PageRenderTime 169ms CodeModel.GetById 14ms app.highlight 141ms RepoModel.GetById 1ms app.codeStats 1ms

/xbmc/visualizations/Vortex/angelscript/angelscript/source/as_context.cpp

http://github.com/xbmc/xbmc
C++ | 3828 lines | 2717 code | 637 blank | 474 comment | 514 complexity | a92b774b4f5f67260a2119c3919efb9d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2   AngelCode Scripting Library
   3   Copyright (c) 2003-2009 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()
  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
  55BEGIN_AS_NAMESPACE
  56
  57// We need at least 2 DWORDs reserved for exception handling
  58// We need at least 1 DWORD reserved for calling system functions
  59const int RESERVE_STACK = 2*AS_PTR_SIZE;
  60
  61// For each script function call we push 5 DWORDs on the call stack
  62const int CALLSTACK_FRAME_SIZE = 5;
  63
  64
  65#ifdef AS_DEBUG
  66// Instruction statistics
  67int instrCount[256];
  68
  69int instrCount2[256][256];
  70int lastBC;
  71
  72class asCDebugStats
  73{
  74public:
  75	asCDebugStats()
  76	{
  77		memset(instrCount, 0, sizeof(instrCount));
  78	}
  79
  80	~asCDebugStats()
  81	{
  82/*
  83		// This code writes out some statistics for the VM. 
  84		// It's useful for determining what needs to be optimized.
  85
  86		_mkdir("AS_DEBUG");
  87		FILE *f = fopen("AS_DEBUG/total.txt", "at");
  88		if( f )
  89		{
  90			// Output instruction statistics
  91			fprintf(f, "\nTotal count\n");
  92			int n;
  93			for( n = 0; n < BC_MAXBYTECODE; n++ )
  94			{
  95				if( bcName[n].name && instrCount[n] > 0 )
  96					fprintf(f, "%-10.10s : %.0f\n", bcName[n].name, instrCount[n]);
  97			}
  98
  99			fprintf(f, "\nNever executed\n");
 100			for( n = 0; n < BC_MAXBYTECODE; n++ )
 101			{
 102				if( bcName[n].name && instrCount[n] == 0 )
 103					fprintf(f, "%-10.10s\n", bcName[n].name);
 104			}
 105
 106			fclose(f);
 107		}
 108*/
 109	}
 110
 111	double instrCount[256];
 112} stats;
 113#endif
 114
 115AS_API asIScriptContext *asGetActiveContext()
 116{
 117	asASSERT(threadManager);
 118	asCThreadLocalData *tld = threadManager->GetLocalData();
 119	if( tld->activeContexts.GetLength() == 0 )
 120		return 0;
 121	return tld->activeContexts[tld->activeContexts.GetLength()-1];
 122}
 123
 124void asPushActiveContext(asIScriptContext *ctx)
 125{
 126	asASSERT(threadManager);
 127	asCThreadLocalData *tld = threadManager->GetLocalData();
 128	tld->activeContexts.PushLast(ctx);
 129}
 130
 131void asPopActiveContext(asIScriptContext *ctx)
 132{
 133	asASSERT(threadManager);
 134	asCThreadLocalData *tld = threadManager->GetLocalData();
 135
 136	asASSERT(tld->activeContexts.GetLength() > 0);
 137	asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == ctx);
 138	UNUSED_VAR(ctx);
 139
 140	tld->activeContexts.PopLast();
 141}
 142
 143asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
 144{
 145#ifdef AS_DEBUG
 146	memset(instrCount, 0, sizeof(instrCount));
 147
 148	memset(instrCount2, 0, sizeof(instrCount2));
 149
 150	lastBC = 255;
 151#endif
 152
 153	holdEngineRef = holdRef;
 154	if( holdRef )
 155		engine->AddRef();
 156	this->engine = engine;
 157
 158	status = asEXECUTION_UNINITIALIZED;
 159	stackBlockSize = 0;
 160	refCount.set(1);
 161	inExceptionHandler = false;
 162	isStackMemoryNotAllocated = false;
 163
 164#ifdef AS_DEPRECATED
 165// Deprecated since 2009-12-08, 2.18.0
 166	stringFunction = 0;
 167#endif
 168	currentFunction = 0;
 169	regs.objectRegister = 0;
 170	initialFunction = 0;
 171
 172	lineCallback = false;
 173	exceptionCallback = false;
 174
 175	regs.doProcessSuspend = false;
 176	doSuspend = false;
 177
 178	userData = 0;
 179}
 180
 181asCContext::~asCContext()
 182{
 183	DetachEngine();
 184}
 185
 186int asCContext::AddRef()
 187{
 188	return refCount.atomicInc();
 189}
 190
 191int asCContext::Release()
 192{
 193	int r = refCount.atomicDec();
 194
 195	if( r == 0 )
 196	{
 197		asDELETE(this,asCContext);
 198		return 0;
 199	}
 200
 201	return r;
 202}
 203
 204void asCContext::DetachEngine()
 205{
 206	if( engine == 0 ) return;
 207
 208	// Abort any execution
 209	Abort();
 210
 211	// Free all resources
 212	Unprepare();
 213
 214	// Clear engine pointer
 215	if( holdEngineRef )
 216		engine->Release();
 217	engine = 0;
 218}
 219
 220asIScriptEngine *asCContext::GetEngine()
 221{
 222	return engine;
 223}
 224
 225void *asCContext::SetUserData(void *data)
 226{
 227	void *oldData = userData;
 228	userData = data;
 229	return oldData;
 230}
 231
 232void *asCContext::GetUserData()
 233{
 234	return userData;
 235}
 236
 237int asCContext::Prepare(int funcID)
 238{
 239	if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
 240		return asCONTEXT_ACTIVE;
 241
 242	// Clean the stack if not done before
 243	if( status != asEXECUTION_FINISHED && status != asEXECUTION_UNINITIALIZED )
 244		CleanStack();
 245
 246	// Release the returned object (if any)
 247	CleanReturnObject();
 248
 249	if( funcID == -1 )
 250	{
 251		// Use the previously prepared function
 252		if( initialFunction == 0 )
 253			return asNO_FUNCTION;
 254
 255		currentFunction = initialFunction;
 256	}
 257	else if( initialFunction && initialFunction->id == funcID )
 258	{
 259		currentFunction = initialFunction;
 260	}
 261	else
 262	{
 263		// Check engine pointer
 264		asASSERT( engine );
 265
 266		if( initialFunction )
 267			initialFunction->Release();
 268
 269		initialFunction = engine->GetScriptFunction(funcID);
 270		if( initialFunction == 0 )
 271			return asNO_FUNCTION;
 272
 273		initialFunction->AddRef();
 274		currentFunction = initialFunction;
 275		regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
 276
 277		// Determine the minimum stack size needed
 278		// TODO: optimize: GetSpaceNeededForArguments() should be precomputed
 279		int stackSize = currentFunction->GetSpaceNeededForArguments() + currentFunction->stackNeeded + RESERVE_STACK;
 280
 281		stackSize = stackSize > engine->initialContextStackSize ? stackSize : engine->initialContextStackSize;
 282
 283		if( stackSize > stackBlockSize )
 284		{
 285			for( asUINT n = 0; n < stackBlocks.GetLength(); n++ )
 286				if( stackBlocks[n] )
 287				{
 288					asDELETEARRAY(stackBlocks[n]);
 289				}
 290			stackBlocks.SetLength(0);
 291
 292			stackBlockSize = stackSize;
 293
 294			asDWORD *stack = asNEWARRAY(asDWORD,stackBlockSize);
 295			stackBlocks.PushLast(stack);
 296		}
 297
 298		// Reserve space for the arguments and return value
 299		returnValueSize = currentFunction->GetSpaceNeededForReturnValue();
 300
 301		// TODO: optimize: GetSpaceNeededForArguments() should be precomputed
 302		argumentsSize = currentFunction->GetSpaceNeededForArguments() + (currentFunction->objectType ? AS_PTR_SIZE : 0);
 303	}
 304
 305	// Reset state
 306	// Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized
 307	if( status != asEXECUTION_FINISHED )
 308	{
 309		exceptionLine           = -1;
 310		exceptionFunction       = 0;
 311		isCallingSystemFunction = false;
 312		doAbort                 = false;
 313		doSuspend               = false;
 314		regs.doProcessSuspend   = lineCallback;
 315		externalSuspendRequest  = false;
 316		stackIndex              = 0;
 317	}
 318	status = asEXECUTION_PREPARED;
 319
 320	// Reserve space for the arguments and return value
 321	regs.stackFramePointer = stackBlocks[0] + stackBlockSize - argumentsSize;
 322	regs.stackPointer      = regs.stackFramePointer;
 323
 324	// Set arguments to 0
 325	memset(regs.stackPointer, 0, 4*argumentsSize);
 326
 327	if( currentFunction->funcType == asFUNC_SCRIPT )
 328	{
 329		regs.programPointer = currentFunction->byteCode.AddressOf();
 330
 331		// Set all object variables to 0
 332		for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
 333		{
 334			int pos = currentFunction->objVariablePos[n];
 335			*(size_t*)&regs.stackFramePointer[-pos] = 0;
 336		}
 337	}
 338	else
 339		regs.programPointer = 0;
 340
 341	return asSUCCESS;
 342}
 343
 344// Free all resources
 345int asCContext::Unprepare()
 346{
 347	if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
 348		return asCONTEXT_ACTIVE;
 349
 350	// Only clean the stack if the context was prepared but not executed
 351	if( status != asEXECUTION_UNINITIALIZED )
 352		CleanStack();
 353
 354	// Release the returned object (if any)
 355	CleanReturnObject();
 356
 357	// Release the initial function
 358	if( initialFunction )
 359		initialFunction->Release();
 360
 361	// Clear function pointers
 362	initialFunction = 0;
 363	currentFunction = 0;
 364	exceptionFunction = 0;
 365	regs.programPointer = 0;
 366
 367	// Reset status
 368	status = asEXECUTION_UNINITIALIZED;
 369
 370	// Deallocate the stack blocks
 371	for( asUINT n = 0; n < stackBlocks.GetLength(); n++ )
 372	{
 373		if( stackBlocks[n] )
 374		{
 375			asDELETEARRAY(stackBlocks[n]);
 376		}
 377	}
 378	stackBlocks.SetLength(0);
 379	stackBlockSize = 0;
 380	regs.stackFramePointer = 0;
 381	regs.stackPointer = 0;
 382	stackIndex = 0;
 383
 384#ifdef AS_DEPRECATED
 385// Deprecated since 2009-12-08, 2.18.0
 386	// Deallocate string function
 387	if( stringFunction )
 388	{
 389		stringFunction->Release();
 390		stringFunction = 0;
 391	}
 392#endif
 393	
 394	return 0;
 395}
 396
 397#ifdef AS_DEPRECATED
 398// Deprecated since 2009-12-08, 2.18.0
 399int asCContext::SetExecuteStringFunction(asCScriptFunction *func)
 400{
 401	if( stringFunction )
 402		stringFunction->Release();
 403
 404	// The new function already has the refCount set to 1
 405	stringFunction = func;
 406
 407	return 0;
 408}
 409#endif
 410
 411asBYTE asCContext::GetReturnByte()
 412{
 413	if( status != asEXECUTION_FINISHED ) return 0;
 414
 415	asCDataType *dt = &initialFunction->returnType;
 416
 417	if( dt->IsObject() || dt->IsReference() ) return 0;
 418
 419	return *(asBYTE*)&regs.valueRegister;
 420}
 421
 422asWORD asCContext::GetReturnWord()
 423{
 424	if( status != asEXECUTION_FINISHED ) return 0;
 425
 426	asCDataType *dt = &initialFunction->returnType;
 427
 428	if( dt->IsObject() || dt->IsReference() ) return 0;
 429
 430	return *(asWORD*)&regs.valueRegister;
 431}
 432
 433asDWORD asCContext::GetReturnDWord()
 434{
 435	if( status != asEXECUTION_FINISHED ) return 0;
 436
 437	asCDataType *dt = &initialFunction->returnType;
 438
 439	if( dt->IsObject() || dt->IsReference() ) return 0;
 440
 441	return *(asDWORD*)&regs.valueRegister;
 442}
 443
 444asQWORD asCContext::GetReturnQWord()
 445{
 446	if( status != asEXECUTION_FINISHED ) return 0;
 447
 448	asCDataType *dt = &initialFunction->returnType;
 449
 450	if( dt->IsObject() || dt->IsReference() ) return 0;
 451
 452	return regs.valueRegister;
 453}
 454
 455float asCContext::GetReturnFloat()
 456{
 457	if( status != asEXECUTION_FINISHED ) return 0;
 458
 459	asCDataType *dt = &initialFunction->returnType;
 460
 461	if( dt->IsObject() || dt->IsReference() ) return 0;
 462
 463	return *(float*)&regs.valueRegister;
 464}
 465
 466double asCContext::GetReturnDouble()
 467{
 468	if( status != asEXECUTION_FINISHED ) return 0;
 469
 470	asCDataType *dt = &initialFunction->returnType;
 471
 472	if( dt->IsObject() || dt->IsReference() ) return 0;
 473
 474	return *(double*)&regs.valueRegister;
 475}
 476
 477void *asCContext::GetReturnAddress()
 478{
 479	if( status != asEXECUTION_FINISHED ) return 0;
 480
 481	asCDataType *dt = &initialFunction->returnType;
 482
 483	if( dt->IsReference() )
 484		return *(void**)&regs.valueRegister;
 485	else if( dt->IsObject() )
 486		return regs.objectRegister;
 487
 488	return 0;
 489}
 490
 491void *asCContext::GetReturnObject()
 492{
 493	if( status != asEXECUTION_FINISHED ) return 0;
 494
 495	asCDataType *dt = &initialFunction->returnType;
 496
 497	if( !dt->IsObject() ) return 0;
 498
 499	if( dt->IsReference() )
 500		return *(void**)(size_t)regs.valueRegister;
 501	else
 502		return regs.objectRegister;
 503}
 504
 505void *asCContext::GetAddressOfReturnValue()
 506{
 507	if( status != asEXECUTION_FINISHED ) return 0;
 508
 509	asCDataType *dt = &initialFunction->returnType;
 510
 511	// An object is stored in the objectRegister
 512	if( !dt->IsReference() && dt->IsObject() )
 513	{
 514		// Need to dereference objects 
 515		if( !dt->IsObjectHandle() )
 516			return *(void**)&regs.objectRegister;
 517		return &regs.objectRegister;
 518	}
 519
 520	// Primitives and references are stored in valueRegister
 521	return &regs.valueRegister;
 522}
 523
 524int asCContext::SetObject(void *obj)
 525{
 526	if( status != asEXECUTION_PREPARED )
 527		return asCONTEXT_NOT_PREPARED;
 528
 529	if( !initialFunction->objectType )
 530	{
 531		status = asEXECUTION_ERROR;
 532		return asERROR;
 533	}
 534
 535	*(size_t*)&regs.stackFramePointer[0] = (size_t)obj;
 536
 537	return 0;
 538}
 539
 540int asCContext::SetArgByte(asUINT arg, asBYTE value)
 541{
 542	if( status != asEXECUTION_PREPARED )
 543		return asCONTEXT_NOT_PREPARED;
 544
 545	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 546	{
 547		status = asEXECUTION_ERROR;
 548		return asINVALID_ARG;
 549	}
 550
 551	// Verify the type of the argument
 552	asCDataType *dt = &initialFunction->parameterTypes[arg];
 553	if( dt->IsObject() || dt->IsReference() )
 554	{
 555		status = asEXECUTION_ERROR;
 556		return asINVALID_TYPE;
 557	}
 558
 559	if( dt->GetSizeInMemoryBytes() != 1 )
 560	{
 561		status = asEXECUTION_ERROR;
 562		return asINVALID_TYPE;
 563	}
 564
 565	// Determine the position of the argument
 566	int offset = 0;
 567	if( initialFunction->objectType )
 568		offset += AS_PTR_SIZE;
 569	for( asUINT n = 0; n < arg; n++ )
 570		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 571
 572	// Set the value
 573	*(asBYTE*)&regs.stackFramePointer[offset] = value;
 574
 575	return 0;
 576}
 577
 578int asCContext::SetArgWord(asUINT arg, asWORD value)
 579{
 580	if( status != asEXECUTION_PREPARED )
 581		return asCONTEXT_NOT_PREPARED;
 582
 583	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 584	{
 585		status = asEXECUTION_ERROR;
 586		return asINVALID_ARG;
 587	}
 588
 589	// Verify the type of the argument
 590	asCDataType *dt = &initialFunction->parameterTypes[arg];
 591	if( dt->IsObject() || dt->IsReference() )
 592	{
 593		status = asEXECUTION_ERROR;
 594		return asINVALID_TYPE;
 595	}
 596
 597	if( dt->GetSizeInMemoryBytes() != 2 )
 598	{
 599		status = asEXECUTION_ERROR;
 600		return asINVALID_TYPE;
 601	}
 602
 603	// Determine the position of the argument
 604	int offset = 0;
 605	if( initialFunction->objectType )
 606		offset += AS_PTR_SIZE;
 607	for( asUINT n = 0; n < arg; n++ )
 608		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 609
 610	// Set the value
 611	*(asWORD*)&regs.stackFramePointer[offset] = value;
 612
 613	return 0;
 614}
 615
 616int asCContext::SetArgDWord(asUINT arg, asDWORD value)
 617{
 618	if( status != asEXECUTION_PREPARED )
 619		return asCONTEXT_NOT_PREPARED;
 620
 621	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 622	{
 623		status = asEXECUTION_ERROR;
 624		return asINVALID_ARG;
 625	}
 626
 627	// Verify the type of the argument
 628	asCDataType *dt = &initialFunction->parameterTypes[arg];
 629	if( dt->IsObject() || dt->IsReference() )
 630	{
 631		status = asEXECUTION_ERROR;
 632		return asINVALID_TYPE;
 633	}
 634
 635	if( dt->GetSizeInMemoryBytes() != 4 )
 636	{
 637		status = asEXECUTION_ERROR;
 638		return asINVALID_TYPE;
 639	}
 640
 641	// Determine the position of the argument
 642	int offset = 0;
 643	if( initialFunction->objectType )
 644		offset += AS_PTR_SIZE;
 645	for( asUINT n = 0; n < arg; n++ )
 646		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 647
 648	// Set the value
 649	*(asDWORD*)&regs.stackFramePointer[offset] = value;
 650
 651	return 0;
 652}
 653
 654int asCContext::SetArgQWord(asUINT arg, asQWORD value)
 655{
 656	if( status != asEXECUTION_PREPARED )
 657		return asCONTEXT_NOT_PREPARED;
 658
 659	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 660	{
 661		status = asEXECUTION_ERROR;
 662		return asINVALID_ARG;
 663	}
 664
 665	// Verify the type of the argument
 666	asCDataType *dt = &initialFunction->parameterTypes[arg];
 667	if( dt->IsObject() || dt->IsReference() )
 668	{
 669		status = asEXECUTION_ERROR;
 670		return asINVALID_TYPE;
 671	}
 672
 673	if( dt->GetSizeOnStackDWords() != 2 )
 674	{
 675		status = asEXECUTION_ERROR;
 676		return asINVALID_TYPE;
 677	}
 678
 679	// Determine the position of the argument
 680	int offset = 0;
 681	if( initialFunction->objectType )
 682		offset += AS_PTR_SIZE;
 683	for( asUINT n = 0; n < arg; n++ )
 684		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 685
 686	// Set the value
 687	*(asQWORD*)(&regs.stackFramePointer[offset]) = value;
 688
 689	return 0;
 690}
 691
 692int asCContext::SetArgFloat(asUINT arg, float value)
 693{
 694	if( status != asEXECUTION_PREPARED )
 695		return asCONTEXT_NOT_PREPARED;
 696
 697	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 698	{
 699		status = asEXECUTION_ERROR;
 700		return asINVALID_ARG;
 701	}
 702
 703	// Verify the type of the argument
 704	asCDataType *dt = &initialFunction->parameterTypes[arg];
 705	if( dt->IsObject() || dt->IsReference() )
 706	{
 707		status = asEXECUTION_ERROR;
 708		return asINVALID_TYPE;
 709	}
 710
 711	if( dt->GetSizeOnStackDWords() != 1 )
 712	{
 713		status = asEXECUTION_ERROR;
 714		return asINVALID_TYPE;
 715	}
 716
 717	// Determine the position of the argument
 718	int offset = 0;
 719	if( initialFunction->objectType )
 720		offset += AS_PTR_SIZE;
 721	for( asUINT n = 0; n < arg; n++ )
 722		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 723
 724	// Set the value
 725	*(float*)(&regs.stackFramePointer[offset]) = value;
 726
 727	return 0;
 728}
 729
 730int asCContext::SetArgDouble(asUINT arg, double value)
 731{
 732	if( status != asEXECUTION_PREPARED )
 733		return asCONTEXT_NOT_PREPARED;
 734
 735	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 736	{
 737		status = asEXECUTION_ERROR;
 738		return asINVALID_ARG;
 739	}
 740
 741	// Verify the type of the argument
 742	asCDataType *dt = &initialFunction->parameterTypes[arg];
 743	if( dt->IsObject() || dt->IsReference() )
 744	{
 745		status = asEXECUTION_ERROR;
 746		return asINVALID_TYPE;
 747	}
 748
 749	if( dt->GetSizeOnStackDWords() != 2 )
 750	{
 751		status = asEXECUTION_ERROR;
 752		return asINVALID_TYPE;
 753	}
 754
 755	// Determine the position of the argument
 756	int offset = 0;
 757	if( initialFunction->objectType )
 758		offset += AS_PTR_SIZE;
 759	for( asUINT n = 0; n < arg; n++ )
 760		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 761
 762	// Set the value
 763	*(double*)(&regs.stackFramePointer[offset]) = value;
 764
 765	return 0;
 766}
 767
 768int asCContext::SetArgAddress(asUINT arg, void *value)
 769{
 770	if( status != asEXECUTION_PREPARED )
 771		return asCONTEXT_NOT_PREPARED;
 772
 773	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 774	{
 775		status = asEXECUTION_ERROR;
 776		return asINVALID_ARG;
 777	}
 778
 779	// Verify the type of the argument
 780	asCDataType *dt = &initialFunction->parameterTypes[arg];
 781	if( !dt->IsReference() && !dt->IsObjectHandle() )
 782	{
 783		status = asEXECUTION_ERROR;
 784		return asINVALID_TYPE;
 785	}
 786
 787	// Determine the position of the argument
 788	int offset = 0;
 789	if( initialFunction->objectType )
 790		offset += AS_PTR_SIZE;
 791
 792	for( asUINT n = 0; n < arg; n++ )
 793		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 794
 795	// Set the value
 796	*(size_t*)(&regs.stackFramePointer[offset]) = (size_t)value;
 797
 798	return 0;
 799}
 800
 801int asCContext::SetArgObject(asUINT arg, void *obj)
 802{
 803	if( status != asEXECUTION_PREPARED )
 804		return asCONTEXT_NOT_PREPARED;
 805
 806	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 807	{
 808		status = asEXECUTION_ERROR;
 809		return asINVALID_ARG;
 810	}
 811
 812	// Verify the type of the argument
 813	asCDataType *dt = &initialFunction->parameterTypes[arg];
 814	if( !dt->IsObject() )
 815	{
 816		status = asEXECUTION_ERROR;
 817		return asINVALID_TYPE;
 818	}
 819
 820	// If the object should be sent by value we must make a copy of it
 821	if( !dt->IsReference() )
 822	{
 823		if( dt->IsObjectHandle() )
 824		{
 825			// Increase the reference counter
 826			asSTypeBehaviour *beh = &dt->GetObjectType()->beh;
 827			if( obj && beh->addref )
 828				engine->CallObjectMethod(obj, beh->addref);
 829		}
 830		else 
 831		{
 832			obj = engine->CreateScriptObjectCopy(obj, engine->GetTypeIdFromDataType(*dt));
 833		}
 834	}
 835
 836	// Determine the position of the argument
 837	int offset = 0;
 838	if( initialFunction->objectType )
 839		offset += AS_PTR_SIZE;
 840	for( asUINT n = 0; n < arg; n++ )
 841		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 842
 843	// Set the value
 844	*(size_t*)(&regs.stackFramePointer[offset]) = (size_t)obj;
 845
 846	return 0;
 847}
 848
 849
 850// TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
 851
 852// interface
 853void *asCContext::GetAddressOfArg(asUINT arg)
 854{
 855	if( status != asEXECUTION_PREPARED )
 856		return 0;
 857
 858	if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
 859		return 0;
 860
 861	// Determine the position of the argument
 862	int offset = 0;
 863	if( initialFunction->objectType )
 864		offset += AS_PTR_SIZE;
 865	for( asUINT n = 0; n < arg; n++ )
 866		offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
 867
 868	// We should return the address of the location where the argument value will be placed
 869
 870	// All registered types are always sent by reference, even if  
 871	// the function is declared to receive the argument by value.	
 872	return &regs.stackFramePointer[offset];
 873}
 874
 875
 876int asCContext::Abort()
 877{
 878	// TODO: multithread: Make thread safe
 879
 880	if( engine == 0 ) return asERROR;
 881
 882	if( status == asEXECUTION_SUSPENDED )
 883		status = asEXECUTION_ABORTED;
 884
 885	doSuspend = true;
 886	regs.doProcessSuspend = true;
 887	externalSuspendRequest = true;
 888	doAbort = true;
 889
 890	return 0;
 891}
 892
 893// interface
 894int asCContext::Suspend()
 895{
 896	// This function just sets some internal flags and is safe 
 897	// to call from a secondary thread, even if the library has
 898	// been built without multi-thread support.
 899
 900	if( engine == 0 ) return asERROR;
 901
 902	doSuspend = true;
 903	externalSuspendRequest = true;
 904	regs.doProcessSuspend = true;
 905
 906	return 0;
 907}
 908
 909// interface
 910int asCContext::Execute()
 911{
 912	asASSERT( engine != 0 );
 913
 914	if( status != asEXECUTION_SUSPENDED && status != asEXECUTION_PREPARED )
 915		return asERROR;
 916
 917	status = asEXECUTION_ACTIVE;
 918
 919	asPushActiveContext((asIScriptContext *)this);
 920
 921	if( regs.programPointer == 0 )
 922	{
 923		if( currentFunction->funcType == asFUNC_VIRTUAL ||
 924			currentFunction->funcType == asFUNC_INTERFACE )
 925		{
 926			// The currentFunction is a virtual method
 927
 928			// Determine the true function from the object
 929			asCScriptObject *obj = *(asCScriptObject**)(size_t*)regs.stackFramePointer;
 930			if( obj == 0 )
 931			{
 932				SetInternalException(TXT_NULL_POINTER_ACCESS);
 933			}
 934			else
 935			{
 936				asCObjectType *objType = obj->objType;
 937				asCScriptFunction *realFunc = 0;
 938
 939				if( currentFunction->funcType == asFUNC_VIRTUAL )
 940				{
 941					if( objType->virtualFunctionTable.GetLength() > (asUINT)currentFunction->vfTableIdx )
 942					{
 943						realFunc = objType->virtualFunctionTable[currentFunction->vfTableIdx];
 944					}
 945				}
 946				else
 947				{
 948					// Search the object type for a function that matches the interface function
 949					for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
 950					{
 951						asCScriptFunction *f2 = engine->scriptFunctions[objType->methods[n]];
 952						if( f2->signatureId == currentFunction->signatureId )
 953						{
 954							if( f2->funcType == asFUNC_VIRTUAL )
 955								realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
 956							else
 957								realFunc = f2;
 958							break;
 959						}
 960					}
 961				}
 962
 963				if( realFunc )
 964				{
 965					if( realFunc->signatureId != currentFunction->signatureId )
 966					{
 967						SetInternalException(TXT_NULL_POINTER_ACCESS);
 968					}
 969					else
 970					{
 971						currentFunction = realFunc;
 972						regs.programPointer = currentFunction->byteCode.AddressOf();
 973						regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
 974
 975						// Set the local objects to 0
 976						for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
 977						{
 978							int pos = currentFunction->objVariablePos[n];
 979							*(size_t*)&regs.stackFramePointer[-pos] = 0;
 980						}
 981					}
 982				}
 983			}
 984		}
 985		else if( currentFunction->funcType == asFUNC_SYSTEM )
 986		{
 987			// The current function is an application registered function
 988
 989			// Call the function directly
 990			CallSystemFunction(currentFunction->id, this, 0);
 991			
 992			// Was the call successful?
 993			if( status == asEXECUTION_ACTIVE )
 994			{
 995				status = asEXECUTION_FINISHED;
 996			}
 997		}
 998		else
 999		{
1000			// This shouldn't happen
1001			asASSERT(false);
1002		}
1003	}
1004
1005	while(  status == asEXECUTION_ACTIVE )
1006		ExecuteNext();
1007
1008	doSuspend = false;
1009	regs.doProcessSuspend = lineCallback;
1010
1011	asPopActiveContext((asIScriptContext *)this);
1012
1013
1014#ifdef AS_DEBUG
1015/*
1016	// Output instruction statistics
1017	// This is useful for determining what needs to be optimized.
1018
1019	_mkdir("AS_DEBUG");
1020	FILE *f = fopen("AS_DEBUG/stats.txt", "at");
1021	fprintf(f, "\n");
1022	asQWORD total = 0;
1023	int n;
1024	for( n = 0; n < 256; n++ )
1025	{
1026		if( bcName[n].name && instrCount[n] )
1027			fprintf(f, "%-10.10s : %d\n", bcName[n].name, instrCount[n]);
1028
1029		total += instrCount[n];
1030	}
1031
1032	fprintf(f, "\ntotal      : %I64d\n", total);
1033
1034	fprintf(f, "\n");
1035	for( n = 0; n < 256; n++ )
1036	{
1037		if( bcName[n].name )
1038		{
1039			for( int m = 0; m < 256; m++ )
1040			{
1041				if( instrCount2[n][m] )
1042					fprintf(f, "%-10.10s, %-10.10s : %d\n", bcName[n].name, bcName[m].name, instrCount2[n][m]);
1043			}
1044		}
1045	}
1046	fclose(f);
1047*/
1048#endif
1049
1050	if( status == asEXECUTION_FINISHED )
1051	{
1052		regs.objectType = initialFunction->returnType.GetObjectType();
1053		return asEXECUTION_FINISHED;
1054	}
1055
1056	if( status == asEXECUTION_SUSPENDED )
1057		return asEXECUTION_SUSPENDED;
1058
1059	if( doAbort )
1060	{
1061		doAbort = false;
1062
1063		status = asEXECUTION_ABORTED;
1064		return asEXECUTION_ABORTED;
1065	}
1066
1067	if( status == asEXECUTION_EXCEPTION )
1068		return asEXECUTION_EXCEPTION;
1069
1070	return asERROR;
1071}
1072
1073void asCContext::PushCallState()
1074{
1075	callStack.SetLength(callStack.GetLength() + CALLSTACK_FRAME_SIZE);
1076
1077    // Separating the loads and stores limits data cache trash, and with a smart compiler
1078    // could turn into SIMD style loading/storing if available.
1079    // The compiler can't do this itself due to potential pointer aliasing between the pointers,
1080    // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example
1081    // for all the compiler knows. So introducing the local variable s, which is never referred to by
1082    // its address we avoid this issue.
1083
1084	size_t s[5];
1085	s[0] = (size_t)regs.stackFramePointer;
1086	s[1] = (size_t)currentFunction;
1087	s[2] = (size_t)regs.programPointer;
1088	s[3] = (size_t)regs.stackPointer;
1089	s[4] = stackIndex;
1090
1091	size_t *tmp = callStack.AddressOf() + callStack.GetLength() - CALLSTACK_FRAME_SIZE;
1092	tmp[0] = s[0];
1093	tmp[1] = s[1];
1094	tmp[2] = s[2];
1095	tmp[3] = s[3];
1096	tmp[4] = s[4];
1097}
1098
1099void asCContext::PopCallState()
1100{
1101	// See comments in PushCallState about pointer aliasing and data cache trashing
1102	size_t *tmp = callStack.AddressOf() + callStack.GetLength() - CALLSTACK_FRAME_SIZE;
1103	size_t s[5];
1104	s[0] = tmp[0];
1105	s[1] = tmp[1];
1106	s[2] = tmp[2];
1107	s[3] = tmp[3];
1108	s[4] = tmp[4];
1109
1110	regs.stackFramePointer = (asDWORD*)s[0];
1111	currentFunction        = (asCScriptFunction*)s[1];
1112	regs.programPointer    = (asDWORD*)s[2];
1113	regs.stackPointer      = (asDWORD*)s[3];
1114	stackIndex             = (int)s[4];
1115
1116	regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
1117
1118	callStack.SetLength(callStack.GetLength() - CALLSTACK_FRAME_SIZE);
1119}
1120
1121int asCContext::GetCallstackSize()
1122{
1123	return (int)callStack.GetLength() / CALLSTACK_FRAME_SIZE;
1124}
1125
1126int asCContext::GetCallstackFunction(int index)
1127{
1128	if( index < 0 || index >= GetCallstackSize() ) return asINVALID_ARG;
1129
1130	size_t *s = callStack.AddressOf() + index*CALLSTACK_FRAME_SIZE;
1131	asCScriptFunction *func = (asCScriptFunction*)s[1];
1132
1133	return func->id;
1134}
1135
1136int asCContext::GetCallstackLineNumber(int index, int *column)
1137{
1138	if( index < 0 || index >= GetCallstackSize() ) return asINVALID_ARG;
1139
1140	size_t *s = callStack.AddressOf() + index*CALLSTACK_FRAME_SIZE;
1141	asCScriptFunction *func = (asCScriptFunction*)s[1];
1142	asDWORD *bytePos = (asDWORD*)s[2];
1143
1144	asDWORD line = func->GetLineNumber(int(bytePos - func->byteCode.AddressOf()));
1145	if( column ) *column = (line >> 20);
1146
1147	return (line & 0xFFFFF);
1148}
1149
1150void asCContext::CallScriptFunction(asCScriptFunction *func)
1151{
1152	// Push the framepointer, function id and programCounter on the stack
1153	PushCallState();
1154
1155	currentFunction = func;
1156
1157	regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
1158	regs.programPointer = currentFunction->byteCode.AddressOf();
1159
1160	// Verify if there is enough room in the stack block. Allocate new block if not
1161	if( regs.stackPointer - (func->stackNeeded + RESERVE_STACK) < stackBlocks[stackIndex] )
1162	{
1163		asDWORD *oldStackPointer = regs.stackPointer;
1164
1165		// The size of each stack block is determined by the following formula:
1166		// size = stackBlockSize << index
1167
1168		while( regs.stackPointer - (func->stackNeeded + RESERVE_STACK) < stackBlocks[stackIndex] )
1169		{
1170			// Make sure we don't allocate more space than allowed
1171			if( engine->ep.maximumContextStackSize )
1172			{
1173				// This test will only stop growth once it has already crossed the limit
1174				if( stackBlockSize * ((1 << (stackIndex+1)) - 1) > engine->ep.maximumContextStackSize )
1175				{
1176					isStackMemoryNotAllocated = true;
1177
1178					// Set the stackFramePointer, even though the stackPointer wasn't updated
1179					regs.stackFramePointer = regs.stackPointer;
1180
1181					// TODO: Make sure the exception handler doesn't try to free objects that have not been initialized
1182					SetInternalException(TXT_STACK_OVERFLOW);
1183					return;
1184				}
1185			}
1186
1187			stackIndex++;
1188			if( (int)stackBlocks.GetLength() == stackIndex )
1189			{
1190				asDWORD *stack = asNEWARRAY(asDWORD,(stackBlockSize << stackIndex));
1191				stackBlocks.PushLast(stack);
1192			}
1193
1194			regs.stackPointer = stackBlocks[stackIndex] + (stackBlockSize<<stackIndex) - func->GetSpaceNeededForArguments();
1195		} 
1196
1197		// Copy the function arguments to the new stack space
1198		memcpy(regs.stackPointer, oldStackPointer, sizeof(asDWORD)*func->GetSpaceNeededForArguments());
1199	}
1200
1201	// Update framepointer and programCounter
1202	regs.stackFramePointer = regs.stackPointer;
1203
1204	// Set all object variables to 0
1205	for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
1206	{
1207		int pos = currentFunction->objVariablePos[n];
1208		*(size_t*)&regs.stackFramePointer[-pos] = 0;
1209	}
1210}
1211
1212void asCContext::CallInterfaceMethod(asCScriptFunction *func)
1213{
1214	// Resolve the interface method using the current script type
1215	asCScriptObject *obj = *(asCScriptObject**)(size_t*)regs.stackPointer;
1216	if( obj == 0 )
1217	{
1218		SetInternalException(TXT_NULL_POINTER_ACCESS);
1219		return;
1220	}
1221
1222	asCObjectType *objType = obj->objType;
1223
1224	// TODO: optimize: The object type should have a list of only those methods that 
1225	//                 implement interface methods. This list should be ordered by
1226	//                 the signatureId so that a binary search can be made, instead
1227	//                 of a linear search.
1228	//
1229	//                 When this is done, we must also make sure the signatureId of a 
1230	//                 function never changes, e.g. when if the signature functions are
1231	//                 released.
1232
1233	// Search the object type for a function that matches the interface function
1234	asCScriptFunction *realFunc = 0;
1235	if( func->funcType == asFUNC_INTERFACE )
1236	{
1237		for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
1238		{
1239			asCScriptFunction *f2 = engine->scriptFunctions[objType->methods[n]];
1240			if( f2->signatureId == func->signatureId )
1241			{
1242				if( f2->funcType == asFUNC_VIRTUAL )
1243					realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
1244				else
1245					realFunc = f2;
1246				break;
1247			}
1248		}
1249
1250		if( realFunc == 0 )
1251		{
1252			SetInternalException(TXT_NULL_POINTER_ACCESS);
1253			return;
1254		}
1255	}
1256	else /* if( func->funcType == asFUNC_VIRTUAL ) */
1257	{
1258		realFunc = objType->virtualFunctionTable[func->vfTableIdx];
1259	}
1260
1261	// Then call the true script function
1262	CallScriptFunction(realFunc);
1263}
1264
1265void asCContext::ExecuteNext()
1266{
1267	asDWORD *l_bc = regs.programPointer;
1268	asDWORD *l_sp = regs.stackPointer;
1269	asDWORD *l_fp = regs.stackFramePointer;
1270
1271	for(;;)
1272	{
1273
1274#ifdef AS_DEBUG
1275	++stats.instrCount[*(asBYTE*)l_bc];
1276
1277	++instrCount[*(asBYTE*)l_bc];
1278
1279	++instrCount2[lastBC][*(asBYTE*)l_bc];
1280	lastBC = *(asBYTE*)l_bc;
1281
1282	// Used to verify that the size of the instructions are correct
1283	asDWORD *old = l_bc;
1284#endif
1285
1286
1287	// Remember to keep the cases in order and without
1288	// gaps, because that will make the switch faster.
1289	// It will be faster since only one lookup will be
1290	// made to find the correct jump destination. If not
1291	// in order, the switch will make two lookups.
1292	switch( *(asBYTE*)l_bc )
1293	{
1294//--------------
1295// memory access functions
1296
1297	// Decrease the stack pointer with n dwords (stack grows downward)
1298	case asBC_POP:
1299		l_sp += asBC_WORDARG0(l_bc);
1300		l_bc++;
1301		break;
1302
1303	// Increase the stack pointer with n dwords
1304	case asBC_PUSH:
1305		l_sp -= asBC_WORDARG0(l_bc);
1306		l_bc++;
1307		break;
1308
1309	// Push a dword value on the stack
1310	case asBC_PshC4:
1311		--l_sp;
1312		*l_sp = asBC_DWORDARG(l_bc);
1313		l_bc += 2;
1314		break;
1315
1316	// Push the dword value of a variable on the stack
1317	case asBC_PshV4:
1318		--l_sp;
1319		*l_sp = *(l_fp - asBC_SWORDARG0(l_bc));
1320		l_bc++;
1321		break;
1322
1323	// Push the address of a variable on the stack
1324	case asBC_PSF:
1325		l_sp -= AS_PTR_SIZE;
1326		*(asPTRWORD*)l_sp = (asPTRWORD)size_t(l_fp - asBC_SWORDARG0(l_bc));
1327		l_bc++;
1328		break;
1329
1330	// Swap the top 2 dwords on the stack
1331	case asBC_SWAP4:
1332		{
1333			asDWORD d = (asDWORD)*l_sp;
1334			*l_sp = *(l_sp+1);
1335			*(asDWORD*)(l_sp+1) = d;
1336			l_bc++;
1337		}
1338		break;
1339
1340	// Do a boolean not operation, modifying the value of the variable
1341	case asBC_NOT:
1342#if AS_SIZEOF_BOOL == 1
1343		{
1344			// Set the value to true if it is equal to 0
1345
1346			// We need to use volatile here to tell the compiler it cannot
1347			// change the order of read and write operations on the pointer.
1348
1349			volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
1350			asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1351			ptr[0] = val; // The result is stored in the lower byte
1352			ptr[1] = 0;   // Make sure the rest of the DWORD is 0
1353			ptr[2] = 0;
1354			ptr[3] = 0;
1355		}
1356#else
1357		*(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
1358#endif
1359		l_bc++;
1360		break;
1361
1362	// Push the dword value of a global variable on the stack
1363	case asBC_PshG4:
1364		--l_sp;
1365		// TODO: global: The global var address should be stored in the instruction directly
1366		*l_sp = *(asDWORD*)regs.globalVarPointers[asBC_WORDARG0(l_bc)];
1367		l_bc++;
1368		break;
1369
1370	// Load the address of a global variable in the register, then  
1371	// copy the value of the global variable into a local variable
1372	case asBC_LdGRdR4:
1373		// TODO: global: The global var address should be stored in the instruction directly
1374		*(void**)&regs.valueRegister = regs.globalVarPointers[asBC_WORDARG1(l_bc)];
1375		*(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&regs.valueRegister;
1376		l_bc += 2;
1377		break;
1378
1379//----------------
1380// path control instructions
1381
1382	// Begin execution of a script function
1383	case asBC_CALL:
1384		{
1385			int i = asBC_INTARG(l_bc);
1386			l_bc += 2;
1387
1388			asASSERT( i >= 0 );
1389			asASSERT( (i & FUNC_IMPORTED) == 0 );
1390
1391			// Need to move the values back to the context
1392			regs.programPointer = l_bc;
1393			regs.stackPointer = l_sp;
1394			regs.stackFramePointer = l_fp;
1395
1396			CallScriptFunction(engine->scriptFunctions[i]);
1397
1398			// Extract the values from the context again
1399			l_bc = regs.programPointer;
1400			l_sp = regs.stackPointer;
1401			l_fp = regs.stackFramePointer;
1402
1403			// If status isn't active anymore then we must stop
1404			if( status != asEXECUTION_ACTIVE )
1405				return;
1406		}
1407		break;
1408
1409	// Return to the caller, and remove the arguments from the stack
1410	case asBC_RET:
1411		{
1412			if( callStack.GetLength() == 0 )
1413			{
1414				status = asEXECUTION_FINISHED;
1415				return;
1416			}
1417
1418			asWORD w = asBC_WORDARG0(l_bc);
1419
1420			// Read the old framepointer, functionid, and programCounter from the call stack
1421			PopCallState();
1422
1423			// Extract the values from the context again
1424			l_bc = regs.programPointer;
1425			l_sp = regs.stackPointer;
1426			l_fp = regs.stackFramePointer;
1427
1428			// Pop arguments from stack
1429			l_sp += w;
1430		}
1431		break;
1432
1433	// Jump to a relative position
1434	case asBC_JMP:
1435		l_bc += 2 + asBC_INTARG(l_bc);
1436		break;
1437
1438//----------------
1439// Conditional jumps
1440
1441	// Jump to a relative position if the value in the register is 0
1442	case asBC_JZ:
1443		if( *(int*)&regs.valueRegister == 0 )
1444			l_bc += asBC_INTARG(l_bc) + 2;
1445		else
1446			l_bc += 2;
1447		break;
1448
1449	// Jump to a relative position if the value in the register is not 0
1450	case asBC_JNZ:
1451		if( *(int*)&regs.valueRegister != 0 )
1452			l_bc += asBC_INTARG(l_bc) + 2;
1453		else
1454			l_bc += 2;
1455		break;
1456
1457	// Jump to a relative position if the value in the register is negative
1458	case asBC_JS:
1459		if( *(int*)&regs.valueRegister < 0 )
1460			l_bc += asBC_INTARG(l_bc) + 2;
1461		else
1462			l_bc += 2;
1463		break;
1464
1465	// Jump to a relative position if the value in the register it not negative
1466	case asBC_JNS:
1467		if( *(int*)&regs.valueRegister >= 0 )
1468			l_bc += asBC_INTARG(l_bc) + 2;
1469		else
1470			l_bc += 2;
1471		break;
1472
1473	// Jump to a relative position if the value in the register is greater than 0
1474	case asBC_JP:
1475		if( *(int*)&regs.valueRegister > 0 )
1476			l_bc += asBC_INTARG(l_bc) + 2;
1477		else
1478			l_bc += 2;
1479		break;
1480
1481	// Jump to a relative position if the value in the register is not greater than 0
1482	case asBC_JNP:
1483		if( *(int*)&regs.valueRegister <= 0 )
1484			l_bc += asBC_INTARG(l_bc) + 2;
1485		else
1486			l_bc += 2;
1487		break;
1488//--------------------
1489// test instructions
1490
1491	// If the value in the register is 0, then set the register to 1, else to 0
1492	case asBC_TZ:
1493#if AS_SIZEOF_BOOL == 1
1494		{
1495			// Set the value to true if it is equal to 0
1496
1497			// We need to use volatile here to tell the compiler it cannot
1498			// change the order of read and write operations on valueRegister.
1499
1500			volatile int    *regPtr  = (int*)&regs.valueRegister;
1501			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1502			asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1503			regBptr[0] = val; // The result is stored in the lower byte
1504			regBptr[1] = 0;   // Make sure the rest of the register is 0
1505			regBptr[2] = 0;
1506			regBptr[3] = 0;
1507			regBptr[4] = 0;
1508			regBptr[5] = 0;
1509			regBptr[6] = 0;
1510			regBptr[7] = 0;
1511		}
1512#else
1513		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
1514#endif
1515		l_bc++;
1516		break;
1517
1518	// If the value in the register is not 0, then set the register to 1, else to 0
1519	case asBC_TNZ:
1520#if AS_SIZEOF_BOOL == 1
1521		{
1522			// Set the value to true if it is not equal to 0
1523
1524			// We need to use volatile here to tell the compiler it cannot
1525			// change the order of read and write operations on valueRegister.
1526
1527			volatile int    *regPtr  = (int*)&regs.valueRegister;
1528			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1529			asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE;
1530			regBptr[0] = val; // The result is stored in the lower byte
1531			regBptr[1] = 0;   // Make sure the rest of the register is 0
1532			regBptr[2] = 0;
1533			regBptr[3] = 0;
1534			regBptr[4] = 0;
1535			regBptr[5] = 0;
1536			regBptr[6] = 0;
1537			regBptr[7] = 0;
1538		}
1539#else
1540		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
1541#endif
1542		l_bc++;
1543		break;
1544
1545	// If the value in the register is negative, then set the register to 1, else to 0
1546	case asBC_TS:
1547#if AS_SIZEOF_BOOL == 1
1548		{
1549			// Set the value to true if it is less than 0
1550
1551			// We need to use volatile here to tell the compiler it cannot
1552			// change the order of read and write operations on valueRegister.
1553
1554			volatile int    *regPtr  = (int*)&regs.valueRegister;
1555			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1556			asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1557			regBptr[0] = val; // The result is stored in the lower byte
1558			regBptr[1] = 0;   // Make sure the rest of the register is 0
1559			regBptr[2] = 0;
1560			regBptr[3] = 0;
1561			regBptr[4] = 0;
1562			regBptr[5] = 0;
1563			regBptr[6] = 0;
1564			regBptr[7] = 0;
1565		}
1566#else
1567		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
1568#endif
1569		l_bc++;
1570		break;
1571
1572	// If the value in the register is not negative, then set the register to 1, else to 0
1573	case asBC_TNS:
1574#if AS_SIZEOF_BOOL == 1
1575		{
1576			// Set the value to true if it is not less than 0
1577
1578			// We need to use volatile here to tell the compiler it cannot
1579			// change the order of read and write operations on valueRegister.
1580
1581			volatile int    *regPtr  = (int*)&regs.valueRegister;
1582			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1583			asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1584			regBptr[0] = val; // The result is stored in the lower byte
1585			regBptr[1] = 0;   // Make sure the rest of the register is 0
1586			regBptr[2] = 0;
1587			regBptr[3] = 0;
1588			regBptr[4] = 0;
1589			regBptr[5] = 0;
1590			regBptr[6] = 0;
1591			regBptr[7] = 0;
1592		}
1593#else
1594		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
1595#endif
1596		l_bc++;
1597		break;
1598
1599	// If the value in the register is greater than 0, then set the register to 1, else to 0
1600	case asBC_TP:
1601#if AS_SIZEOF_BOOL == 1
1602		{
1603			// Set the value to true if it is greater than 0
1604
1605			// We need to use volatile here to tell the compiler it cannot
1606			// change the order of read and write operations on valueRegister.
1607
1608			volatile int    *regPtr  = (int*)&regs.valueRegister;
1609			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1610			asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1611			regBptr[0] = val; // The result is stored in the lower byte
1612			regBptr[1] = 0;   // Make sure the rest of the register is 0
1613			regBptr[2] = 0;
1614			regBptr[3] = 0;
1615			regBptr[4] = 0;
1616			regBptr[5] = 0;
1617			regBptr[6] = 0;
1618			regBptr[7] = 0;
1619		}
1620#else
1621		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
1622#endif
1623		l_bc++;
1624		break;
1625
1626	// If the value in the register is not greater than 0, then set the register to 1, else to 0
1627	case asBC_TNP:
1628#if AS_SIZEOF_BOOL == 1
1629		{
1630			// Set the value to true if it is not greater than 0
1631
1632			// We need to use volatile here to tell the compiler it cannot
1633			// change the order of read and write operations on valueRegister.
1634
1635			volatile int    *regPtr  = (int*)&regs.valueRegister;
1636			volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
1637			asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1638			regBptr[0] = val; // The result is stored in the lower byte
1639			regBptr[1] = 0;   // Make sure the rest of the register is 0
1640			regBptr[2] = 0;
1641			regBptr[3] = 0;
1642			regBptr[4] = 0;
1643			regBptr[5] = 0;
1644			regBptr[6] = 0;
1645			regBptr[7] = 0;
1646		}
1647#else
1648		*(int*)&regs.valueRegister = (*(int*)&regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
1649#endif
1650		l_bc++;
1651		break;
1652
1653//--------------------
1654// negate value
1655
1656	// Negate the integer value in the variable
1657	case asBC_NEGi:
1658		*(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc))));
1659		l_bc++;
1660		break;
1661
1662	// Negate the float value in the variable
1663	case asBC_NEGf:
1664		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc));
1665		l_bc++;
1666		break;
1667
1668	// Negate the double value in the variable
1669	case asBC_NEGd:
1670		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc));
1671		l_bc++;
1672		break;
1673
1674//-------------------------
1675// Increment value pointed to by address in register
1676
1677	// Increment the short value pointed to by the register
1678	case asBC_INCi16:
1679		(**(short**)&regs.valueRegister)++;
1680		l_bc++;
1681		break;
1682
1683	// Increment the byte value pointed to by the register
1684	case asBC_INCi8:
1685		(**(char**)&regs.valueRegister)++;
1686		l_bc++;
1687		break;
1688
1689	// Decrement the short value pointed to by the register
1690	case asBC_DECi16:
1691		(**(short**)&regs.valueRegister)--;
1692		l_bc++;
1693		break;
1694
1695	// Decrement the byte value pointed to by the register
1696	case asBC_DECi8:
1697		(**(char**)&regs.valueRegister)--;
1698		l_bc++;
1699		break;
1700
1701	// Increment the integer value pointed to by the register
1702	case asBC_INCi:
1703		++(**(int**)&regs.valueRegister);
1704		l_bc++;
1705		break;
1706
1707	// Decrement the integer value pointed to by the register
1708	case asBC_DECi:
1709		--(**(int**)&regs.valueRegister);
1710		l_bc++;
1711		break;
1712
1713	// Increment the float value pointed to by the register
1714	case asBC_INCf:
1715		++(**(float**)&regs.valueRegister);
1716		l_bc++;
1717		break;
1718
1719	// Decrement the float value pointed to by the register
1720	case asBC_DECf:
1721		--(**(float**)&regs.valueRegister);
1722		l_bc++;
1723		break;
1724
1725	// Increment the double value pointed to by the register
1726	case asBC_INCd:
1727		++(**(double**)&regs.valueRegister);
1728		l_bc++;
1729		break;
1730
1731	// Decrement the double value pointed to by the register
1732	case asBC_DECd:
1733		--(**(double**)&regs.valueRegister);
1734		l_bc++;
1735		break;
1736
1737	// Increment the local integer variable
1738	case asBC_IncVi:
1739		(*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++;
1740		l_bc++;
1741		break;
1742
1743	// Decrement the local integer variable
1744	case asBC_DecVi:
1745		(*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--;
1746		l_bc++;
1747		break;
1748
1749//--------------------
1750// bits instructions
1751
1752	// Do a bitwise not on the value in the variable
1753	case asBC_BNOT:
1754		*(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc));
1755		l_bc++;
1756		break;
1757
1758	// Do a bitwise and of two variables and store the result in a third variable
1759	case asBC_BAND:
1760		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc));
1761		l_bc += 2;
1762		break;
1763
1764	// Do a bitwise or of two variables and store the result in a third variable
1765	case asBC_BOR:
1766		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc));
1767		l_bc += 2;
1768		break;
1769
1770	// Do a bitwise xor of two variables and store the result in a third variable
1771	case asBC_BXOR:
1772		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc));
1773		l_bc += 2;
1774		break;
1775
1776	// Do a logical shift left of two variables and store the result in a third variable
1777	case asBC_BSLL:
1778		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
1779		l_bc += 2;
1780		break;
1781
1782	// Do a logical shift right of two variables and store the result in a third variable
1783	case asBC_BSRL:
1784		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
1785		l_bc += 2;
1786		break;
1787
1788	// Do an arithmetic shift right of two variables and store the result in a third variable
1789	case asBC_BSRA:
1790		*(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc));
1791		l_bc += 2;
1792		break;
1793
1794	case asBC_COPY:
1795		{
1796			void *d = (void*)*(size_t*)l_sp; l_sp += AS_PTR_SIZE;
1797			void *s = (void*)*(size_t*)l_sp;
1798			if( s == 0 || d == 0 )
1799			{
1800				// Need to move the values back to the context
1801				regs.programPointer = l_bc;
1802				regs.stackPointer = l_sp;
1803				regs.stackFramePointer = l_fp;
1804
1805				// Raise exception
1806				SetInternalException(TXT_NULL_POINTER_ACCESS);
1807				return;
1808			}
1809			memcpy(d, s, asBC_WORDARG0(l_bc)*4);
1810
1811			// replace the pointer on the stack with the lvalue
1812			*(size_t**)l_sp = (size_t*)d;
1813		}
1814		l_bc++;
1815		break;
1816
1817	case asBC_PshC8:
1818		l_sp -= 2;
1819		*(asQWORD*)l_sp = asBC_QWORDARG(l_bc);
1820		l_bc += 3;
1821		break;
1822
1823	case asBC_RDS8:
1824#ifndef AS_64BIT_PTR
1825		*(asQWORD*)(l_sp-1) = *(asQWORD*)*(size_t*)l_sp;
1826		--l_sp;
1827#else
1828		*(asQWORD*)l_sp = *(asQWORD*)*(size_t*)l_sp;
1829#endif
1830		l_bc++;
1831		break;
1832
1833	case asBC_SWAP8:
1834		{
1835			asQWORD q = *(asQWORD*)l_sp;
1836			*(asQWORD*)l_sp = *(asQWORD*)(l_sp+2);
1837			*(asQWORD*)(l_sp+2) = q;
1838			l_bc++;
1839		}
1840		break;
1841
1842	//----------------------------
1843	// Comparisons
1844	case asBC_CMPd:
1845		{
1846			double dbl = *(double*)(l_fp - asBC_SWORDARG0(l_bc)) - *(double*)(l_fp - asBC_SWORDARG1(l_bc));
1847			if( dbl == 0 )     *(int*)&regs.valueRegister =  0;
1848			else if( dbl < 0 ) *(int*)&regs.valueRegister = -1;
1849			else               *(int*)&regs.valueRegister =  1;
1850			l_bc += 2;
1851		}
1852		break;
1853
1854	case asBC_CMPu:
1855		{
1856			asDWORD d = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
1857			asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
1858			if( d == d2 )     *(int*)&regs.valueRegister =  0;
1859			else if( d < d2 ) *(int*)&regs.valueRegister = -1;
1860			else              *(int*)&regs.valueRegister =  1;
1861			l_bc += 2;
1862		}
1863		break;
1864
1865	case asBC_CMPf:
1866		{
1867			float f = *(float*)(l_fp - asBC_SWORDARG0(l_bc)) - *(float*)(l_fp - asBC_SWORDARG1(l_bc));
1868			if( f == 0 )     *(int*)&regs.valueRegister =  0;
1869			else if( f < 0 ) *(int*)&regs.valueRegister = -1;
1870			else             *(int*)&regs.valueRegister =  1;
1871			l_bc += 2;
1872		}
1873		break;
1874
1875	case asBC_CMPi:
1876		{
1877			int i = *(int*)(l_fp - asBC_SWORDARG0(l_bc)) - *(int*)(l_fp - asBC_SWORDARG1(l_bc));
1878			if( i == 0 )     *(int*)&regs.valueRegister =  0;
1879			else if( i < 0 ) *(int*)&regs.valueRegister = -1;
1880			else             *(int*)&regs.valueRegister =  1;
1881			l_bc += 2;
1882		}
1883		break;
1884
1885	//----------------------------
1886	// Comparisons with constant value
1887	case asBC_CMPIi:
1888		{
1889			int i = *(int*)(l_fp - asBC_SWORDARG0(l_bc)) - asBC_INTARG(l_bc);
1890			if( i == 0 )     *(int*)&regs.valueRegister =  0;
1891			else if( i < 0 ) *(int*)&regs.valueRegister = -1;
1892			else             *(int*)&regs.valueRegister =  1;
1893			l_bc += 2;
1894		}
1895		break;
1896
1897	case asBC_CMPIf:
1898		{
1899			float f = *(float*)(l_fp - asBC_SWORDARG0(l_bc)) - asBC_FLOATARG(l_bc);
1900			if( f == 0 )     *(int*)&regs.valueRegister =  0;
1901			else if( f < 0 ) *(int*)&regs.valueRegister = -1;
1902			else             *(int*)&regs.valueRegister =  1;
1903			l_bc += 2;
1904		}
1905		break;
1906
1907	case asBC_CMPIu:
1908		{
1909			asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
1910			asDWORD d2 = asBC_DWORDARG(l_bc);
1911			if( d1 == d2 )     *(int*)&regs.valueRegister =  0;
1912			else if( d1 < d2 ) *(int*)&regs.valueRegister = -1;
1913			else               *(int*)&regs.valueRegister =  1;
1914			l_bc += 2;
1915		}
1916		break;
1917
1918	case asBC_JMPP:
1919		l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2;
1920		break;
1921
1922	case asBC_PopRPtr:
1923		*(asPTRWORD*)&regs.valueRegister = *(asPTRWORD*)l_sp;
1924		l_sp += AS_PTR_SIZE;
1925		l_bc++;
1926		break;
1927
1928	case asBC_PshRPtr:
1929		l_sp -= AS_PTR_SIZE;
1930		*(asPTRWORD*)l_sp = *(asPTRWORD*)&regs.valueRegister;
1931		l_bc++;
1932		break;
1933
1934	case asBC_STR:
1935		{
1936			// Get the string id from the argument
1937			asWORD w = asBC_WORDARG0(l_bc);
1938			// Push the string pointer on the stack
1939			const asCString &b = engine->GetConstantString(w);
1940			l_sp -= AS_PTR_SIZE;
1941			*(asPTRWORD*)l_sp = (asPTRWORD)(size_t)b.AddressOf();
1942			// Push the string length on the stack
1943			--l_sp;
1944			*l_sp = (asDWORD)b.GetLength();
1945			l_bc++;
1946		}
1947		break;
1948
1949	case asBC_CALLSYS:
1950		{
1951			// Get function ID from the argument
1952			int i = asBC_INTARG(l_bc);
1953
1954			// Need to move the values back to the context as the called functions
1955			// may use the debug interface to inspect the registers
1956			regs.programPointer = l_bc;
1957			regs.stackPointer = l_sp;
1958			regs.stackFramePointer = l_fp;
1959
1960			l_sp += CallSystemFunction(i, this, 0);
1961
1962			// Update the program position after the call so that line number is correct
1963			l_bc += 2;
1964
1965			if( regs.doProcessSuspend )
1966			{
1967				// Should the execution be suspended?
1968				if( doSuspend )
1969				{
1970					regs.programPointer = l_bc;
1971					regs.stackPointer = l_sp;
1972					regs.stackFramePointer = l_fp;
1973
1974					status = asEXECUTION_SUSPENDED;
1975					return;
1976				}
1977				// An exception might have been raised
1978				if( status != asEXECUTION_ACTIVE )
1979				{
1980					regs.programPointer = l_bc;
1981					regs.stackPointer = l_sp;
1982					regs.stackFramePointer = l_fp;
1983
1984					return;
1985				}
1986			}
1987		}
1988		break;
1989
1990	case asBC_CALLBND:
1991		{
1992			// Get the function ID from the stack
1993			int i = asBC_INTARG(l_bc);
1994			l_bc += 2;
1995
1996			asASSERT( i >= 0 );
1997			asASSERT( i & FUNC_IMPORTED

Large files files are truncated, but you can click here to view the full file