PageRenderTime 66ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/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
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-2.0, 0BSD, Unlicense, GPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2009 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_context.cpp
  25. //
  26. // This class handles the execution of the byte code
  27. //
  28. #include <math.h> // fmodf()
  29. #include "as_config.h"
  30. #include "as_context.h"
  31. #include "as_scriptengine.h"
  32. #include "as_tokendef.h"
  33. #include "as_texts.h"
  34. #include "as_callfunc.h"
  35. #include "as_generic.h"
  36. #include "as_debug.h" // mkdir()
  37. #include "as_bytecode.h"
  38. #include "as_scriptobject.h"
  39. #ifdef _MSC_VER
  40. #pragma warning(disable:4702) // unreachable code
  41. #endif
  42. BEGIN_AS_NAMESPACE
  43. // We need at least 2 DWORDs reserved for exception handling
  44. // We need at least 1 DWORD reserved for calling system functions
  45. const int RESERVE_STACK = 2*AS_PTR_SIZE;
  46. // For each script function call we push 5 DWORDs on the call stack
  47. const int CALLSTACK_FRAME_SIZE = 5;
  48. #ifdef AS_DEBUG
  49. // Instruction statistics
  50. int instrCount[256];
  51. int instrCount2[256][256];
  52. int lastBC;
  53. class asCDebugStats
  54. {
  55. public:
  56. asCDebugStats()
  57. {
  58. memset(instrCount, 0, sizeof(instrCount));
  59. }
  60. ~asCDebugStats()
  61. {
  62. /*
  63. // This code writes out some statistics for the VM.
  64. // It's useful for determining what needs to be optimized.
  65. _mkdir("AS_DEBUG");
  66. FILE *f = fopen("AS_DEBUG/total.txt", "at");
  67. if( f )
  68. {
  69. // Output instruction statistics
  70. fprintf(f, "\nTotal count\n");
  71. int n;
  72. for( n = 0; n < BC_MAXBYTECODE; n++ )
  73. {
  74. if( bcName[n].name && instrCount[n] > 0 )
  75. fprintf(f, "%-10.10s : %.0f\n", bcName[n].name, instrCount[n]);
  76. }
  77. fprintf(f, "\nNever executed\n");
  78. for( n = 0; n < BC_MAXBYTECODE; n++ )
  79. {
  80. if( bcName[n].name && instrCount[n] == 0 )
  81. fprintf(f, "%-10.10s\n", bcName[n].name);
  82. }
  83. fclose(f);
  84. }
  85. */
  86. }
  87. double instrCount[256];
  88. } stats;
  89. #endif
  90. AS_API asIScriptContext *asGetActiveContext()
  91. {
  92. asASSERT(threadManager);
  93. asCThreadLocalData *tld = threadManager->GetLocalData();
  94. if( tld->activeContexts.GetLength() == 0 )
  95. return 0;
  96. return tld->activeContexts[tld->activeContexts.GetLength()-1];
  97. }
  98. void asPushActiveContext(asIScriptContext *ctx)
  99. {
  100. asASSERT(threadManager);
  101. asCThreadLocalData *tld = threadManager->GetLocalData();
  102. tld->activeContexts.PushLast(ctx);
  103. }
  104. void asPopActiveContext(asIScriptContext *ctx)
  105. {
  106. asASSERT(threadManager);
  107. asCThreadLocalData *tld = threadManager->GetLocalData();
  108. asASSERT(tld->activeContexts.GetLength() > 0);
  109. asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == ctx);
  110. UNUSED_VAR(ctx);
  111. tld->activeContexts.PopLast();
  112. }
  113. asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
  114. {
  115. #ifdef AS_DEBUG
  116. memset(instrCount, 0, sizeof(instrCount));
  117. memset(instrCount2, 0, sizeof(instrCount2));
  118. lastBC = 255;
  119. #endif
  120. holdEngineRef = holdRef;
  121. if( holdRef )
  122. engine->AddRef();
  123. this->engine = engine;
  124. status = asEXECUTION_UNINITIALIZED;
  125. stackBlockSize = 0;
  126. refCount.set(1);
  127. inExceptionHandler = false;
  128. isStackMemoryNotAllocated = false;
  129. #ifdef AS_DEPRECATED
  130. // Deprecated since 2009-12-08, 2.18.0
  131. stringFunction = 0;
  132. #endif
  133. currentFunction = 0;
  134. regs.objectRegister = 0;
  135. initialFunction = 0;
  136. lineCallback = false;
  137. exceptionCallback = false;
  138. regs.doProcessSuspend = false;
  139. doSuspend = false;
  140. userData = 0;
  141. }
  142. asCContext::~asCContext()
  143. {
  144. DetachEngine();
  145. }
  146. int asCContext::AddRef()
  147. {
  148. return refCount.atomicInc();
  149. }
  150. int asCContext::Release()
  151. {
  152. int r = refCount.atomicDec();
  153. if( r == 0 )
  154. {
  155. asDELETE(this,asCContext);
  156. return 0;
  157. }
  158. return r;
  159. }
  160. void asCContext::DetachEngine()
  161. {
  162. if( engine == 0 ) return;
  163. // Abort any execution
  164. Abort();
  165. // Free all resources
  166. Unprepare();
  167. // Clear engine pointer
  168. if( holdEngineRef )
  169. engine->Release();
  170. engine = 0;
  171. }
  172. asIScriptEngine *asCContext::GetEngine()
  173. {
  174. return engine;
  175. }
  176. void *asCContext::SetUserData(void *data)
  177. {
  178. void *oldData = userData;
  179. userData = data;
  180. return oldData;
  181. }
  182. void *asCContext::GetUserData()
  183. {
  184. return userData;
  185. }
  186. int asCContext::Prepare(int funcID)
  187. {
  188. if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
  189. return asCONTEXT_ACTIVE;
  190. // Clean the stack if not done before
  191. if( status != asEXECUTION_FINISHED && status != asEXECUTION_UNINITIALIZED )
  192. CleanStack();
  193. // Release the returned object (if any)
  194. CleanReturnObject();
  195. if( funcID == -1 )
  196. {
  197. // Use the previously prepared function
  198. if( initialFunction == 0 )
  199. return asNO_FUNCTION;
  200. currentFunction = initialFunction;
  201. }
  202. else if( initialFunction && initialFunction->id == funcID )
  203. {
  204. currentFunction = initialFunction;
  205. }
  206. else
  207. {
  208. // Check engine pointer
  209. asASSERT( engine );
  210. if( initialFunction )
  211. initialFunction->Release();
  212. initialFunction = engine->GetScriptFunction(funcID);
  213. if( initialFunction == 0 )
  214. return asNO_FUNCTION;
  215. initialFunction->AddRef();
  216. currentFunction = initialFunction;
  217. regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
  218. // Determine the minimum stack size needed
  219. // TODO: optimize: GetSpaceNeededForArguments() should be precomputed
  220. int stackSize = currentFunction->GetSpaceNeededForArguments() + currentFunction->stackNeeded + RESERVE_STACK;
  221. stackSize = stackSize > engine->initialContextStackSize ? stackSize : engine->initialContextStackSize;
  222. if( stackSize > stackBlockSize )
  223. {
  224. for( asUINT n = 0; n < stackBlocks.GetLength(); n++ )
  225. if( stackBlocks[n] )
  226. {
  227. asDELETEARRAY(stackBlocks[n]);
  228. }
  229. stackBlocks.SetLength(0);
  230. stackBlockSize = stackSize;
  231. asDWORD *stack = asNEWARRAY(asDWORD,stackBlockSize);
  232. stackBlocks.PushLast(stack);
  233. }
  234. // Reserve space for the arguments and return value
  235. returnValueSize = currentFunction->GetSpaceNeededForReturnValue();
  236. // TODO: optimize: GetSpaceNeededForArguments() should be precomputed
  237. argumentsSize = currentFunction->GetSpaceNeededForArguments() + (currentFunction->objectType ? AS_PTR_SIZE : 0);
  238. }
  239. // Reset state
  240. // Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized
  241. if( status != asEXECUTION_FINISHED )
  242. {
  243. exceptionLine = -1;
  244. exceptionFunction = 0;
  245. isCallingSystemFunction = false;
  246. doAbort = false;
  247. doSuspend = false;
  248. regs.doProcessSuspend = lineCallback;
  249. externalSuspendRequest = false;
  250. stackIndex = 0;
  251. }
  252. status = asEXECUTION_PREPARED;
  253. // Reserve space for the arguments and return value
  254. regs.stackFramePointer = stackBlocks[0] + stackBlockSize - argumentsSize;
  255. regs.stackPointer = regs.stackFramePointer;
  256. // Set arguments to 0
  257. memset(regs.stackPointer, 0, 4*argumentsSize);
  258. if( currentFunction->funcType == asFUNC_SCRIPT )
  259. {
  260. regs.programPointer = currentFunction->byteCode.AddressOf();
  261. // Set all object variables to 0
  262. for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
  263. {
  264. int pos = currentFunction->objVariablePos[n];
  265. *(size_t*)&regs.stackFramePointer[-pos] = 0;
  266. }
  267. }
  268. else
  269. regs.programPointer = 0;
  270. return asSUCCESS;
  271. }
  272. // Free all resources
  273. int asCContext::Unprepare()
  274. {
  275. if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
  276. return asCONTEXT_ACTIVE;
  277. // Only clean the stack if the context was prepared but not executed
  278. if( status != asEXECUTION_UNINITIALIZED )
  279. CleanStack();
  280. // Release the returned object (if any)
  281. CleanReturnObject();
  282. // Release the initial function
  283. if( initialFunction )
  284. initialFunction->Release();
  285. // Clear function pointers
  286. initialFunction = 0;
  287. currentFunction = 0;
  288. exceptionFunction = 0;
  289. regs.programPointer = 0;
  290. // Reset status
  291. status = asEXECUTION_UNINITIALIZED;
  292. // Deallocate the stack blocks
  293. for( asUINT n = 0; n < stackBlocks.GetLength(); n++ )
  294. {
  295. if( stackBlocks[n] )
  296. {
  297. asDELETEARRAY(stackBlocks[n]);
  298. }
  299. }
  300. stackBlocks.SetLength(0);
  301. stackBlockSize = 0;
  302. regs.stackFramePointer = 0;
  303. regs.stackPointer = 0;
  304. stackIndex = 0;
  305. #ifdef AS_DEPRECATED
  306. // Deprecated since 2009-12-08, 2.18.0
  307. // Deallocate string function
  308. if( stringFunction )
  309. {
  310. stringFunction->Release();
  311. stringFunction = 0;
  312. }
  313. #endif
  314. return 0;
  315. }
  316. #ifdef AS_DEPRECATED
  317. // Deprecated since 2009-12-08, 2.18.0
  318. int asCContext::SetExecuteStringFunction(asCScriptFunction *func)
  319. {
  320. if( stringFunction )
  321. stringFunction->Release();
  322. // The new function already has the refCount set to 1
  323. stringFunction = func;
  324. return 0;
  325. }
  326. #endif
  327. asBYTE asCContext::GetReturnByte()
  328. {
  329. if( status != asEXECUTION_FINISHED ) return 0;
  330. asCDataType *dt = &initialFunction->returnType;
  331. if( dt->IsObject() || dt->IsReference() ) return 0;
  332. return *(asBYTE*)&regs.valueRegister;
  333. }
  334. asWORD asCContext::GetReturnWord()
  335. {
  336. if( status != asEXECUTION_FINISHED ) return 0;
  337. asCDataType *dt = &initialFunction->returnType;
  338. if( dt->IsObject() || dt->IsReference() ) return 0;
  339. return *(asWORD*)&regs.valueRegister;
  340. }
  341. asDWORD asCContext::GetReturnDWord()
  342. {
  343. if( status != asEXECUTION_FINISHED ) return 0;
  344. asCDataType *dt = &initialFunction->returnType;
  345. if( dt->IsObject() || dt->IsReference() ) return 0;
  346. return *(asDWORD*)&regs.valueRegister;
  347. }
  348. asQWORD asCContext::GetReturnQWord()
  349. {
  350. if( status != asEXECUTION_FINISHED ) return 0;
  351. asCDataType *dt = &initialFunction->returnType;
  352. if( dt->IsObject() || dt->IsReference() ) return 0;
  353. return regs.valueRegister;
  354. }
  355. float asCContext::GetReturnFloat()
  356. {
  357. if( status != asEXECUTION_FINISHED ) return 0;
  358. asCDataType *dt = &initialFunction->returnType;
  359. if( dt->IsObject() || dt->IsReference() ) return 0;
  360. return *(float*)&regs.valueRegister;
  361. }
  362. double asCContext::GetReturnDouble()
  363. {
  364. if( status != asEXECUTION_FINISHED ) return 0;
  365. asCDataType *dt = &initialFunction->returnType;
  366. if( dt->IsObject() || dt->IsReference() ) return 0;
  367. return *(double*)&regs.valueRegister;
  368. }
  369. void *asCContext::GetReturnAddress()
  370. {
  371. if( status != asEXECUTION_FINISHED ) return 0;
  372. asCDataType *dt = &initialFunction->returnType;
  373. if( dt->IsReference() )
  374. return *(void**)&regs.valueRegister;
  375. else if( dt->IsObject() )
  376. return regs.objectRegister;
  377. return 0;
  378. }
  379. void *asCContext::GetReturnObject()
  380. {
  381. if( status != asEXECUTION_FINISHED ) return 0;
  382. asCDataType *dt = &initialFunction->returnType;
  383. if( !dt->IsObject() ) return 0;
  384. if( dt->IsReference() )
  385. return *(void**)(size_t)regs.valueRegister;
  386. else
  387. return regs.objectRegister;
  388. }
  389. void *asCContext::GetAddressOfReturnValue()
  390. {
  391. if( status != asEXECUTION_FINISHED ) return 0;
  392. asCDataType *dt = &initialFunction->returnType;
  393. // An object is stored in the objectRegister
  394. if( !dt->IsReference() && dt->IsObject() )
  395. {
  396. // Need to dereference objects
  397. if( !dt->IsObjectHandle() )
  398. return *(void**)&regs.objectRegister;
  399. return &regs.objectRegister;
  400. }
  401. // Primitives and references are stored in valueRegister
  402. return &regs.valueRegister;
  403. }
  404. int asCContext::SetObject(void *obj)
  405. {
  406. if( status != asEXECUTION_PREPARED )
  407. return asCONTEXT_NOT_PREPARED;
  408. if( !initialFunction->objectType )
  409. {
  410. status = asEXECUTION_ERROR;
  411. return asERROR;
  412. }
  413. *(size_t*)&regs.stackFramePointer[0] = (size_t)obj;
  414. return 0;
  415. }
  416. int asCContext::SetArgByte(asUINT arg, asBYTE value)
  417. {
  418. if( status != asEXECUTION_PREPARED )
  419. return asCONTEXT_NOT_PREPARED;
  420. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  421. {
  422. status = asEXECUTION_ERROR;
  423. return asINVALID_ARG;
  424. }
  425. // Verify the type of the argument
  426. asCDataType *dt = &initialFunction->parameterTypes[arg];
  427. if( dt->IsObject() || dt->IsReference() )
  428. {
  429. status = asEXECUTION_ERROR;
  430. return asINVALID_TYPE;
  431. }
  432. if( dt->GetSizeInMemoryBytes() != 1 )
  433. {
  434. status = asEXECUTION_ERROR;
  435. return asINVALID_TYPE;
  436. }
  437. // Determine the position of the argument
  438. int offset = 0;
  439. if( initialFunction->objectType )
  440. offset += AS_PTR_SIZE;
  441. for( asUINT n = 0; n < arg; n++ )
  442. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  443. // Set the value
  444. *(asBYTE*)&regs.stackFramePointer[offset] = value;
  445. return 0;
  446. }
  447. int asCContext::SetArgWord(asUINT arg, asWORD value)
  448. {
  449. if( status != asEXECUTION_PREPARED )
  450. return asCONTEXT_NOT_PREPARED;
  451. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  452. {
  453. status = asEXECUTION_ERROR;
  454. return asINVALID_ARG;
  455. }
  456. // Verify the type of the argument
  457. asCDataType *dt = &initialFunction->parameterTypes[arg];
  458. if( dt->IsObject() || dt->IsReference() )
  459. {
  460. status = asEXECUTION_ERROR;
  461. return asINVALID_TYPE;
  462. }
  463. if( dt->GetSizeInMemoryBytes() != 2 )
  464. {
  465. status = asEXECUTION_ERROR;
  466. return asINVALID_TYPE;
  467. }
  468. // Determine the position of the argument
  469. int offset = 0;
  470. if( initialFunction->objectType )
  471. offset += AS_PTR_SIZE;
  472. for( asUINT n = 0; n < arg; n++ )
  473. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  474. // Set the value
  475. *(asWORD*)&regs.stackFramePointer[offset] = value;
  476. return 0;
  477. }
  478. int asCContext::SetArgDWord(asUINT arg, asDWORD value)
  479. {
  480. if( status != asEXECUTION_PREPARED )
  481. return asCONTEXT_NOT_PREPARED;
  482. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  483. {
  484. status = asEXECUTION_ERROR;
  485. return asINVALID_ARG;
  486. }
  487. // Verify the type of the argument
  488. asCDataType *dt = &initialFunction->parameterTypes[arg];
  489. if( dt->IsObject() || dt->IsReference() )
  490. {
  491. status = asEXECUTION_ERROR;
  492. return asINVALID_TYPE;
  493. }
  494. if( dt->GetSizeInMemoryBytes() != 4 )
  495. {
  496. status = asEXECUTION_ERROR;
  497. return asINVALID_TYPE;
  498. }
  499. // Determine the position of the argument
  500. int offset = 0;
  501. if( initialFunction->objectType )
  502. offset += AS_PTR_SIZE;
  503. for( asUINT n = 0; n < arg; n++ )
  504. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  505. // Set the value
  506. *(asDWORD*)&regs.stackFramePointer[offset] = value;
  507. return 0;
  508. }
  509. int asCContext::SetArgQWord(asUINT arg, asQWORD value)
  510. {
  511. if( status != asEXECUTION_PREPARED )
  512. return asCONTEXT_NOT_PREPARED;
  513. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  514. {
  515. status = asEXECUTION_ERROR;
  516. return asINVALID_ARG;
  517. }
  518. // Verify the type of the argument
  519. asCDataType *dt = &initialFunction->parameterTypes[arg];
  520. if( dt->IsObject() || dt->IsReference() )
  521. {
  522. status = asEXECUTION_ERROR;
  523. return asINVALID_TYPE;
  524. }
  525. if( dt->GetSizeOnStackDWords() != 2 )
  526. {
  527. status = asEXECUTION_ERROR;
  528. return asINVALID_TYPE;
  529. }
  530. // Determine the position of the argument
  531. int offset = 0;
  532. if( initialFunction->objectType )
  533. offset += AS_PTR_SIZE;
  534. for( asUINT n = 0; n < arg; n++ )
  535. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  536. // Set the value
  537. *(asQWORD*)(&regs.stackFramePointer[offset]) = value;
  538. return 0;
  539. }
  540. int asCContext::SetArgFloat(asUINT arg, float value)
  541. {
  542. if( status != asEXECUTION_PREPARED )
  543. return asCONTEXT_NOT_PREPARED;
  544. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  545. {
  546. status = asEXECUTION_ERROR;
  547. return asINVALID_ARG;
  548. }
  549. // Verify the type of the argument
  550. asCDataType *dt = &initialFunction->parameterTypes[arg];
  551. if( dt->IsObject() || dt->IsReference() )
  552. {
  553. status = asEXECUTION_ERROR;
  554. return asINVALID_TYPE;
  555. }
  556. if( dt->GetSizeOnStackDWords() != 1 )
  557. {
  558. status = asEXECUTION_ERROR;
  559. return asINVALID_TYPE;
  560. }
  561. // Determine the position of the argument
  562. int offset = 0;
  563. if( initialFunction->objectType )
  564. offset += AS_PTR_SIZE;
  565. for( asUINT n = 0; n < arg; n++ )
  566. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  567. // Set the value
  568. *(float*)(&regs.stackFramePointer[offset]) = value;
  569. return 0;
  570. }
  571. int asCContext::SetArgDouble(asUINT arg, double value)
  572. {
  573. if( status != asEXECUTION_PREPARED )
  574. return asCONTEXT_NOT_PREPARED;
  575. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  576. {
  577. status = asEXECUTION_ERROR;
  578. return asINVALID_ARG;
  579. }
  580. // Verify the type of the argument
  581. asCDataType *dt = &initialFunction->parameterTypes[arg];
  582. if( dt->IsObject() || dt->IsReference() )
  583. {
  584. status = asEXECUTION_ERROR;
  585. return asINVALID_TYPE;
  586. }
  587. if( dt->GetSizeOnStackDWords() != 2 )
  588. {
  589. status = asEXECUTION_ERROR;
  590. return asINVALID_TYPE;
  591. }
  592. // Determine the position of the argument
  593. int offset = 0;
  594. if( initialFunction->objectType )
  595. offset += AS_PTR_SIZE;
  596. for( asUINT n = 0; n < arg; n++ )
  597. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  598. // Set the value
  599. *(double*)(&regs.stackFramePointer[offset]) = value;
  600. return 0;
  601. }
  602. int asCContext::SetArgAddress(asUINT arg, void *value)
  603. {
  604. if( status != asEXECUTION_PREPARED )
  605. return asCONTEXT_NOT_PREPARED;
  606. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  607. {
  608. status = asEXECUTION_ERROR;
  609. return asINVALID_ARG;
  610. }
  611. // Verify the type of the argument
  612. asCDataType *dt = &initialFunction->parameterTypes[arg];
  613. if( !dt->IsReference() && !dt->IsObjectHandle() )
  614. {
  615. status = asEXECUTION_ERROR;
  616. return asINVALID_TYPE;
  617. }
  618. // Determine the position of the argument
  619. int offset = 0;
  620. if( initialFunction->objectType )
  621. offset += AS_PTR_SIZE;
  622. for( asUINT n = 0; n < arg; n++ )
  623. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  624. // Set the value
  625. *(size_t*)(&regs.stackFramePointer[offset]) = (size_t)value;
  626. return 0;
  627. }
  628. int asCContext::SetArgObject(asUINT arg, void *obj)
  629. {
  630. if( status != asEXECUTION_PREPARED )
  631. return asCONTEXT_NOT_PREPARED;
  632. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  633. {
  634. status = asEXECUTION_ERROR;
  635. return asINVALID_ARG;
  636. }
  637. // Verify the type of the argument
  638. asCDataType *dt = &initialFunction->parameterTypes[arg];
  639. if( !dt->IsObject() )
  640. {
  641. status = asEXECUTION_ERROR;
  642. return asINVALID_TYPE;
  643. }
  644. // If the object should be sent by value we must make a copy of it
  645. if( !dt->IsReference() )
  646. {
  647. if( dt->IsObjectHandle() )
  648. {
  649. // Increase the reference counter
  650. asSTypeBehaviour *beh = &dt->GetObjectType()->beh;
  651. if( obj && beh->addref )
  652. engine->CallObjectMethod(obj, beh->addref);
  653. }
  654. else
  655. {
  656. obj = engine->CreateScriptObjectCopy(obj, engine->GetTypeIdFromDataType(*dt));
  657. }
  658. }
  659. // Determine the position of the argument
  660. int offset = 0;
  661. if( initialFunction->objectType )
  662. offset += AS_PTR_SIZE;
  663. for( asUINT n = 0; n < arg; n++ )
  664. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  665. // Set the value
  666. *(size_t*)(&regs.stackFramePointer[offset]) = (size_t)obj;
  667. return 0;
  668. }
  669. // TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
  670. // interface
  671. void *asCContext::GetAddressOfArg(asUINT arg)
  672. {
  673. if( status != asEXECUTION_PREPARED )
  674. return 0;
  675. if( arg >= (unsigned)initialFunction->parameterTypes.GetLength() )
  676. return 0;
  677. // Determine the position of the argument
  678. int offset = 0;
  679. if( initialFunction->objectType )
  680. offset += AS_PTR_SIZE;
  681. for( asUINT n = 0; n < arg; n++ )
  682. offset += initialFunction->parameterTypes[n].GetSizeOnStackDWords();
  683. // We should return the address of the location where the argument value will be placed
  684. // All registered types are always sent by reference, even if
  685. // the function is declared to receive the argument by value.
  686. return &regs.stackFramePointer[offset];
  687. }
  688. int asCContext::Abort()
  689. {
  690. // TODO: multithread: Make thread safe
  691. if( engine == 0 ) return asERROR;
  692. if( status == asEXECUTION_SUSPENDED )
  693. status = asEXECUTION_ABORTED;
  694. doSuspend = true;
  695. regs.doProcessSuspend = true;
  696. externalSuspendRequest = true;
  697. doAbort = true;
  698. return 0;
  699. }
  700. // interface
  701. int asCContext::Suspend()
  702. {
  703. // This function just sets some internal flags and is safe
  704. // to call from a secondary thread, even if the library has
  705. // been built without multi-thread support.
  706. if( engine == 0 ) return asERROR;
  707. doSuspend = true;
  708. externalSuspendRequest = true;
  709. regs.doProcessSuspend = true;
  710. return 0;
  711. }
  712. // interface
  713. int asCContext::Execute()
  714. {
  715. asASSERT( engine != 0 );
  716. if( status != asEXECUTION_SUSPENDED && status != asEXECUTION_PREPARED )
  717. return asERROR;
  718. status = asEXECUTION_ACTIVE;
  719. asPushActiveContext((asIScriptContext *)this);
  720. if( regs.programPointer == 0 )
  721. {
  722. if( currentFunction->funcType == asFUNC_VIRTUAL ||
  723. currentFunction->funcType == asFUNC_INTERFACE )
  724. {
  725. // The currentFunction is a virtual method
  726. // Determine the true function from the object
  727. asCScriptObject *obj = *(asCScriptObject**)(size_t*)regs.stackFramePointer;
  728. if( obj == 0 )
  729. {
  730. SetInternalException(TXT_NULL_POINTER_ACCESS);
  731. }
  732. else
  733. {
  734. asCObjectType *objType = obj->objType;
  735. asCScriptFunction *realFunc = 0;
  736. if( currentFunction->funcType == asFUNC_VIRTUAL )
  737. {
  738. if( objType->virtualFunctionTable.GetLength() > (asUINT)currentFunction->vfTableIdx )
  739. {
  740. realFunc = objType->virtualFunctionTable[currentFunction->vfTableIdx];
  741. }
  742. }
  743. else
  744. {
  745. // Search the object type for a function that matches the interface function
  746. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  747. {
  748. asCScriptFunction *f2 = engine->scriptFunctions[objType->methods[n]];
  749. if( f2->signatureId == currentFunction->signatureId )
  750. {
  751. if( f2->funcType == asFUNC_VIRTUAL )
  752. realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
  753. else
  754. realFunc = f2;
  755. break;
  756. }
  757. }
  758. }
  759. if( realFunc )
  760. {
  761. if( realFunc->signatureId != currentFunction->signatureId )
  762. {
  763. SetInternalException(TXT_NULL_POINTER_ACCESS);
  764. }
  765. else
  766. {
  767. currentFunction = realFunc;
  768. regs.programPointer = currentFunction->byteCode.AddressOf();
  769. regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
  770. // Set the local objects to 0
  771. for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
  772. {
  773. int pos = currentFunction->objVariablePos[n];
  774. *(size_t*)&regs.stackFramePointer[-pos] = 0;
  775. }
  776. }
  777. }
  778. }
  779. }
  780. else if( currentFunction->funcType == asFUNC_SYSTEM )
  781. {
  782. // The current function is an application registered function
  783. // Call the function directly
  784. CallSystemFunction(currentFunction->id, this, 0);
  785. // Was the call successful?
  786. if( status == asEXECUTION_ACTIVE )
  787. {
  788. status = asEXECUTION_FINISHED;
  789. }
  790. }
  791. else
  792. {
  793. // This shouldn't happen
  794. asASSERT(false);
  795. }
  796. }
  797. while( status == asEXECUTION_ACTIVE )
  798. ExecuteNext();
  799. doSuspend = false;
  800. regs.doProcessSuspend = lineCallback;
  801. asPopActiveContext((asIScriptContext *)this);
  802. #ifdef AS_DEBUG
  803. /*
  804. // Output instruction statistics
  805. // This is useful for determining what needs to be optimized.
  806. _mkdir("AS_DEBUG");
  807. FILE *f = fopen("AS_DEBUG/stats.txt", "at");
  808. fprintf(f, "\n");
  809. asQWORD total = 0;
  810. int n;
  811. for( n = 0; n < 256; n++ )
  812. {
  813. if( bcName[n].name && instrCount[n] )
  814. fprintf(f, "%-10.10s : %d\n", bcName[n].name, instrCount[n]);
  815. total += instrCount[n];
  816. }
  817. fprintf(f, "\ntotal : %I64d\n", total);
  818. fprintf(f, "\n");
  819. for( n = 0; n < 256; n++ )
  820. {
  821. if( bcName[n].name )
  822. {
  823. for( int m = 0; m < 256; m++ )
  824. {
  825. if( instrCount2[n][m] )
  826. fprintf(f, "%-10.10s, %-10.10s : %d\n", bcName[n].name, bcName[m].name, instrCount2[n][m]);
  827. }
  828. }
  829. }
  830. fclose(f);
  831. */
  832. #endif
  833. if( status == asEXECUTION_FINISHED )
  834. {
  835. regs.objectType = initialFunction->returnType.GetObjectType();
  836. return asEXECUTION_FINISHED;
  837. }
  838. if( status == asEXECUTION_SUSPENDED )
  839. return asEXECUTION_SUSPENDED;
  840. if( doAbort )
  841. {
  842. doAbort = false;
  843. status = asEXECUTION_ABORTED;
  844. return asEXECUTION_ABORTED;
  845. }
  846. if( status == asEXECUTION_EXCEPTION )
  847. return asEXECUTION_EXCEPTION;
  848. return asERROR;
  849. }
  850. void asCContext::PushCallState()
  851. {
  852. callStack.SetLength(callStack.GetLength() + CALLSTACK_FRAME_SIZE);
  853. // Separating the loads and stores limits data cache trash, and with a smart compiler
  854. // could turn into SIMD style loading/storing if available.
  855. // The compiler can't do this itself due to potential pointer aliasing between the pointers,
  856. // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example
  857. // for all the compiler knows. So introducing the local variable s, which is never referred to by
  858. // its address we avoid this issue.
  859. size_t s[5];
  860. s[0] = (size_t)regs.stackFramePointer;
  861. s[1] = (size_t)currentFunction;
  862. s[2] = (size_t)regs.programPointer;
  863. s[3] = (size_t)regs.stackPointer;
  864. s[4] = stackIndex;
  865. size_t *tmp = callStack.AddressOf() + callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  866. tmp[0] = s[0];
  867. tmp[1] = s[1];
  868. tmp[2] = s[2];
  869. tmp[3] = s[3];
  870. tmp[4] = s[4];
  871. }
  872. void asCContext::PopCallState()
  873. {
  874. // See comments in PushCallState about pointer aliasing and data cache trashing
  875. size_t *tmp = callStack.AddressOf() + callStack.GetLength() - CALLSTACK_FRAME_SIZE;
  876. size_t s[5];
  877. s[0] = tmp[0];
  878. s[1] = tmp[1];
  879. s[2] = tmp[2];
  880. s[3] = tmp[3];
  881. s[4] = tmp[4];
  882. regs.stackFramePointer = (asDWORD*)s[0];
  883. currentFunction = (asCScriptFunction*)s[1];
  884. regs.programPointer = (asDWORD*)s[2];
  885. regs.stackPointer = (asDWORD*)s[3];
  886. stackIndex = (int)s[4];
  887. regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
  888. callStack.SetLength(callStack.GetLength() - CALLSTACK_FRAME_SIZE);
  889. }
  890. int asCContext::GetCallstackSize()
  891. {
  892. return (int)callStack.GetLength() / CALLSTACK_FRAME_SIZE;
  893. }
  894. int asCContext::GetCallstackFunction(int index)
  895. {
  896. if( index < 0 || index >= GetCallstackSize() ) return asINVALID_ARG;
  897. size_t *s = callStack.AddressOf() + index*CALLSTACK_FRAME_SIZE;
  898. asCScriptFunction *func = (asCScriptFunction*)s[1];
  899. return func->id;
  900. }
  901. int asCContext::GetCallstackLineNumber(int index, int *column)
  902. {
  903. if( index < 0 || index >= GetCallstackSize() ) return asINVALID_ARG;
  904. size_t *s = callStack.AddressOf() + index*CALLSTACK_FRAME_SIZE;
  905. asCScriptFunction *func = (asCScriptFunction*)s[1];
  906. asDWORD *bytePos = (asDWORD*)s[2];
  907. asDWORD line = func->GetLineNumber(int(bytePos - func->byteCode.AddressOf()));
  908. if( column ) *column = (line >> 20);
  909. return (line & 0xFFFFF);
  910. }
  911. void asCContext::CallScriptFunction(asCScriptFunction *func)
  912. {
  913. // Push the framepointer, function id and programCounter on the stack
  914. PushCallState();
  915. currentFunction = func;
  916. regs.globalVarPointers = currentFunction->globalVarPointers.AddressOf();
  917. regs.programPointer = currentFunction->byteCode.AddressOf();
  918. // Verify if there is enough room in the stack block. Allocate new block if not
  919. if( regs.stackPointer - (func->stackNeeded + RESERVE_STACK) < stackBlocks[stackIndex] )
  920. {
  921. asDWORD *oldStackPointer = regs.stackPointer;
  922. // The size of each stack block is determined by the following formula:
  923. // size = stackBlockSize << index
  924. while( regs.stackPointer - (func->stackNeeded + RESERVE_STACK) < stackBlocks[stackIndex] )
  925. {
  926. // Make sure we don't allocate more space than allowed
  927. if( engine->ep.maximumContextStackSize )
  928. {
  929. // This test will only stop growth once it has already crossed the limit
  930. if( stackBlockSize * ((1 << (stackIndex+1)) - 1) > engine->ep.maximumContextStackSize )
  931. {
  932. isStackMemoryNotAllocated = true;
  933. // Set the stackFramePointer, even though the stackPointer wasn't updated
  934. regs.stackFramePointer = regs.stackPointer;
  935. // TODO: Make sure the exception handler doesn't try to free objects that have not been initialized
  936. SetInternalException(TXT_STACK_OVERFLOW);
  937. return;
  938. }
  939. }
  940. stackIndex++;
  941. if( (int)stackBlocks.GetLength() == stackIndex )
  942. {
  943. asDWORD *stack = asNEWARRAY(asDWORD,(stackBlockSize << stackIndex));
  944. stackBlocks.PushLast(stack);
  945. }
  946. regs.stackPointer = stackBlocks[stackIndex] + (stackBlockSize<<stackIndex) - func->GetSpaceNeededForArguments();
  947. }
  948. // Copy the function arguments to the new stack space
  949. memcpy(regs.stackPointer, oldStackPointer, sizeof(asDWORD)*func->GetSpaceNeededForArguments());
  950. }
  951. // Update framepointer and programCounter
  952. regs.stackFramePointer = regs.stackPointer;
  953. // Set all object variables to 0
  954. for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
  955. {
  956. int pos = currentFunction->objVariablePos[n];
  957. *(size_t*)&regs.stackFramePointer[-pos] = 0;
  958. }
  959. }
  960. void asCContext::CallInterfaceMethod(asCScriptFunction *func)
  961. {
  962. // Resolve the interface method using the current script type
  963. asCScriptObject *obj = *(asCScriptObject**)(size_t*)regs.stackPointer;
  964. if( obj == 0 )
  965. {
  966. SetInternalException(TXT_NULL_POINTER_ACCESS);
  967. return;
  968. }
  969. asCObjectType *objType = obj->objType;
  970. // TODO: optimize: The object type should have a list of only those methods that
  971. // implement interface methods. This list should be ordered by
  972. // the signatureId so that a binary search can be made, instead
  973. // of a linear search.
  974. //
  975. // When this is done, we must also make sure the signatureId of a
  976. // function never changes, e.g. when if the signature functions are
  977. // released.
  978. // Search the object type for a function that matches the interface function
  979. asCScriptFunction *realFunc = 0;
  980. if( func->funcType == asFUNC_INTERFACE )
  981. {
  982. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  983. {
  984. asCScriptFunction *f2 = engine->scriptFunctions[objType->methods[n]];
  985. if( f2->signatureId == func->signatureId )
  986. {
  987. if( f2->funcType == asFUNC_VIRTUAL )
  988. realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
  989. else
  990. realFunc = f2;
  991. break;
  992. }
  993. }
  994. if( realFunc == 0 )
  995. {
  996. SetInternalException(TXT_NULL_POINTER_ACCESS);
  997. return;
  998. }
  999. }
  1000. else /* if( func->funcType == asFUNC_VIRTUAL ) */
  1001. {
  1002. realFunc = objType->virtualFunctionTable[func->vfTableIdx];
  1003. }
  1004. // Then call the true script function
  1005. CallScriptFunction(realFunc);
  1006. }
  1007. void asCContext::ExecuteNext()
  1008. {
  1009. asDWORD *l_bc = regs.programPointer;
  1010. asDWORD *l_sp = regs.stackPointer;
  1011. asDWORD *l_fp = regs.stackFramePointer;
  1012. for(;;)
  1013. {
  1014. #ifdef AS_DEBUG
  1015. ++stats.instrCount[*(asBYTE*)l_bc];
  1016. ++instrCount[*(asBYTE*)l_bc];
  1017. ++instrCount2[lastBC][*(asBYTE*)l_bc];
  1018. lastBC = *(asBYTE*)l_bc;
  1019. // Used to verify that the size of the instructions are correct
  1020. asDWORD *old = l_bc;
  1021. #endif
  1022. // Remember to keep the cases in order and without
  1023. // gaps, because that will make the switch faster.
  1024. // It will be faster since only one lookup will be
  1025. // made to find the correct jump destination. If not
  1026. // in order, the switch will make two lookups.
  1027. switch( *(asBYTE*)l_bc )
  1028. {
  1029. //--------------
  1030. // memory access functions
  1031. // Decrease the stack pointer with n dwords (stack grows downward)
  1032. case asBC_POP:
  1033. l_sp += asBC_WORDARG0(l_bc);
  1034. l_bc++;
  1035. break;
  1036. // Increase the stack pointer with n dwords
  1037. case asBC_PUSH:
  1038. l_sp -= asBC_WORDARG0(l_bc);
  1039. l_bc++;
  1040. break;
  1041. // Push a dword value on the stack
  1042. case asBC_PshC4:
  1043. --l_sp;
  1044. *l_sp = asBC_DWORDARG(l_bc);
  1045. l_bc += 2;
  1046. break;
  1047. // Push the dword value of a variable on the stack
  1048. case asBC_PshV4:
  1049. --l_sp;
  1050. *l_sp = *(l_fp - asBC_SWORDARG0(l_bc));
  1051. l_bc++;
  1052. break;
  1053. // Push the address of a variable on the stack
  1054. case asBC_PSF:
  1055. l_sp -= AS_PTR_SIZE;
  1056. *(asPTRWORD*)l_sp = (asPTRWORD)size_t(l_fp - asBC_SWORDARG0(l_bc));
  1057. l_bc++;
  1058. break;
  1059. // Swap the top 2 dwords on the stack
  1060. case asBC_SWAP4:
  1061. {
  1062. asDWORD d = (asDWORD)*l_sp;
  1063. *l_sp = *(l_sp+1);
  1064. *(asDWORD*)(l_sp+1) = d;
  1065. l_bc++;
  1066. }
  1067. break;
  1068. // Do a boolean not operation, modifying the value of the variable
  1069. case asBC_NOT:
  1070. #if AS_SIZEOF_BOOL == 1
  1071. {
  1072. // Set the value to true if it is equal to 0
  1073. // We need to use volatile here to tell the compiler it cannot
  1074. // change the order of read and write operations on the pointer.
  1075. volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  1076. asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1077. ptr[0] = val; // The result is stored in the lower byte
  1078. ptr[1] = 0; // Make sure the rest of the DWORD is 0
  1079. ptr[2] = 0;
  1080. ptr[3] = 0;
  1081. }
  1082. #else
  1083. *(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1084. #endif
  1085. l_bc++;
  1086. break;
  1087. // Push the dword value of a global variable on the stack
  1088. case asBC_PshG4:
  1089. --l_sp;
  1090. // TODO: global: The global var address should be stored in the instruction directly
  1091. *l_sp = *(asDWORD*)regs.globalVarPointers[asBC_WORDARG0(l_bc)];
  1092. l_bc++;
  1093. break;
  1094. // Load the address of a global variable in the register, then
  1095. // copy the value of the global variable into a local variable
  1096. case asBC_LdGRdR4:
  1097. // TODO: global: The global var address should be stored in the instruction directly
  1098. *(void**)&regs.valueRegister = regs.globalVarPointers[asBC_WORDARG1(l_bc)];
  1099. *(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&regs.valueRegister;
  1100. l_bc += 2;
  1101. break;
  1102. //----------------
  1103. // path control instructions
  1104. // Begin execution of a script function
  1105. case asBC_CALL:
  1106. {
  1107. int i = asBC_INTARG(l_bc);
  1108. l_bc += 2;
  1109. asASSERT( i >= 0 );
  1110. asASSERT( (i & FUNC_IMPORTED) == 0 );
  1111. // Need to move the values back to the context
  1112. regs.programPointer = l_bc;
  1113. regs.stackPointer = l_sp;
  1114. regs.stackFramePointer = l_fp;
  1115. CallScriptFunction(engine->scriptFunctions[i]);
  1116. // Extract the values from the context again
  1117. l_bc = regs.programPointer;
  1118. l_sp = regs.stackPointer;
  1119. l_fp = regs.stackFramePointer;
  1120. // If status isn't active anymore then we must stop
  1121. if( status != asEXECUTION_ACTIVE )
  1122. return;
  1123. }
  1124. break;
  1125. // Return to the caller, and remove the arguments from the stack
  1126. case asBC_RET:
  1127. {
  1128. if( callStack.GetLength() == 0 )
  1129. {
  1130. status = asEXECUTION_FINISHED;
  1131. return;
  1132. }
  1133. asWORD w = asBC_WORDARG0(l_bc);
  1134. // Read the old framepointer, functionid, and programCounter from the call stack
  1135. PopCallState();
  1136. // Extract the values from the context again
  1137. l_bc = regs.programPointer;
  1138. l_sp = regs.stackPointer;
  1139. l_fp = regs.stackFramePointer;
  1140. // Pop arguments from stack
  1141. l_sp += w;
  1142. }
  1143. break;
  1144. // Jump to a relative position
  1145. case asBC_JMP:
  1146. l_bc += 2 + asBC_INTARG(l_bc);
  1147. break;
  1148. //----------------
  1149. // Conditional jumps
  1150. // Jump to a relative position if the value in the register is 0
  1151. case asBC_JZ:
  1152. if( *(int*)&regs.valueRegister == 0 )
  1153. l_bc += asBC_INTARG(l_bc) + 2;
  1154. else
  1155. l_bc += 2;
  1156. break;
  1157. // Jump to a relative position if the value in the register is not 0
  1158. case asBC_JNZ:
  1159. if( *(int*)&regs.valueRegister != 0 )
  1160. l_bc += asBC_INTARG(l_bc) + 2;
  1161. else
  1162. l_bc += 2;
  1163. break;
  1164. // Jump to a relative position if the value in the register is negative
  1165. case asBC_JS:
  1166. if( *(int*)&regs.valueRegister < 0 )
  1167. l_bc += asBC_INTARG(l_bc) + 2;
  1168. else
  1169. l_bc += 2;
  1170. break;
  1171. // Jump to a relative position if the value in the register it not negative
  1172. case asBC_JNS:
  1173. if( *(int*)&regs.valueRegister >= 0 )
  1174. l_bc += asBC_INTARG(l_bc) + 2;
  1175. else
  1176. l_bc += 2;
  1177. break;
  1178. // Jump to a relative position if the value in the register is greater than 0
  1179. case asBC_JP:
  1180. if( *(int*)&regs.valueRegister > 0 )
  1181. l_bc += asBC_INTARG(l_bc) + 2;
  1182. else
  1183. l_bc += 2;
  1184. break;
  1185. // Jump to a relative position if the value in the register is not greater than 0
  1186. case asBC_JNP:
  1187. if( *(int*)&regs.valueRegister <= 0 )
  1188. l_bc += asBC_INTARG(l_bc) + 2;
  1189. else
  1190. l_bc += 2;
  1191. break;
  1192. //--------------------
  1193. // test instructions
  1194. // If the value in the register is 0, then set the register to 1, else to 0
  1195. case asBC_TZ:
  1196. #if AS_SIZEOF_BOOL == 1
  1197. {
  1198. // Set the value to true if it is equal to 0
  1199. // We need to use volatile here to tell the compiler it cannot
  1200. // change the order of read and write operations on valueRegister.
  1201. volatile int *regPtr = (int*)&regs.valueRegister;
  1202. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1203. asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1204. regBptr[0] = val; // The result is stored in the lower byte
  1205. regBptr[1] = 0; // Make sure the rest of the register is 0
  1206. regBptr[2] = 0;
  1207. regBptr[3] = 0;
  1208. regBptr[4] = 0;
  1209. regBptr[5] = 0;
  1210. regBptr[6] = 0;
  1211. regBptr[7] = 0;
  1212. }
  1213. #else
  1214. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1215. #endif
  1216. l_bc++;
  1217. break;
  1218. // If the value in the register is not 0, then set the register to 1, else to 0
  1219. case asBC_TNZ:
  1220. #if AS_SIZEOF_BOOL == 1
  1221. {
  1222. // Set the value to true if it is not equal to 0
  1223. // We need to use volatile here to tell the compiler it cannot
  1224. // change the order of read and write operations on valueRegister.
  1225. volatile int *regPtr = (int*)&regs.valueRegister;
  1226. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1227. asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE;
  1228. regBptr[0] = val; // The result is stored in the lower byte
  1229. regBptr[1] = 0; // Make sure the rest of the register is 0
  1230. regBptr[2] = 0;
  1231. regBptr[3] = 0;
  1232. regBptr[4] = 0;
  1233. regBptr[5] = 0;
  1234. regBptr[6] = 0;
  1235. regBptr[7] = 0;
  1236. }
  1237. #else
  1238. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1239. #endif
  1240. l_bc++;
  1241. break;
  1242. // If the value in the register is negative, then set the register to 1, else to 0
  1243. case asBC_TS:
  1244. #if AS_SIZEOF_BOOL == 1
  1245. {
  1246. // Set the value to true if it is less than 0
  1247. // We need to use volatile here to tell the compiler it cannot
  1248. // change the order of read and write operations on valueRegister.
  1249. volatile int *regPtr = (int*)&regs.valueRegister;
  1250. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1251. asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1252. regBptr[0] = val; // The result is stored in the lower byte
  1253. regBptr[1] = 0; // Make sure the rest of the register is 0
  1254. regBptr[2] = 0;
  1255. regBptr[3] = 0;
  1256. regBptr[4] = 0;
  1257. regBptr[5] = 0;
  1258. regBptr[6] = 0;
  1259. regBptr[7] = 0;
  1260. }
  1261. #else
  1262. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1263. #endif
  1264. l_bc++;
  1265. break;
  1266. // If the value in the register is not negative, then set the register to 1, else to 0
  1267. case asBC_TNS:
  1268. #if AS_SIZEOF_BOOL == 1
  1269. {
  1270. // Set the value to true if it is not less than 0
  1271. // We need to use volatile here to tell the compiler it cannot
  1272. // change the order of read and write operations on valueRegister.
  1273. volatile int *regPtr = (int*)&regs.valueRegister;
  1274. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1275. asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1276. regBptr[0] = val; // The result is stored in the lower byte
  1277. regBptr[1] = 0; // Make sure the rest of the register is 0
  1278. regBptr[2] = 0;
  1279. regBptr[3] = 0;
  1280. regBptr[4] = 0;
  1281. regBptr[5] = 0;
  1282. regBptr[6] = 0;
  1283. regBptr[7] = 0;
  1284. }
  1285. #else
  1286. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1287. #endif
  1288. l_bc++;
  1289. break;
  1290. // If the value in the register is greater than 0, then set the register to 1, else to 0
  1291. case asBC_TP:
  1292. #if AS_SIZEOF_BOOL == 1
  1293. {
  1294. // Set the value to true if it is greater than 0
  1295. // We need to use volatile here to tell the compiler it cannot
  1296. // change the order of read and write operations on valueRegister.
  1297. volatile int *regPtr = (int*)&regs.valueRegister;
  1298. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1299. asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1300. regBptr[0] = val; // The result is stored in the lower byte
  1301. regBptr[1] = 0; // Make sure the rest of the register is 0
  1302. regBptr[2] = 0;
  1303. regBptr[3] = 0;
  1304. regBptr[4] = 0;
  1305. regBptr[5] = 0;
  1306. regBptr[6] = 0;
  1307. regBptr[7] = 0;
  1308. }
  1309. #else
  1310. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  1311. #endif
  1312. l_bc++;
  1313. break;
  1314. // If the value in the register is not greater than 0, then set the register to 1, else to 0
  1315. case asBC_TNP:
  1316. #if AS_SIZEOF_BOOL == 1
  1317. {
  1318. // Set the value to true if it is not greater than 0
  1319. // We need to use volatile here to tell the compiler it cannot
  1320. // change the order of read and write operations on valueRegister.
  1321. volatile int *regPtr = (int*)&regs.valueRegister;
  1322. volatile asBYTE *regBptr = (asBYTE*)&regs.valueRegister;
  1323. asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
  1324. regBptr[0] = val; // The result is stored in the lower byte
  1325. regBptr[1] = 0; // Make sure the rest of the register is 0
  1326. regBptr[2] = 0;
  1327. regBptr[3] = 0;
  1328. regBptr[4] = 0;
  1329. regBptr[5] = 0;
  1330. regBptr[6] = 0;
  1331. regBptr[7] = 0;
  1332. }
  1333. #else
  1334. *(int*)&regs.valueRegister = (*(int*)&regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
  1335. #endif
  1336. l_bc++;
  1337. break;
  1338. //--------------------
  1339. // negate value
  1340. // Negate the integer value in the variable
  1341. case asBC_NEGi:
  1342. *(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc))));
  1343. l_bc++;
  1344. break;
  1345. // Negate the float value in the variable
  1346. case asBC_NEGf:
  1347. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc));
  1348. l_bc++;
  1349. break;
  1350. // Negate the double value in the variable
  1351. case asBC_NEGd:
  1352. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc));
  1353. l_bc++;
  1354. break;
  1355. //-------------------------
  1356. // Increment value pointed to by address in register
  1357. // Increment the short value pointed to by the register
  1358. case asBC_INCi16:
  1359. (**(short**)&regs.valueRegister)++;
  1360. l_bc++;
  1361. break;
  1362. // Increment the byte value pointed to by the register
  1363. case asBC_INCi8:
  1364. (**(char**)&regs.valueRegister)++;
  1365. l_bc++;
  1366. break;
  1367. // Decrement the short value pointed to by the register
  1368. case asBC_DECi16:
  1369. (**(short**)&regs.valueRegister)--;
  1370. l_bc++;
  1371. break;
  1372. // Decrement the byte value pointed to by the register
  1373. case asBC_DECi8:
  1374. (**(char**)&regs.valueRegister)--;
  1375. l_bc++;
  1376. break;
  1377. // Increment the integer value pointed to by the register
  1378. case asBC_INCi:
  1379. ++(**(int**)&regs.valueRegister);
  1380. l_bc++;
  1381. break;
  1382. // Decrement the integer value pointed to by the register
  1383. case asBC_DECi:
  1384. --(**(int**)&regs.valueRegister);
  1385. l_bc++;
  1386. break;
  1387. // Increment the float value pointed to by the register
  1388. case asBC_INCf:
  1389. ++(**(float**)&regs.valueRegister);
  1390. l_bc++;
  1391. break;
  1392. // Decrement the float value pointed to by the register
  1393. case asBC_DECf:
  1394. --(**(float**)&regs.valueRegister);
  1395. l_bc++;
  1396. break;
  1397. // Increment the double value pointed to by the register
  1398. case asBC_INCd:
  1399. ++(**(double**)&regs.valueRegister);
  1400. l_bc++;
  1401. break;
  1402. // Decrement the double value pointed to by the register
  1403. case asBC_DECd:
  1404. --(**(double**)&regs.valueRegister);
  1405. l_bc++;
  1406. break;
  1407. // Increment the local integer variable
  1408. case asBC_IncVi:
  1409. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++;
  1410. l_bc++;
  1411. break;
  1412. // Decrement the local integer variable
  1413. case asBC_DecVi:
  1414. (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--;
  1415. l_bc++;
  1416. break;
  1417. //--------------------
  1418. // bits instructions
  1419. // Do a bitwise not on the value in the variable
  1420. case asBC_BNOT:
  1421. *(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc));
  1422. l_bc++;
  1423. break;
  1424. // Do a bitwise and of two variables and store the result in a third variable
  1425. case asBC_BAND:
  1426. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc));
  1427. l_bc += 2;
  1428. break;
  1429. // Do a bitwise or of two variables and store the result in a third variable
  1430. case asBC_BOR:
  1431. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc));
  1432. l_bc += 2;
  1433. break;
  1434. // Do a bitwise xor of two variables and store the result in a third variable
  1435. case asBC_BXOR:
  1436. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc));
  1437. l_bc += 2;
  1438. break;
  1439. // Do a logical shift left of two variables and store the result in a third variable
  1440. case asBC_BSLL:
  1441. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  1442. l_bc += 2;
  1443. break;
  1444. // Do a logical shift right of two variables and store the result in a third variable
  1445. case asBC_BSRL:
  1446. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1447. l_bc += 2;
  1448. break;
  1449. // Do an arithmetic shift right of two variables and store the result in a third variable
  1450. case asBC_BSRA:
  1451. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc));
  1452. l_bc += 2;
  1453. break;
  1454. case asBC_COPY:
  1455. {
  1456. void *d = (void*)*(size_t*)l_sp; l_sp += AS_PTR_SIZE;
  1457. void *s = (void*)*(size_t*)l_sp;
  1458. if( s == 0 || d == 0 )
  1459. {
  1460. // Need to move the values back to the context
  1461. regs.programPointer = l_bc;
  1462. regs.stackPointer = l_sp;
  1463. regs.stackFramePointer = l_fp;
  1464. // Raise exception
  1465. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1466. return;
  1467. }
  1468. memcpy(d, s, asBC_WORDARG0(l_bc)*4);
  1469. // replace the pointer on the stack with the lvalue
  1470. *(size_t**)l_sp = (size_t*)d;
  1471. }
  1472. l_bc++;
  1473. break;
  1474. case asBC_PshC8:
  1475. l_sp -= 2;
  1476. *(asQWORD*)l_sp = asBC_QWORDARG(l_bc);
  1477. l_bc += 3;
  1478. break;
  1479. case asBC_RDS8:
  1480. #ifndef AS_64BIT_PTR
  1481. *(asQWORD*)(l_sp-1) = *(asQWORD*)*(size_t*)l_sp;
  1482. --l_sp;
  1483. #else
  1484. *(asQWORD*)l_sp = *(asQWORD*)*(size_t*)l_sp;
  1485. #endif
  1486. l_bc++;
  1487. break;
  1488. case asBC_SWAP8:
  1489. {
  1490. asQWORD q = *(asQWORD*)l_sp;
  1491. *(asQWORD*)l_sp = *(asQWORD*)(l_sp+2);
  1492. *(asQWORD*)(l_sp+2) = q;
  1493. l_bc++;
  1494. }
  1495. break;
  1496. //----------------------------
  1497. // Comparisons
  1498. case asBC_CMPd:
  1499. {
  1500. double dbl = *(double*)(l_fp - asBC_SWORDARG0(l_bc)) - *(double*)(l_fp - asBC_SWORDARG1(l_bc));
  1501. if( dbl == 0 ) *(int*)&regs.valueRegister = 0;
  1502. else if( dbl < 0 ) *(int*)&regs.valueRegister = -1;
  1503. else *(int*)&regs.valueRegister = 1;
  1504. l_bc += 2;
  1505. }
  1506. break;
  1507. case asBC_CMPu:
  1508. {
  1509. asDWORD d = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1510. asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  1511. if( d == d2 ) *(int*)&regs.valueRegister = 0;
  1512. else if( d < d2 ) *(int*)&regs.valueRegister = -1;
  1513. else *(int*)&regs.valueRegister = 1;
  1514. l_bc += 2;
  1515. }
  1516. break;
  1517. case asBC_CMPf:
  1518. {
  1519. float f = *(float*)(l_fp - asBC_SWORDARG0(l_bc)) - *(float*)(l_fp - asBC_SWORDARG1(l_bc));
  1520. if( f == 0 ) *(int*)&regs.valueRegister = 0;
  1521. else if( f < 0 ) *(int*)&regs.valueRegister = -1;
  1522. else *(int*)&regs.valueRegister = 1;
  1523. l_bc += 2;
  1524. }
  1525. break;
  1526. case asBC_CMPi:
  1527. {
  1528. int i = *(int*)(l_fp - asBC_SWORDARG0(l_bc)) - *(int*)(l_fp - asBC_SWORDARG1(l_bc));
  1529. if( i == 0 ) *(int*)&regs.valueRegister = 0;
  1530. else if( i < 0 ) *(int*)&regs.valueRegister = -1;
  1531. else *(int*)&regs.valueRegister = 1;
  1532. l_bc += 2;
  1533. }
  1534. break;
  1535. //----------------------------
  1536. // Comparisons with constant value
  1537. case asBC_CMPIi:
  1538. {
  1539. int i = *(int*)(l_fp - asBC_SWORDARG0(l_bc)) - asBC_INTARG(l_bc);
  1540. if( i == 0 ) *(int*)&regs.valueRegister = 0;
  1541. else if( i < 0 ) *(int*)&regs.valueRegister = -1;
  1542. else *(int*)&regs.valueRegister = 1;
  1543. l_bc += 2;
  1544. }
  1545. break;
  1546. case asBC_CMPIf:
  1547. {
  1548. float f = *(float*)(l_fp - asBC_SWORDARG0(l_bc)) - asBC_FLOATARG(l_bc);
  1549. if( f == 0 ) *(int*)&regs.valueRegister = 0;
  1550. else if( f < 0 ) *(int*)&regs.valueRegister = -1;
  1551. else *(int*)&regs.valueRegister = 1;
  1552. l_bc += 2;
  1553. }
  1554. break;
  1555. case asBC_CMPIu:
  1556. {
  1557. asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1558. asDWORD d2 = asBC_DWORDARG(l_bc);
  1559. if( d1 == d2 ) *(int*)&regs.valueRegister = 0;
  1560. else if( d1 < d2 ) *(int*)&regs.valueRegister = -1;
  1561. else *(int*)&regs.valueRegister = 1;
  1562. l_bc += 2;
  1563. }
  1564. break;
  1565. case asBC_JMPP:
  1566. l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2;
  1567. break;
  1568. case asBC_PopRPtr:
  1569. *(asPTRWORD*)&regs.valueRegister = *(asPTRWORD*)l_sp;
  1570. l_sp += AS_PTR_SIZE;
  1571. l_bc++;
  1572. break;
  1573. case asBC_PshRPtr:
  1574. l_sp -= AS_PTR_SIZE;
  1575. *(asPTRWORD*)l_sp = *(asPTRWORD*)&regs.valueRegister;
  1576. l_bc++;
  1577. break;
  1578. case asBC_STR:
  1579. {
  1580. // Get the string id from the argument
  1581. asWORD w = asBC_WORDARG0(l_bc);
  1582. // Push the string pointer on the stack
  1583. const asCString &b = engine->GetConstantString(w);
  1584. l_sp -= AS_PTR_SIZE;
  1585. *(asPTRWORD*)l_sp = (asPTRWORD)(size_t)b.AddressOf();
  1586. // Push the string length on the stack
  1587. --l_sp;
  1588. *l_sp = (asDWORD)b.GetLength();
  1589. l_bc++;
  1590. }
  1591. break;
  1592. case asBC_CALLSYS:
  1593. {
  1594. // Get function ID from the argument
  1595. int i = asBC_INTARG(l_bc);
  1596. // Need to move the values back to the context as the called functions
  1597. // may use the debug interface to inspect the registers
  1598. regs.programPointer = l_bc;
  1599. regs.stackPointer = l_sp;
  1600. regs.stackFramePointer = l_fp;
  1601. l_sp += CallSystemFunction(i, this, 0);
  1602. // Update the program position after the call so that line number is correct
  1603. l_bc += 2;
  1604. if( regs.doProcessSuspend )
  1605. {
  1606. // Should the execution be suspended?
  1607. if( doSuspend )
  1608. {
  1609. regs.programPointer = l_bc;
  1610. regs.stackPointer = l_sp;
  1611. regs.stackFramePointer = l_fp;
  1612. status = asEXECUTION_SUSPENDED;
  1613. return;
  1614. }
  1615. // An exception might have been raised
  1616. if( status != asEXECUTION_ACTIVE )
  1617. {
  1618. regs.programPointer = l_bc;
  1619. regs.stackPointer = l_sp;
  1620. regs.stackFramePointer = l_fp;
  1621. return;
  1622. }
  1623. }
  1624. }
  1625. break;
  1626. case asBC_CALLBND:
  1627. {
  1628. // Get the function ID from the stack
  1629. int i = asBC_INTARG(l_bc);
  1630. l_bc += 2;
  1631. asASSERT( i >= 0 );
  1632. asASSERT( i & FUNC_IMPORTED );
  1633. // Need to move the values back to the context
  1634. regs.programPointer = l_bc;
  1635. regs.stackPointer = l_sp;
  1636. regs.stackFramePointer = l_fp;
  1637. int funcID = engine->importedFunctions[i&0xFFFF]->boundFunctionId;
  1638. if( funcID == -1 )
  1639. {
  1640. SetInternalException(TXT_UNBOUND_FUNCTION);
  1641. return;
  1642. }
  1643. else
  1644. {
  1645. asCScriptFunction *func = engine->GetScriptFunction(funcID);
  1646. CallScriptFunction(func);
  1647. }
  1648. // Extract the values from the context again
  1649. l_bc = regs.programPointer;
  1650. l_sp = regs.stackPointer;
  1651. l_fp = regs.stackFramePointer;
  1652. // If status isn't active anymore then we must stop
  1653. if( status != asEXECUTION_ACTIVE )
  1654. return;
  1655. }
  1656. break;
  1657. case asBC_SUSPEND:
  1658. if( regs.doProcessSuspend )
  1659. {
  1660. if( lineCallback )
  1661. {
  1662. regs.programPointer = l_bc;
  1663. regs.stackPointer = l_sp;
  1664. regs.stackFramePointer = l_fp;
  1665. CallLineCallback();
  1666. }
  1667. if( doSuspend )
  1668. {
  1669. l_bc++;
  1670. // Need to move the values back to the context
  1671. regs.programPointer = l_bc;
  1672. regs.stackPointer = l_sp;
  1673. regs.stackFramePointer = l_fp;
  1674. status = asEXECUTION_SUSPENDED;
  1675. return;
  1676. }
  1677. }
  1678. l_bc++;
  1679. break;
  1680. case asBC_ALLOC:
  1681. {
  1682. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(l_bc);
  1683. int func = asBC_INTARG(l_bc+AS_PTR_SIZE);
  1684. if( objType->flags & asOBJ_SCRIPT_OBJECT )
  1685. {
  1686. // Pre-allocate the memory
  1687. asDWORD *mem = (asDWORD*)engine->CallAlloc(objType);
  1688. // Pre-initialize the memory by calling the constructor for asCScriptObject
  1689. ScriptObject_Construct(objType, (asCScriptObject*)mem);
  1690. // Call the constructor to initalize the memory
  1691. asCScriptFunction *f = engine->scriptFunctions[func];
  1692. asDWORD **a = (asDWORD**)*(size_t*)(l_sp + f->GetSpaceNeededForArguments());
  1693. if( a ) *a = mem;
  1694. // Push the object pointer on the stack
  1695. l_sp -= AS_PTR_SIZE;
  1696. *(size_t*)l_sp = (size_t)mem;
  1697. l_bc += 2+AS_PTR_SIZE;
  1698. // Need to move the values back to the context
  1699. regs.programPointer = l_bc;
  1700. regs.stackPointer = l_sp;
  1701. regs.stackFramePointer = l_fp;
  1702. CallScriptFunction(f);
  1703. // Extract the values from the context again
  1704. l_bc = regs.programPointer;
  1705. l_sp = regs.stackPointer;
  1706. l_fp = regs.stackFramePointer;
  1707. // If status isn't active anymore then we must stop
  1708. if( status != asEXECUTION_ACTIVE )
  1709. return;
  1710. }
  1711. else
  1712. {
  1713. // Pre-allocate the memory
  1714. asDWORD *mem = (asDWORD*)engine->CallAlloc(objType);
  1715. if( func )
  1716. {
  1717. // Need to move the values back to the context as the called functions
  1718. // may use the debug interface to inspect the registers
  1719. regs.programPointer = l_bc;
  1720. regs.stackPointer = l_sp;
  1721. regs.stackFramePointer = l_fp;
  1722. l_sp += CallSystemFunction(func, this, mem);
  1723. }
  1724. // Pop the variable address from the stack
  1725. asDWORD **a = (asDWORD**)*(size_t*)l_sp;
  1726. l_sp += AS_PTR_SIZE;
  1727. if( a ) *a = mem;
  1728. l_bc += 2+AS_PTR_SIZE;
  1729. if( regs.doProcessSuspend )
  1730. {
  1731. // Should the execution be suspended?
  1732. if( doSuspend )
  1733. {
  1734. regs.programPointer = l_bc;
  1735. regs.stackPointer = l_sp;
  1736. regs.stackFramePointer = l_fp;
  1737. status = asEXECUTION_SUSPENDED;
  1738. return;
  1739. }
  1740. // An exception might have been raised
  1741. if( status != asEXECUTION_ACTIVE )
  1742. {
  1743. regs.programPointer = l_bc;
  1744. regs.stackPointer = l_sp;
  1745. regs.stackFramePointer = l_fp;
  1746. engine->CallFree(mem);
  1747. *a = 0;
  1748. return;
  1749. }
  1750. }
  1751. }
  1752. }
  1753. break;
  1754. case asBC_FREE:
  1755. {
  1756. asDWORD **a = (asDWORD**)*(size_t*)l_sp;
  1757. l_sp += AS_PTR_SIZE;
  1758. if( a && *a )
  1759. {
  1760. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(l_bc);
  1761. asSTypeBehaviour *beh = &objType->beh;
  1762. // Need to move the values back to the context as the called functions
  1763. // may use the debug interface to inspect the registers
  1764. regs.programPointer = l_bc;
  1765. regs.stackPointer = l_sp;
  1766. regs.stackFramePointer = l_fp;
  1767. if( beh->release )
  1768. {
  1769. engine->CallObjectMethod(*a, beh->release);
  1770. }
  1771. else
  1772. {
  1773. if( beh->destruct )
  1774. {
  1775. engine->CallObjectMethod(*a, beh->destruct);
  1776. }
  1777. engine->CallFree(*a);
  1778. }
  1779. // Clear the variable
  1780. *a = 0;
  1781. }
  1782. }
  1783. l_bc += 1+AS_PTR_SIZE;
  1784. break;
  1785. case asBC_LOADOBJ:
  1786. {
  1787. // Move the object pointer from the object variable into the object register
  1788. void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc));
  1789. regs.objectType = 0;
  1790. regs.objectRegister = *a;
  1791. *a = 0;
  1792. }
  1793. l_bc++;
  1794. break;
  1795. case asBC_STOREOBJ:
  1796. // Move the object pointer from the object register to the object variable
  1797. *(size_t*)(l_fp - asBC_SWORDARG0(l_bc)) = size_t(regs.objectRegister);
  1798. regs.objectRegister = 0;
  1799. l_bc++;
  1800. break;
  1801. case asBC_GETOBJ:
  1802. {
  1803. // Read variable index from location on stack
  1804. size_t *a = (size_t*)(l_sp + asBC_WORDARG0(l_bc));
  1805. asDWORD offset = *(asDWORD*)a;
  1806. // Move pointer from variable to the same location on the stack
  1807. size_t *v = (size_t*)(l_fp - offset);
  1808. *a = *v;
  1809. // Clear variable
  1810. *v = 0;
  1811. }
  1812. l_bc++;
  1813. break;
  1814. case asBC_REFCPY:
  1815. {
  1816. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(l_bc);
  1817. asSTypeBehaviour *beh = &objType->beh;
  1818. // Pop address of destination pointer from the stack
  1819. void **d = (void**)*(size_t*)l_sp;
  1820. l_sp += AS_PTR_SIZE;
  1821. // Read wanted pointer from the stack
  1822. void *s = (void*)*(size_t*)l_sp;
  1823. // Need to move the values back to the context as the called functions
  1824. // may use the debug interface to inspect the registers
  1825. regs.programPointer = l_bc;
  1826. regs.stackPointer = l_sp;
  1827. regs.stackFramePointer = l_fp;
  1828. // Release previous object held by destination pointer
  1829. if( *d != 0 )
  1830. engine->CallObjectMethod(*d, beh->release);
  1831. // Increase ref counter of wanted object
  1832. if( s != 0 )
  1833. engine->CallObjectMethod(s, beh->addref);
  1834. // Set the new object in the destination
  1835. *d = s;
  1836. }
  1837. l_bc += 1+AS_PTR_SIZE;
  1838. break;
  1839. case asBC_CHKREF:
  1840. {
  1841. // Verify if the pointer on the stack is null
  1842. // This is used when validating a pointer that an operator will work on
  1843. size_t a = *(size_t*)l_sp;
  1844. if( a == 0 )
  1845. {
  1846. regs.programPointer = l_bc;
  1847. regs.stackPointer = l_sp;
  1848. regs.stackFramePointer = l_fp;
  1849. SetInternalException(TXT_NULL_POINTER_ACCESS);
  1850. return;
  1851. }
  1852. }
  1853. l_bc++;
  1854. break;
  1855. case asBC_GETOBJREF:
  1856. {
  1857. // Get the location on the stack where the reference will be placed
  1858. size_t *a = (size_t*)(l_sp + asBC_WORDARG0(l_bc));
  1859. // Replace the variable index with the object handle held in the variable
  1860. *(size_t**)a = *(size_t**)(l_fp - *a);
  1861. }
  1862. l_bc++;
  1863. break;
  1864. case asBC_GETREF:
  1865. {
  1866. // Get the location on the stack where the reference will be placed
  1867. size_t *a = (size_t*)(l_sp + asBC_WORDARG0(l_bc));
  1868. // Replace the variable index with the address of the variable
  1869. *(size_t**)a = (size_t*)(l_fp - (int)*a);
  1870. }
  1871. l_bc++;
  1872. break;
  1873. case asBC_SWAP48:
  1874. {
  1875. asDWORD d = *(asDWORD*)l_sp;
  1876. asQWORD q = *(asQWORD*)(l_sp+1);
  1877. *(asQWORD*)l_sp = q;
  1878. *(asDWORD*)(l_sp+2) = d;
  1879. l_bc++;
  1880. }
  1881. break;
  1882. case asBC_SWAP84:
  1883. {
  1884. asQWORD q = *(asQWORD*)l_sp;
  1885. asDWORD d = *(asDWORD*)(l_sp+2);
  1886. *(asDWORD*)l_sp = d;
  1887. *(asQWORD*)(l_sp+1) = q;
  1888. l_bc++;
  1889. }
  1890. break;
  1891. case asBC_OBJTYPE:
  1892. l_sp -= AS_PTR_SIZE;
  1893. *(asPTRWORD*)l_sp = asBC_PTRARG(l_bc);
  1894. l_bc += 1+AS_PTR_SIZE;
  1895. break;
  1896. case asBC_TYPEID:
  1897. // Equivalent to PshC4, but kept as separate instruction for bytecode serialization
  1898. --l_sp;
  1899. *l_sp = asBC_DWORDARG(l_bc);
  1900. l_bc += 2;
  1901. break;
  1902. case asBC_SetV4:
  1903. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  1904. l_bc += 2;
  1905. break;
  1906. case asBC_SetV8:
  1907. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc);
  1908. l_bc += 3;
  1909. break;
  1910. case asBC_ADDSi:
  1911. *(size_t*)l_sp = size_t(asPTRWORD(*(size_t*)l_sp) + asBC_INTARG(l_bc));
  1912. l_bc += 2;
  1913. break;
  1914. case asBC_CpyVtoV4:
  1915. *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc));
  1916. l_bc += 2;
  1917. break;
  1918. case asBC_CpyVtoV8:
  1919. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  1920. l_bc += 2;
  1921. break;
  1922. case asBC_CpyVtoR4:
  1923. *(asDWORD*)&regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1924. l_bc++;
  1925. break;
  1926. case asBC_CpyVtoR8:
  1927. *(asQWORD*)&regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1928. l_bc++;
  1929. break;
  1930. case asBC_CpyVtoG4:
  1931. // TODO: global: The global var address should be stored in the instruction directly
  1932. *(asDWORD*)regs.globalVarPointers[asBC_WORDARG0(l_bc)] = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  1933. l_bc += 2;
  1934. break;
  1935. case asBC_CpyRtoV4:
  1936. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&regs.valueRegister;
  1937. l_bc++;
  1938. break;
  1939. case asBC_CpyRtoV8:
  1940. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = regs.valueRegister;
  1941. l_bc++;
  1942. break;
  1943. case asBC_CpyGtoV4:
  1944. // TODO: global: The global var address should be stored in the instruction directly
  1945. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)regs.globalVarPointers[asBC_WORDARG1(l_bc)];
  1946. l_bc += 2;
  1947. break;
  1948. case asBC_WRTV1:
  1949. // The pointer in the register points to a byte, and *(l_fp - offset) too
  1950. **(asBYTE**)&regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  1951. l_bc++;
  1952. break;
  1953. case asBC_WRTV2:
  1954. // The pointer in the register points to a word, and *(l_fp - offset) too
  1955. **(asWORD**)&regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1956. l_bc++;
  1957. break;
  1958. case asBC_WRTV4:
  1959. **(asDWORD**)&regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc));
  1960. l_bc++;
  1961. break;
  1962. case asBC_WRTV8:
  1963. **(asQWORD**)&regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1964. l_bc++;
  1965. break;
  1966. case asBC_RDR1:
  1967. {
  1968. // The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte
  1969. asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  1970. bPtr[0] = **(asBYTE**)&regs.valueRegister; // read the byte
  1971. bPtr[1] = 0; // 0 the rest of the DWORD
  1972. bPtr[2] = 0;
  1973. bPtr[3] = 0;
  1974. }
  1975. l_bc++;
  1976. break;
  1977. case asBC_RDR2:
  1978. {
  1979. // The pointer in the register points to a word, and *(l_fp - offset) will also point to a word
  1980. asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  1981. wPtr[0] = **(asWORD**)&regs.valueRegister; // read the word
  1982. wPtr[1] = 0; // 0 the rest of the DWORD
  1983. }
  1984. l_bc++;
  1985. break;
  1986. case asBC_RDR4:
  1987. *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&regs.valueRegister;
  1988. l_bc++;
  1989. break;
  1990. case asBC_RDR8:
  1991. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&regs.valueRegister;
  1992. l_bc++;
  1993. break;
  1994. case asBC_LDG:
  1995. // TODO: global: The global var address should be stored in the instruction directly
  1996. *(asDWORD**)&regs.valueRegister = (asDWORD*)regs.globalVarPointers[asBC_WORDARG0(l_bc)];
  1997. l_bc++;
  1998. break;
  1999. case asBC_LDV:
  2000. *(asDWORD**)&regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc));
  2001. l_bc++;
  2002. break;
  2003. case asBC_PGA:
  2004. l_sp -= AS_PTR_SIZE;
  2005. // TODO: global: The global var address should be stored in the instruction directly
  2006. *(asPTRWORD*)l_sp = (asPTRWORD)(size_t)regs.globalVarPointers[asBC_WORDARG0(l_bc)];
  2007. l_bc++;
  2008. break;
  2009. case asBC_RDS4:
  2010. #ifndef AS_64BIT_PTR
  2011. *l_sp = *(asDWORD*)*(size_t*)l_sp;
  2012. #else
  2013. {
  2014. asDWORD d = *(asDWORD*)*(size_t*)l_sp;
  2015. l_sp++;
  2016. *l_sp = d;
  2017. }
  2018. #endif
  2019. l_bc++;
  2020. break;
  2021. case asBC_VAR:
  2022. l_sp -= AS_PTR_SIZE;
  2023. *(size_t*)l_sp = (size_t)asBC_SWORDARG0(l_bc);
  2024. l_bc++;
  2025. break;
  2026. //----------------------------
  2027. // Type conversions
  2028. case asBC_iTOf:
  2029. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc)));
  2030. l_bc++;
  2031. break;
  2032. case asBC_fTOi:
  2033. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)));
  2034. l_bc++;
  2035. break;
  2036. case asBC_uTOf:
  2037. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc)));
  2038. l_bc++;
  2039. break;
  2040. case asBC_fTOu:
  2041. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2042. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))));
  2043. l_bc++;
  2044. break;
  2045. case asBC_sbTOi:
  2046. // *(l_fp - offset) points to a char, and will point to an int afterwards
  2047. *(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc));
  2048. l_bc++;
  2049. break;
  2050. case asBC_swTOi:
  2051. // *(l_fp - offset) points to a short, and will point to an int afterwards
  2052. *(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc));
  2053. l_bc++;
  2054. break;
  2055. case asBC_ubTOi:
  2056. // (l_fp - offset) points to a byte, and will point to an int afterwards
  2057. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2058. l_bc++;
  2059. break;
  2060. case asBC_uwTOi:
  2061. // *(l_fp - offset) points to a word, and will point to an int afterwards
  2062. *(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2063. l_bc++;
  2064. break;
  2065. case asBC_dTOi:
  2066. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2067. l_bc += 2;
  2068. break;
  2069. case asBC_dTOu:
  2070. // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
  2071. *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))));
  2072. l_bc += 2;
  2073. break;
  2074. case asBC_dTOf:
  2075. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
  2076. l_bc += 2;
  2077. break;
  2078. case asBC_iTOd:
  2079. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2080. l_bc += 2;
  2081. break;
  2082. case asBC_uTOd:
  2083. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2084. l_bc += 2;
  2085. break;
  2086. case asBC_fTOd:
  2087. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2088. l_bc += 2;
  2089. break;
  2090. //------------------------------
  2091. // Math operations
  2092. case asBC_ADDi:
  2093. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2094. l_bc += 2;
  2095. break;
  2096. case asBC_SUBi:
  2097. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2098. l_bc += 2;
  2099. break;
  2100. case asBC_MULi:
  2101. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2102. l_bc += 2;
  2103. break;
  2104. case asBC_DIVi:
  2105. {
  2106. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2107. if( divider == 0 )
  2108. {
  2109. // Need to move the values back to the context
  2110. regs.programPointer = l_bc;
  2111. regs.stackPointer = l_sp;
  2112. regs.stackFramePointer = l_fp;
  2113. // Raise exception
  2114. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2115. return;
  2116. }
  2117. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2118. }
  2119. l_bc += 2;
  2120. break;
  2121. case asBC_MODi:
  2122. {
  2123. int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
  2124. if( divider == 0 )
  2125. {
  2126. // Need to move the values back to the context
  2127. regs.programPointer = l_bc;
  2128. regs.stackPointer = l_sp;
  2129. regs.stackFramePointer = l_fp;
  2130. // Raise exception
  2131. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2132. return;
  2133. }
  2134. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  2135. }
  2136. l_bc += 2;
  2137. break;
  2138. case asBC_ADDf:
  2139. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2140. l_bc += 2;
  2141. break;
  2142. case asBC_SUBf:
  2143. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2144. l_bc += 2;
  2145. break;
  2146. case asBC_MULf:
  2147. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2148. l_bc += 2;
  2149. break;
  2150. case asBC_DIVf:
  2151. {
  2152. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2153. if( divider == 0 )
  2154. {
  2155. // Need to move the values back to the context
  2156. regs.programPointer = l_bc;
  2157. regs.stackPointer = l_sp;
  2158. regs.stackFramePointer = l_fp;
  2159. // Raise exception
  2160. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2161. return;
  2162. }
  2163. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2164. }
  2165. l_bc += 2;
  2166. break;
  2167. case asBC_MODf:
  2168. {
  2169. float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
  2170. if( divider == 0 )
  2171. {
  2172. // Need to move the values back to the context
  2173. regs.programPointer = l_bc;
  2174. regs.stackPointer = l_sp;
  2175. regs.stackFramePointer = l_fp;
  2176. // Raise exception
  2177. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2178. return;
  2179. }
  2180. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2181. }
  2182. l_bc += 2;
  2183. break;
  2184. case asBC_ADDd:
  2185. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2186. l_bc += 2;
  2187. break;
  2188. case asBC_SUBd:
  2189. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2190. l_bc += 2;
  2191. break;
  2192. case asBC_MULd:
  2193. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2194. l_bc += 2;
  2195. break;
  2196. case asBC_DIVd:
  2197. {
  2198. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2199. if( divider == 0 )
  2200. {
  2201. // Need to move the values back to the context
  2202. regs.programPointer = l_bc;
  2203. regs.stackPointer = l_sp;
  2204. regs.stackFramePointer = l_fp;
  2205. // Raise exception
  2206. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2207. return;
  2208. }
  2209. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2210. l_bc += 2;
  2211. }
  2212. break;
  2213. case asBC_MODd:
  2214. {
  2215. double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
  2216. if( divider == 0 )
  2217. {
  2218. // Need to move the values back to the context
  2219. regs.programPointer = l_bc;
  2220. regs.stackPointer = l_sp;
  2221. regs.stackFramePointer = l_fp;
  2222. // Raise exception
  2223. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2224. return;
  2225. }
  2226. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
  2227. l_bc += 2;
  2228. }
  2229. break;
  2230. //------------------------------
  2231. // Math operations with constant value
  2232. case asBC_ADDIi:
  2233. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1);
  2234. l_bc += 3;
  2235. break;
  2236. case asBC_SUBIi:
  2237. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1);
  2238. l_bc += 3;
  2239. break;
  2240. case asBC_MULIi:
  2241. *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1);
  2242. l_bc += 3;
  2243. break;
  2244. case asBC_ADDIf:
  2245. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1);
  2246. l_bc += 3;
  2247. break;
  2248. case asBC_SUBIf:
  2249. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1);
  2250. l_bc += 3;
  2251. break;
  2252. case asBC_MULIf:
  2253. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1);
  2254. l_bc += 3;
  2255. break;
  2256. //-----------------------------------
  2257. case asBC_SetG4:
  2258. // TODO: global: The global var address should be stored in the instruction directly
  2259. *(asDWORD*)regs.globalVarPointers[asBC_WORDARG0(l_bc)] = asBC_DWORDARG(l_bc);
  2260. l_bc += 2;
  2261. break;
  2262. case asBC_ChkRefS:
  2263. {
  2264. // Verify if the pointer on the stack refers to a non-null value
  2265. // This is used to validate a reference to a handle
  2266. asDWORD *a = (asDWORD*)*(size_t*)l_sp;
  2267. if( *a == 0 )
  2268. {
  2269. regs.programPointer = l_bc;
  2270. regs.stackPointer = l_sp;
  2271. regs.stackFramePointer = l_fp;
  2272. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2273. return;
  2274. }
  2275. }
  2276. l_bc++;
  2277. break;
  2278. case asBC_ChkNullV:
  2279. {
  2280. // Verify if variable (on the stack) is not null
  2281. asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc));
  2282. if( a == 0 )
  2283. {
  2284. regs.programPointer = l_bc;
  2285. regs.stackPointer = l_sp;
  2286. regs.stackFramePointer = l_fp;
  2287. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2288. return;
  2289. }
  2290. }
  2291. l_bc++;
  2292. break;
  2293. case asBC_CALLINTF:
  2294. {
  2295. int i = asBC_INTARG(l_bc);
  2296. l_bc += 2;
  2297. asASSERT( i >= 0 );
  2298. asASSERT( (i & FUNC_IMPORTED) == 0 );
  2299. // Need to move the values back to the context
  2300. regs.programPointer = l_bc;
  2301. regs.stackPointer = l_sp;
  2302. regs.stackFramePointer = l_fp;
  2303. CallInterfaceMethod(engine->GetScriptFunction(i));
  2304. // Extract the values from the context again
  2305. l_bc = regs.programPointer;
  2306. l_sp = regs.stackPointer;
  2307. l_fp = regs.stackFramePointer;
  2308. // If status isn't active anymore then we must stop
  2309. if( status != asEXECUTION_ACTIVE )
  2310. return;
  2311. }
  2312. break;
  2313. case asBC_iTOb:
  2314. {
  2315. // *(l_fp - offset) points to an int, and will point to a byte afterwards
  2316. // We need to use volatile here to tell the compiler not to rearrange
  2317. // read and write operations during optimizations.
  2318. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2319. volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
  2320. bPtr[0] = (asBYTE)val; // write the byte
  2321. bPtr[1] = 0; // 0 the rest of the DWORD
  2322. bPtr[2] = 0;
  2323. bPtr[3] = 0;
  2324. }
  2325. l_bc++;
  2326. break;
  2327. case asBC_iTOw:
  2328. {
  2329. // *(l_fp - offset) points to an int, and will point to word afterwards
  2330. // We need to use volatile here to tell the compiler not to rearrange
  2331. // read and write operations during optimizations.
  2332. volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc));
  2333. volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2334. wPtr[0] = (asWORD)val; // write the word
  2335. wPtr[1] = 0; // 0 the rest of the DWORD
  2336. }
  2337. l_bc++;
  2338. break;
  2339. case asBC_SetV1:
  2340. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2341. // when the bytecode instructions were more tightly packed. It can now
  2342. // be removed. When removing it, make sure the value is correctly converted
  2343. // on big-endian CPUs.
  2344. // The byte is already stored correctly in the argument
  2345. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2346. l_bc += 2;
  2347. break;
  2348. case asBC_SetV2:
  2349. // TODO: This is exactly the same as SetV4. This is a left over from the time
  2350. // when the bytecode instructions were more tightly packed. It can now
  2351. // be removed. When removing it, make sure the value is correctly converted
  2352. // on big-endian CPUs.
  2353. // The word is already stored correctly in the argument
  2354. *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
  2355. l_bc += 2;
  2356. break;
  2357. case asBC_Cast:
  2358. // Cast the handle at the top of the stack to the type in the argument
  2359. {
  2360. asDWORD **a = (asDWORD**)*(size_t*)l_sp;
  2361. if( a && *a )
  2362. {
  2363. asDWORD typeId = asBC_DWORDARG(l_bc);
  2364. asCScriptObject *obj = (asCScriptObject *)* a;
  2365. asCObjectType *objType = obj->objType;
  2366. asCObjectType *to = engine->GetObjectTypeFromTypeId(typeId);
  2367. // This instruction can only be used with script classes and interfaces
  2368. asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT );
  2369. asASSERT( to->flags & asOBJ_SCRIPT_OBJECT );
  2370. if( objType->Implements(to) || objType->DerivesFrom(to) )
  2371. {
  2372. regs.objectType = 0;
  2373. regs.objectRegister = obj;
  2374. obj->AddRef();
  2375. }
  2376. else
  2377. {
  2378. // The object register should already be null, so there
  2379. // is no need to clear it if the cast is unsuccessful
  2380. asASSERT( regs.objectRegister == 0 );
  2381. }
  2382. }
  2383. l_sp += AS_PTR_SIZE;
  2384. }
  2385. l_bc += 2;
  2386. break;
  2387. case asBC_i64TOi:
  2388. *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  2389. l_bc += 2;
  2390. break;
  2391. case asBC_uTOi64:
  2392. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
  2393. l_bc += 2;
  2394. break;
  2395. case asBC_iTOi64:
  2396. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
  2397. l_bc += 2;
  2398. break;
  2399. case asBC_fTOi64:
  2400. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
  2401. l_bc += 2;
  2402. break;
  2403. case asBC_dTOi64:
  2404. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)));
  2405. l_bc++;
  2406. break;
  2407. case asBC_fTOu64:
  2408. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))));
  2409. l_bc += 2;
  2410. break;
  2411. case asBC_dTOu64:
  2412. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))));
  2413. l_bc++;
  2414. break;
  2415. case asBC_i64TOf:
  2416. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
  2417. l_bc += 2;
  2418. break;
  2419. case asBC_u64TOf:
  2420. #if _MSC_VER <= 1200 // MSVC6
  2421. {
  2422. // MSVC6 doesn't permit UINT64 to double
  2423. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  2424. if( v < 0 )
  2425. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v);
  2426. else
  2427. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v);
  2428. }
  2429. #else
  2430. *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)));
  2431. #endif
  2432. l_bc += 2;
  2433. break;
  2434. case asBC_i64TOd:
  2435. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)));
  2436. l_bc++;
  2437. break;
  2438. case asBC_u64TOd:
  2439. #if _MSC_VER <= 1200 // MSVC6
  2440. {
  2441. // MSVC6 doesn't permit UINT64 to double
  2442. asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  2443. if( v < 0 )
  2444. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v);
  2445. else
  2446. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v);
  2447. }
  2448. #else
  2449. *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)));
  2450. #endif
  2451. l_bc++;
  2452. break;
  2453. case asBC_NEGi64:
  2454. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
  2455. l_bc++;
  2456. break;
  2457. case asBC_INCi64:
  2458. ++(**(asQWORD**)&regs.valueRegister);
  2459. l_bc++;
  2460. break;
  2461. case asBC_DECi64:
  2462. --(**(asQWORD**)&regs.valueRegister);
  2463. l_bc++;
  2464. break;
  2465. case asBC_BNOT64:
  2466. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2467. l_bc++;
  2468. break;
  2469. case asBC_ADDi64:
  2470. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2471. l_bc += 2;
  2472. break;
  2473. case asBC_SUBi64:
  2474. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2475. l_bc += 2;
  2476. break;
  2477. case asBC_MULi64:
  2478. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2479. l_bc += 2;
  2480. break;
  2481. case asBC_DIVi64:
  2482. {
  2483. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2484. if( divider == 0 )
  2485. {
  2486. // Need to move the values back to the context
  2487. regs.programPointer = l_bc;
  2488. regs.stackPointer = l_sp;
  2489. regs.stackFramePointer = l_fp;
  2490. // Raise exception
  2491. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2492. return;
  2493. }
  2494. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
  2495. }
  2496. l_bc += 2;
  2497. break;
  2498. case asBC_MODi64:
  2499. {
  2500. asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2501. if( divider == 0 )
  2502. {
  2503. // Need to move the values back to the context
  2504. regs.programPointer = l_bc;
  2505. regs.stackPointer = l_sp;
  2506. regs.stackFramePointer = l_fp;
  2507. // Raise exception
  2508. SetInternalException(TXT_DIVIDE_BY_ZERO);
  2509. return;
  2510. }
  2511. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
  2512. }
  2513. l_bc += 2;
  2514. break;
  2515. case asBC_BAND64:
  2516. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2517. l_bc += 2;
  2518. break;
  2519. case asBC_BOR64:
  2520. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2521. l_bc += 2;
  2522. break;
  2523. case asBC_BXOR64:
  2524. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
  2525. l_bc += 2;
  2526. break;
  2527. case asBC_BSLL64:
  2528. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
  2529. l_bc += 2;
  2530. break;
  2531. case asBC_BSRL64:
  2532. *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  2533. l_bc += 2;
  2534. break;
  2535. case asBC_BSRA64:
  2536. *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
  2537. l_bc += 2;
  2538. break;
  2539. case asBC_CMPi64:
  2540. {
  2541. asINT64 i = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) - *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
  2542. if( i == 0 ) *(int*)&regs.valueRegister = 0;
  2543. else if( i < 0 ) *(int*)&regs.valueRegister = -1;
  2544. else *(int*)&regs.valueRegister = 1;
  2545. l_bc += 2;
  2546. }
  2547. break;
  2548. case asBC_CMPu64:
  2549. {
  2550. asQWORD d = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
  2551. asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
  2552. if( d == d2 ) *(int*)&regs.valueRegister = 0;
  2553. else if( d < d2 ) *(int*)&regs.valueRegister = -1;
  2554. else *(int*)&regs.valueRegister = 1;
  2555. l_bc += 2;
  2556. }
  2557. break;
  2558. case asBC_ChkNullS:
  2559. {
  2560. // Verify if the pointer on the stack is null
  2561. // This is used for example when validating handles passed as function arguments
  2562. size_t a = *(size_t*)(l_sp + asBC_WORDARG0(l_bc));
  2563. if( a == 0 )
  2564. {
  2565. regs.programPointer = l_bc;
  2566. regs.stackPointer = l_sp;
  2567. regs.stackFramePointer = l_fp;
  2568. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2569. return;
  2570. }
  2571. }
  2572. l_bc++;
  2573. break;
  2574. case asBC_ClrHi:
  2575. #if AS_SIZEOF_BOOL == 1
  2576. {
  2577. // Clear the upper bytes, so that trash data don't interfere with boolean operations
  2578. // We need to use volatile here to tell the compiler it cannot
  2579. // change the order of read and write operations on the pointer.
  2580. volatile asBYTE *ptr = (asBYTE*)&regs.valueRegister;
  2581. ptr[1] = 0; // The boolean value is stored in the lower byte, so we clear the rest
  2582. ptr[2] = 0;
  2583. ptr[3] = 0;
  2584. }
  2585. #else
  2586. // We don't have anything to do here
  2587. #endif
  2588. l_bc++;
  2589. break;
  2590. case asBC_JitEntry:
  2591. {
  2592. if( currentFunction->jitFunction )
  2593. {
  2594. unsigned int jitOffset = asBC_WORDARG0(l_bc);
  2595. if( jitOffset )
  2596. {
  2597. // Resume JIT operation
  2598. regs.programPointer = l_bc;
  2599. regs.stackPointer = l_sp;
  2600. regs.stackFramePointer = l_fp;
  2601. // TODO: JIT: We should return from this function if the jitFunction tells us to
  2602. (currentFunction->jitFunction)(&regs, jitOffset-1);
  2603. l_bc = regs.programPointer;
  2604. l_sp = regs.stackPointer;
  2605. l_fp = regs.stackFramePointer;
  2606. break;
  2607. }
  2608. }
  2609. // Not a JIT resume point, treat as nop
  2610. l_bc++;
  2611. }
  2612. break;
  2613. // Don't let the optimizer optimize for size,
  2614. // since it requires extra conditions and jumps
  2615. case 176: l_bc = (asDWORD*)176; break;
  2616. case 177: l_bc = (asDWORD*)177; break;
  2617. case 178: l_bc = (asDWORD*)178; break;
  2618. case 179: l_bc = (asDWORD*)179; break;
  2619. case 180: l_bc = (asDWORD*)180; break;
  2620. case 181: l_bc = (asDWORD*)181; break;
  2621. case 182: l_bc = (asDWORD*)182; break;
  2622. case 183: l_bc = (asDWORD*)183; break;
  2623. case 184: l_bc = (asDWORD*)184; break;
  2624. case 185: l_bc = (asDWORD*)185; break;
  2625. case 186: l_bc = (asDWORD*)186; break;
  2626. case 187: l_bc = (asDWORD*)187; break;
  2627. case 188: l_bc = (asDWORD*)188; break;
  2628. case 189: l_bc = (asDWORD*)189; break;
  2629. case 190: l_bc = (asDWORD*)190; break;
  2630. case 191: l_bc = (asDWORD*)191; break;
  2631. case 192: l_bc = (asDWORD*)192; break;
  2632. case 193: l_bc = (asDWORD*)193; break;
  2633. case 194: l_bc = (asDWORD*)194; break;
  2634. case 195: l_bc = (asDWORD*)195; break;
  2635. case 196: l_bc = (asDWORD*)196; break;
  2636. case 197: l_bc = (asDWORD*)197; break;
  2637. case 198: l_bc = (asDWORD*)198; break;
  2638. case 199: l_bc = (asDWORD*)199; break;
  2639. case 200: l_bc = (asDWORD*)200; break;
  2640. case 201: l_bc = (asDWORD*)201; break;
  2641. case 202: l_bc = (asDWORD*)202; break;
  2642. case 203: l_bc = (asDWORD*)203; break;
  2643. case 204: l_bc = (asDWORD*)204; break;
  2644. case 205: l_bc = (asDWORD*)205; break;
  2645. case 206: l_bc = (asDWORD*)206; break;
  2646. case 207: l_bc = (asDWORD*)207; break;
  2647. case 208: l_bc = (asDWORD*)208; break;
  2648. case 209: l_bc = (asDWORD*)209; break;
  2649. case 210: l_bc = (asDWORD*)210; break;
  2650. case 211: l_bc = (asDWORD*)211; break;
  2651. case 212: l_bc = (asDWORD*)212; break;
  2652. case 213: l_bc = (asDWORD*)213; break;
  2653. case 214: l_bc = (asDWORD*)214; break;
  2654. case 215: l_bc = (asDWORD*)215; break;
  2655. case 216: l_bc = (asDWORD*)216; break;
  2656. case 217: l_bc = (asDWORD*)217; break;
  2657. case 218: l_bc = (asDWORD*)218; break;
  2658. case 219: l_bc = (asDWORD*)219; break;
  2659. case 220: l_bc = (asDWORD*)220; break;
  2660. case 221: l_bc = (asDWORD*)221; break;
  2661. case 222: l_bc = (asDWORD*)222; break;
  2662. case 223: l_bc = (asDWORD*)223; break;
  2663. case 224: l_bc = (asDWORD*)224; break;
  2664. case 225: l_bc = (asDWORD*)225; break;
  2665. case 226: l_bc = (asDWORD*)226; break;
  2666. case 227: l_bc = (asDWORD*)227; break;
  2667. case 228: l_bc = (asDWORD*)228; break;
  2668. case 229: l_bc = (asDWORD*)229; break;
  2669. case 230: l_bc = (asDWORD*)230; break;
  2670. case 231: l_bc = (asDWORD*)231; break;
  2671. case 232: l_bc = (asDWORD*)232; break;
  2672. case 233: l_bc = (asDWORD*)233; break;
  2673. case 234: l_bc = (asDWORD*)234; break;
  2674. case 235: l_bc = (asDWORD*)235; break;
  2675. case 236: l_bc = (asDWORD*)236; break;
  2676. case 237: l_bc = (asDWORD*)237; break;
  2677. case 238: l_bc = (asDWORD*)238; break;
  2678. case 239: l_bc = (asDWORD*)239; break;
  2679. case 240: l_bc = (asDWORD*)240; break;
  2680. case 241: l_bc = (asDWORD*)241; break;
  2681. case 242: l_bc = (asDWORD*)242; break;
  2682. case 243: l_bc = (asDWORD*)243; break;
  2683. case 244: l_bc = (asDWORD*)244; break;
  2684. case 245: l_bc = (asDWORD*)245; break;
  2685. case 246: l_bc = (asDWORD*)246; break;
  2686. case 247: l_bc = (asDWORD*)247; break;
  2687. case 248: l_bc = (asDWORD*)248; break;
  2688. case 249: l_bc = (asDWORD*)249; break;
  2689. case 250: l_bc = (asDWORD*)250; break;
  2690. case 251: l_bc = (asDWORD*)251; break;
  2691. case 252: l_bc = (asDWORD*)252; break;
  2692. case 253: l_bc = (asDWORD*)253; break;
  2693. case 254: l_bc = (asDWORD*)254; break;
  2694. case 255: l_bc = (asDWORD*)255; break;
  2695. #ifdef AS_DEBUG
  2696. default:
  2697. asASSERT(false);
  2698. #endif
  2699. /*
  2700. default:
  2701. // This Microsoft specific code allows the
  2702. // compiler to optimize the switch case as
  2703. // it will know that the code will never
  2704. // reach this point
  2705. __assume(0);
  2706. */ }
  2707. #ifdef AS_DEBUG
  2708. asDWORD instr = *(asBYTE*)old;
  2709. if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) &&
  2710. instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC )
  2711. {
  2712. asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] );
  2713. }
  2714. #endif
  2715. }
  2716. SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
  2717. }
  2718. int asCContext::SetException(const char *descr)
  2719. {
  2720. // Only allow this if we're executing a CALL byte code
  2721. if( !isCallingSystemFunction ) return asERROR;
  2722. SetInternalException(descr);
  2723. return 0;
  2724. }
  2725. void asCContext::SetInternalException(const char *descr)
  2726. {
  2727. if( inExceptionHandler )
  2728. {
  2729. asASSERT(false); // Shouldn't happen
  2730. return; // but if it does, at least this will not crash the application
  2731. }
  2732. status = asEXECUTION_EXCEPTION;
  2733. regs.doProcessSuspend = true;
  2734. exceptionString = descr;
  2735. exceptionFunction = currentFunction->id;
  2736. exceptionLine = currentFunction->GetLineNumber(int(regs.programPointer - currentFunction->byteCode.AddressOf()));
  2737. exceptionColumn = exceptionLine >> 20;
  2738. exceptionLine &= 0xFFFFF;
  2739. if( exceptionCallback )
  2740. CallExceptionCallback();
  2741. }
  2742. void asCContext::CleanReturnObject()
  2743. {
  2744. if( regs.objectRegister == 0 ) return;
  2745. asASSERT( regs.objectType != 0 );
  2746. if( regs.objectType )
  2747. {
  2748. // Call the destructor on the object
  2749. asSTypeBehaviour *beh = &((asCObjectType*)regs.objectType)->beh;
  2750. if( beh->release )
  2751. {
  2752. engine->CallObjectMethod(regs.objectRegister, beh->release);
  2753. regs.objectRegister = 0;
  2754. // The release method is responsible for freeing the memory
  2755. }
  2756. else
  2757. {
  2758. if( beh->destruct )
  2759. engine->CallObjectMethod(regs.objectRegister, beh->destruct);
  2760. // Free the memory
  2761. engine->CallFree(regs.objectRegister);
  2762. regs.objectRegister = 0;
  2763. }
  2764. }
  2765. }
  2766. void asCContext::CleanStack()
  2767. {
  2768. inExceptionHandler = true;
  2769. // Run the clean up code for each of the functions called
  2770. CleanStackFrame();
  2771. while( callStack.GetLength() > 0 )
  2772. {
  2773. PopCallState();
  2774. CleanStackFrame();
  2775. }
  2776. inExceptionHandler = false;
  2777. }
  2778. void asCContext::CleanStackFrame()
  2779. {
  2780. // Clean object variables
  2781. if( !isStackMemoryNotAllocated )
  2782. {
  2783. for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
  2784. {
  2785. int pos = currentFunction->objVariablePos[n];
  2786. if( *(size_t*)&regs.stackFramePointer[-pos] )
  2787. {
  2788. // Call the object's destructor
  2789. asSTypeBehaviour *beh = &currentFunction->objVariableTypes[n]->beh;
  2790. if( beh->release )
  2791. {
  2792. engine->CallObjectMethod((void*)*(size_t*)&regs.stackFramePointer[-pos], beh->release);
  2793. *(size_t*)&regs.stackFramePointer[-pos] = 0;
  2794. }
  2795. else
  2796. {
  2797. if( beh->destruct )
  2798. engine->CallObjectMethod((void*)*(size_t*)&regs.stackFramePointer[-pos], beh->destruct);
  2799. // Free the memory
  2800. engine->CallFree((void*)*(size_t*)&regs.stackFramePointer[-pos]);
  2801. *(size_t*)&regs.stackFramePointer[-pos] = 0;
  2802. }
  2803. }
  2804. }
  2805. }
  2806. else
  2807. isStackMemoryNotAllocated = false;
  2808. // Functions that do not own the object and parameters shouldn't do any clean up
  2809. if( currentFunction->dontCleanUpOnException )
  2810. return;
  2811. // Clean object and parameters
  2812. int offset = 0;
  2813. if( currentFunction->objectType )
  2814. {
  2815. offset += AS_PTR_SIZE;
  2816. // If the object is a script declared object, then we must release it
  2817. // as the compiler adds a reference at the entry of the function
  2818. asSTypeBehaviour *beh = &currentFunction->objectType->beh;
  2819. if( beh->release && *(size_t*)&regs.stackFramePointer[0] != 0 )
  2820. {
  2821. engine->CallObjectMethod((void*)*(size_t*)&regs.stackFramePointer[0], beh->release);
  2822. *(size_t*)&regs.stackFramePointer[0] = 0;
  2823. }
  2824. }
  2825. for( asUINT n = 0; n < currentFunction->parameterTypes.GetLength(); n++ )
  2826. {
  2827. if( currentFunction->parameterTypes[n].IsObject() && !currentFunction->parameterTypes[n].IsReference() )
  2828. {
  2829. if( *(size_t*)&regs.stackFramePointer[offset] )
  2830. {
  2831. // Call the object's destructor
  2832. asSTypeBehaviour *beh = currentFunction->parameterTypes[n].GetBehaviour();
  2833. if( beh->release )
  2834. {
  2835. engine->CallObjectMethod((void*)*(size_t*)&regs.stackFramePointer[offset], beh->release);
  2836. *(size_t*)&regs.stackFramePointer[offset] = 0;
  2837. }
  2838. else
  2839. {
  2840. if( beh->destruct )
  2841. engine->CallObjectMethod((void*)*(size_t*)&regs.stackFramePointer[offset], beh->destruct);
  2842. // Free the memory
  2843. engine->CallFree((void*)*(size_t*)&regs.stackFramePointer[offset]);
  2844. *(size_t*)&regs.stackFramePointer[offset] = 0;
  2845. }
  2846. }
  2847. }
  2848. offset += currentFunction->parameterTypes[n].GetSizeOnStackDWords();
  2849. }
  2850. }
  2851. int asCContext::GetExceptionLineNumber(int *column)
  2852. {
  2853. if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
  2854. if( column ) *column = exceptionColumn;
  2855. return exceptionLine;
  2856. }
  2857. int asCContext::GetExceptionFunction()
  2858. {
  2859. if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
  2860. return exceptionFunction;
  2861. }
  2862. int asCContext::GetCurrentFunction()
  2863. {
  2864. if( status == asEXECUTION_SUSPENDED || status == asEXECUTION_ACTIVE )
  2865. return currentFunction->id;
  2866. return -1;
  2867. }
  2868. int asCContext::GetCurrentLineNumber(int *column)
  2869. {
  2870. if( status == asEXECUTION_SUSPENDED || status == asEXECUTION_ACTIVE )
  2871. {
  2872. asDWORD line = currentFunction->GetLineNumber(int(regs.programPointer - currentFunction->byteCode.AddressOf()));
  2873. if( column ) *column = line >> 20;
  2874. return line & 0xFFFFF;
  2875. }
  2876. return -1;
  2877. }
  2878. const char *asCContext::GetExceptionString()
  2879. {
  2880. if( GetState() != asEXECUTION_EXCEPTION ) return 0;
  2881. return exceptionString.AddressOf();
  2882. }
  2883. asEContextState asCContext::GetState()
  2884. {
  2885. return status;
  2886. }
  2887. int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
  2888. {
  2889. lineCallback = true;
  2890. regs.doProcessSuspend = true;
  2891. lineCallbackObj = obj;
  2892. bool isObj = false;
  2893. if( (unsigned)callConv == asCALL_GENERIC )
  2894. {
  2895. lineCallback = false;
  2896. regs.doProcessSuspend = doSuspend;
  2897. return asNOT_SUPPORTED;
  2898. }
  2899. if( (unsigned)callConv >= asCALL_THISCALL )
  2900. {
  2901. isObj = true;
  2902. if( obj == 0 )
  2903. {
  2904. lineCallback = false;
  2905. regs.doProcessSuspend = doSuspend;
  2906. return asINVALID_ARG;
  2907. }
  2908. }
  2909. int r = DetectCallingConvention(isObj, callback, callConv, &lineCallbackFunc);
  2910. if( r < 0 ) lineCallback = false;
  2911. regs.doProcessSuspend = doSuspend || lineCallback;
  2912. return r;
  2913. }
  2914. void asCContext::CallLineCallback()
  2915. {
  2916. if( lineCallbackFunc.callConv < ICC_THISCALL )
  2917. engine->CallGlobalFunction(this, lineCallbackObj, &lineCallbackFunc, 0);
  2918. else
  2919. engine->CallObjectMethod(lineCallbackObj, this, &lineCallbackFunc, 0);
  2920. }
  2921. int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv)
  2922. {
  2923. exceptionCallback = true;
  2924. exceptionCallbackObj = obj;
  2925. bool isObj = false;
  2926. if( (unsigned)callConv == asCALL_GENERIC )
  2927. return asNOT_SUPPORTED;
  2928. if( (unsigned)callConv >= asCALL_THISCALL )
  2929. {
  2930. isObj = true;
  2931. if( obj == 0 )
  2932. {
  2933. exceptionCallback = false;
  2934. return asINVALID_ARG;
  2935. }
  2936. }
  2937. int r = DetectCallingConvention(isObj, callback, callConv, &exceptionCallbackFunc);
  2938. if( r < 0 ) exceptionCallback = false;
  2939. return r;
  2940. }
  2941. void asCContext::CallExceptionCallback()
  2942. {
  2943. if( exceptionCallbackFunc.callConv < ICC_THISCALL )
  2944. engine->CallGlobalFunction(this, exceptionCallbackObj, &exceptionCallbackFunc, 0);
  2945. else
  2946. engine->CallObjectMethod(exceptionCallbackObj, this, &exceptionCallbackFunc, 0);
  2947. }
  2948. void asCContext::ClearLineCallback()
  2949. {
  2950. lineCallback = false;
  2951. regs.doProcessSuspend = doSuspend;
  2952. }
  2953. void asCContext::ClearExceptionCallback()
  2954. {
  2955. exceptionCallback = false;
  2956. }
  2957. int asCContext::CallGeneric(int id, void *objectPointer)
  2958. {
  2959. asCScriptFunction *sysFunction = engine->scriptFunctions[id];
  2960. asSSystemFunctionInterface *sysFunc = sysFunction->sysFuncIntf;
  2961. void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func;
  2962. int popSize = sysFunc->paramSize;
  2963. asDWORD *args = regs.stackPointer;
  2964. // Verify the object pointer if it is a class method
  2965. void *currentObject = 0;
  2966. if( sysFunc->callConv == ICC_GENERIC_METHOD )
  2967. {
  2968. if( objectPointer )
  2969. {
  2970. currentObject = objectPointer;
  2971. // Don't increase the reference of this pointer
  2972. // since it will not have been constructed yet
  2973. }
  2974. else
  2975. {
  2976. // The object pointer should be popped from the context stack
  2977. popSize += AS_PTR_SIZE;
  2978. // Check for null pointer
  2979. currentObject = (void*)*(size_t*)(args);
  2980. if( currentObject == 0 )
  2981. {
  2982. SetInternalException(TXT_NULL_POINTER_ACCESS);
  2983. return 0;
  2984. }
  2985. // Add the base offset for multiple inheritance
  2986. currentObject = (void*)(size_t(currentObject) + sysFunc->baseOffset);
  2987. // Skip object pointer
  2988. args += AS_PTR_SIZE;
  2989. }
  2990. }
  2991. asCGeneric gen(engine, sysFunction, currentObject, args);
  2992. isCallingSystemFunction = true;
  2993. func(&gen);
  2994. isCallingSystemFunction = false;
  2995. regs.valueRegister = gen.returnVal;
  2996. regs.objectRegister = gen.objectRegister;
  2997. regs.objectType = sysFunction->returnType.GetObjectType();
  2998. // Clean up function parameters
  2999. int offset = 0;
  3000. for( asUINT n = 0; n < sysFunction->parameterTypes.GetLength(); n++ )
  3001. {
  3002. if( sysFunction->parameterTypes[n].IsObject() && !sysFunction->parameterTypes[n].IsReference() )
  3003. {
  3004. void *obj = *(void**)&args[offset];
  3005. if( obj )
  3006. {
  3007. // Release the object
  3008. asSTypeBehaviour *beh = &sysFunction->parameterTypes[n].GetObjectType()->beh;
  3009. if( beh->release )
  3010. engine->CallObjectMethod(obj, beh->release);
  3011. else
  3012. {
  3013. // Call the destructor then free the memory
  3014. if( beh->destruct )
  3015. engine->CallObjectMethod(obj, beh->destruct);
  3016. engine->CallFree(obj);
  3017. }
  3018. }
  3019. }
  3020. offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords();
  3021. }
  3022. // Return how much should be popped from the stack
  3023. return popSize;
  3024. }
  3025. int asCContext::GetVarCount(int stackLevel)
  3026. {
  3027. if( stackLevel < -1 || stackLevel >= GetCallstackSize() ) return asINVALID_ARG;
  3028. asCScriptFunction *func;
  3029. if( stackLevel == -1 )
  3030. func = currentFunction;
  3031. else
  3032. {
  3033. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3034. func = (asCScriptFunction*)s[1];
  3035. }
  3036. if( func == 0 )
  3037. return asERROR;
  3038. return (int)func->variables.GetLength();
  3039. }
  3040. const char *asCContext::GetVarName(int varIndex, int stackLevel)
  3041. {
  3042. if( stackLevel < -1 || stackLevel >= GetCallstackSize() ) return 0;
  3043. asCScriptFunction *func;
  3044. if( stackLevel == -1 )
  3045. func = currentFunction;
  3046. else
  3047. {
  3048. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3049. func = (asCScriptFunction*)s[1];
  3050. }
  3051. if( func == 0 )
  3052. return 0;
  3053. if( varIndex < 0 || varIndex >= (signed)func->variables.GetLength() )
  3054. return 0;
  3055. return func->variables[varIndex]->name.AddressOf();
  3056. }
  3057. const char *asCContext::GetVarDeclaration(int varIndex, int stackLevel)
  3058. {
  3059. if( stackLevel < -1 || stackLevel >= GetCallstackSize() ) return 0;
  3060. asCScriptFunction *func;
  3061. if( stackLevel == -1 )
  3062. func = currentFunction;
  3063. else
  3064. {
  3065. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3066. func = (asCScriptFunction*)s[1];
  3067. }
  3068. if( func == 0 )
  3069. return 0;
  3070. if( varIndex < 0 || varIndex >= (signed)func->variables.GetLength() )
  3071. return 0;
  3072. asASSERT(threadManager);
  3073. asCString *tempString = &threadManager->GetLocalData()->string;
  3074. *tempString = func->variables[varIndex]->type.Format();
  3075. *tempString += " " + func->variables[varIndex]->name;
  3076. return tempString->AddressOf();
  3077. }
  3078. int asCContext::GetVarTypeId(int varIndex, int stackLevel)
  3079. {
  3080. if( stackLevel < -1 || stackLevel >= GetCallstackSize() ) return asINVALID_ARG;
  3081. asCScriptFunction *func;
  3082. if( stackLevel == -1 )
  3083. func = currentFunction;
  3084. else
  3085. {
  3086. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3087. func = (asCScriptFunction*)s[1];
  3088. }
  3089. if( func == 0 )
  3090. return asINVALID_ARG;
  3091. if( varIndex < 0 || varIndex >= (signed)func->variables.GetLength() )
  3092. return asINVALID_ARG;
  3093. return engine->GetTypeIdFromDataType(func->variables[varIndex]->type);
  3094. }
  3095. void *asCContext::GetAddressOfVar(int varIndex, int stackLevel)
  3096. {
  3097. if( stackLevel < -1 || stackLevel >= GetCallstackSize() ) return 0;
  3098. asCScriptFunction *func;
  3099. asDWORD *sf;
  3100. if( stackLevel == -1 )
  3101. {
  3102. func = currentFunction;
  3103. sf = regs.stackFramePointer;
  3104. }
  3105. else
  3106. {
  3107. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3108. func = (asCScriptFunction*)s[1];
  3109. sf = (asDWORD*)s[0];
  3110. }
  3111. if( func == 0 )
  3112. return 0;
  3113. if( varIndex < 0 || varIndex >= (signed)func->variables.GetLength() )
  3114. return 0;
  3115. // For object variables it's necessary to dereference the pointer to get the address of the value
  3116. if( func->variables[varIndex]->type.IsObject() && !func->variables[varIndex]->type.IsObjectHandle() )
  3117. return *(void**)(sf - func->variables[varIndex]->stackOffset);
  3118. return sf - func->variables[varIndex]->stackOffset;
  3119. }
  3120. // returns the typeId of the 'this' object at the given call stack level (-1 for current)
  3121. // returns 0 if the function call at the given stack level is not a method
  3122. int asCContext::GetThisTypeId(int stackLevel)
  3123. {
  3124. if( stackLevel < -1 || stackLevel >= GetCallstackSize() )
  3125. return 0;
  3126. asCScriptFunction *func = 0;
  3127. if( stackLevel == -1 )
  3128. {
  3129. func = currentFunction;
  3130. }
  3131. else
  3132. {
  3133. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3134. func = (asCScriptFunction*)s[1];
  3135. }
  3136. if( func == 0 )
  3137. return 0;
  3138. if( func->objectType == 0 )
  3139. return 0; // not in a method
  3140. // create a datatype
  3141. asCDataType dt = asCDataType::CreateObject( func->objectType, false);
  3142. // return a typeId from the data type
  3143. return engine->GetTypeIdFromDataType( dt );
  3144. }
  3145. // returns the 'this' object pointer at the given call stack level (-1 for current)
  3146. // returns 0 if the function call at the given stack level is not a method
  3147. void *asCContext::GetThisPointer(int stackLevel)
  3148. {
  3149. if( stackLevel < -1 || stackLevel >= GetCallstackSize() )
  3150. return 0;
  3151. asCScriptFunction *func;
  3152. asDWORD *sf;
  3153. if( stackLevel == -1 )
  3154. {
  3155. func = currentFunction;
  3156. sf = regs.stackFramePointer;
  3157. }
  3158. else
  3159. {
  3160. size_t *s = callStack.AddressOf() + stackLevel*CALLSTACK_FRAME_SIZE;
  3161. func = (asCScriptFunction*)s[1];
  3162. sf = (asDWORD*)s[0];
  3163. }
  3164. if( func == 0 )
  3165. return 0;
  3166. if( func->objectType == 0 )
  3167. return 0; // not in a method
  3168. void *thisPointer = (void*)*(size_t*)(sf);
  3169. if( thisPointer == 0 )
  3170. {
  3171. return 0;
  3172. }
  3173. // NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return
  3174. // a pointer to a pointer. I can't imagine someone would want to change the 'this'
  3175. return thisPointer;
  3176. }
  3177. END_AS_NAMESPACE