1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.runtime.engine; 7 8 import std..string; 9 import std.array; 10 import std.conv; 11 import std.math; 12 import std.algorithm.mutation : swapAt; 13 import std.typecons : Nullable; 14 15 import grimoire.compiler, grimoire.assembly; 16 17 import grimoire.runtime.context; 18 import grimoire.runtime.array; 19 import grimoire.runtime.object; 20 import grimoire.runtime.channel; 21 import grimoire.runtime.indexedarray; 22 import grimoire.runtime.call; 23 24 /** 25 Grimoire's virtual machine. 26 */ 27 class GrEngine { 28 private { 29 /// Bytecode. 30 GrBytecode _bytecode; 31 32 /// Global integral variables. 33 GrInt[] _iglobals; 34 /// Global float variables. 35 GrFloat[] _fglobals; 36 /// Global string variables. 37 GrString[] _sglobals; 38 /// Global object variables. 39 GrPtr[] _oglobals; 40 41 /// Global integral stack. 42 GrInt[] _iglobalStackIn, _iglobalStackOut; 43 /// Global float stack. 44 GrFloat[] _fglobalStackIn, _fglobalStackOut; 45 /// Global string stack. 46 GrString[] _sglobalStackIn, _sglobalStackOut; 47 /// Global object stack. 48 GrPtr[] _oglobalStackIn, _oglobalStackOut; 49 50 /// Context array. 51 DynamicIndexedArray!GrContext _contexts, _contextsToSpawn; 52 53 /// Global panic state. 54 /// It means that the throwing context didn't handle the exception. 55 bool _isPanicking; 56 /// Unhandled panic message. 57 string _panicMessage; 58 /// Stack traces are generated each time an error is raised. 59 GrStackTrace[] _stackTraces; 60 61 /// Extra type compiler information. 62 string _meta; 63 64 /// Primitives. 65 GrCallback[] _callbacks; 66 /// Ditto 67 GrCall[] _calls; 68 } 69 70 /// External way of stopping the VM. 71 shared bool isRunning = true; 72 73 @property { 74 /// Check if there is a coroutine currently running. 75 bool hasCoroutines() const { 76 return (_contexts.length + _contextsToSpawn.length) > 0uL; 77 } 78 79 /// Whether the whole VM has panicked, true if an unhandled error occurred. 80 bool isPanicking() const { 81 return _isPanicking; 82 } 83 84 /// If the VM has raised an error, stack traces are generated. 85 const(GrStackTrace[]) stackTraces() const { 86 return _stackTraces; 87 } 88 89 /// The unhandled error message. 90 string panicMessage() const { 91 return _panicMessage; 92 } 93 94 /// Extra type compiler information. 95 string meta() const { 96 return _meta; 97 } 98 /// Ditto 99 string meta(string newMeta) { 100 return _meta = newMeta; 101 } 102 } 103 104 /// Default. 105 this() { 106 } 107 108 private void initialize() { 109 _contexts = new DynamicIndexedArray!GrContext; 110 _contextsToSpawn = new DynamicIndexedArray!GrContext; 111 } 112 113 /// Add a new library to the runtime. 114 /// ___ 115 /// It must be called before loading the bytecode. 116 /// It should be loading the same library as the compiler 117 /// and in the same order. 118 final void addLibrary(GrLibrary library) { 119 _callbacks ~= library._callbacks; 120 } 121 122 /// Load the bytecode. 123 final void load(GrBytecode bytecode) { 124 initialize(); 125 _bytecode = bytecode; 126 _iglobals = new GrInt[_bytecode.iglobalsCount]; 127 _fglobals = new GrFloat[_bytecode.fglobalsCount]; 128 _sglobals = new GrString[_bytecode.sglobalsCount]; 129 _oglobals = new GrPtr[_bytecode.oglobalsCount]; 130 131 // Setup the primitives 132 for (uint i; i < _bytecode.primitives.length; ++i) { 133 if (_bytecode.primitives[i].index > _callbacks.length) 134 throw new Exception("callback index out of bounds"); 135 _calls ~= new GrCall(_callbacks[_bytecode.primitives[i].index], _bytecode.primitives[i]); 136 } 137 138 foreach (ref globalRef; _bytecode.variables) { 139 const uint typeMask = globalRef.typeMask; 140 const uint index = globalRef.index; 141 if (typeMask & 0x1) 142 _iglobals[index] = globalRef.ivalue; 143 else if (typeMask & 0x2) 144 _fglobals[index] = globalRef.fvalue; 145 else if (typeMask & 0x4) 146 _sglobals[index] = globalRef.svalue; 147 else if (typeMask & 0x8) 148 _oglobals[index] = null; 149 } 150 } 151 152 /** 153 Create the main context. 154 You must call this function before running the vm. 155 --- 156 main { 157 printl("Hello World !"); 158 } 159 --- 160 */ 161 void spawn() { 162 _contexts.push(new GrContext(this)); 163 } 164 165 /** 166 Checks whether an event exists. \ 167 `eventName` must be the mangled name of the event. 168 */ 169 bool hasEvent(string eventName) { 170 return (eventName in _bytecode.events) !is null; 171 } 172 173 /** 174 Spawn a new coroutine registered as an event. \ 175 `eventName` must be the mangled name of the event. 176 --- 177 event mycoroutine() { 178 printl("mycoroutine was created !"); 179 } 180 --- 181 */ 182 GrContext spawnEvent(string eventName) { 183 const auto event = eventName in _bytecode.events; 184 if (event is null) 185 throw new Exception("no event \'" ~ eventName ~ "\' in script"); 186 GrContext context = new GrContext(this); 187 context.pc = *event; 188 _contextsToSpawn.push(context); 189 return context; 190 } 191 192 package(grimoire) void pushContext(GrContext context) { 193 _contextsToSpawn.push(context); 194 } 195 196 /** 197 Captures an unhandled error and kill the VM. 198 */ 199 void panic() { 200 _contexts.reset(); 201 } 202 203 /** 204 Immediately prints a stacktrace to standard output 205 */ 206 private void generateStackTrace(GrContext context) { 207 { 208 GrStackTrace trace; 209 trace.pc = context.pc; 210 auto func = getFunctionInfo(context.pc); 211 if (func.isNull) { 212 trace.name = "?"; 213 } 214 else { 215 trace.name = func.get.name; 216 trace.file = func.get.file; 217 uint index = cast(uint)(cast(int) trace.pc - cast(int) func.get.start); 218 if (index < 0 || index >= func.get.positions.length) { 219 trace.line = 0; 220 trace.column = 0; 221 } 222 else { 223 auto position = func.get.positions[index]; 224 trace.line = position.line; 225 trace.column = position.column; 226 } 227 } 228 _stackTraces ~= trace; 229 } 230 231 for (int i = context.stackPos - 1; i >= 0; i--) { 232 GrStackTrace trace; 233 trace.pc = cast(uint)((cast(int) context.callStack[i].retPosition) - 1); 234 auto func = getFunctionInfo(trace.pc); 235 if (func.isNull) { 236 trace.name = "?"; 237 } 238 else { 239 trace.name = func.get.name; 240 trace.file = func.get.file; 241 uint index = cast(uint)(cast(int) trace.pc - cast(int) func.get.start); 242 if (index < 0 || index >= func.get.positions.length) { 243 trace.line = 1; 244 trace.column = 0; 245 } 246 else { 247 auto position = func.get.positions[index]; 248 trace.line = position.line; 249 trace.column = position.column; 250 } 251 } 252 _stackTraces ~= trace; 253 } 254 } 255 256 /** 257 Tries to resolve a function from a position in the bytecode 258 */ 259 private Nullable!(GrFunctionSymbol) getFunctionInfo(uint position) { 260 Nullable!(GrFunctionSymbol) bestInfo; 261 foreach (const GrSymbol symbol; _bytecode.symbols) { 262 if (symbol.type == GrSymbol.Type.function_) { 263 auto info = cast(GrFunctionSymbol) symbol; 264 if (info.start <= position && info.start + info.length > position) { 265 if (bestInfo.isNull) { 266 bestInfo = info; 267 } 268 else { 269 if (bestInfo.get.length > info.length) { 270 bestInfo = info; 271 } 272 } 273 } 274 } 275 } 276 return bestInfo; 277 } 278 279 /** 280 Raise an error message and attempt to recover from it. \ 281 The error is raised inside a coroutine. \ 282 ___ 283 For each function it unwinds, it'll search for a `try/catch` that captures it. \ 284 If none is found, it'll execute every `defer` statements inside the function and 285 do the same for the next function in the callstack. 286 ___ 287 If nothing catches the error inside the coroutine, the VM enters in a panic state. \ 288 Every coroutines will then execute their `defer` statements and be killed. 289 */ 290 void raise(GrContext context, string message) { 291 if (context.isPanicking) 292 return; 293 //Error message. 294 _sglobalStackIn ~= message; 295 296 generateStackTrace(context); 297 298 //We indicate that the coroutine is in a panic state until a catch is found. 299 context.isPanicking = true; 300 301 context.pc = cast(uint)(cast(int) _bytecode.opcodes.length - 1); 302 303 /+ 304 //Exception handler found in the current function, just jump. 305 if (context.callStack[context.stackPos].exceptionHandlers.length) { 306 context.pc = context.callStack[context.stackPos].exceptionHandlers[$ - 1]; 307 } 308 //No exception handler in the current function, unwinding the deferred code, then return. 309 310 //Check for deferred calls as we will exit the current function. 311 else if (context.callStack[context.stackPos].deferStack.length) { 312 //Pop the last defer and run it. 313 context.pc = context.callStack[context.stackPos].deferStack[$ - 1]; 314 context.callStack[context.stackPos].deferStack.length--; 315 //The search for an exception handler will be done by Unwind after all defer 316 //has been called for this function. 317 } 318 else if (context.stackPos) { 319 //Then returns to the last context, raise will be run again. 320 context.stackPos--; 321 context.ilocalsPos -= context.callStack[context.stackPos].ilocalStackSize; 322 context.flocalsPos -= context.callStack[context.stackPos].flocalStackSize; 323 context.slocalsPos -= context.callStack[context.stackPos].slocalStackSize; 324 context.olocalsPos -= context.callStack[context.stackPos].olocalStackSize; 325 326 if (_isDebug) 327 _debugProfileEnd(); 328 } 329 else { 330 //Kill the others. 331 foreach (coroutine; _contexts) { 332 coroutine.pc = cast(uint)(cast(int) _bytecode.opcodes.length - 1); 333 coroutine.isKilled = true; 334 } 335 _contextsToSpawn.reset(); 336 337 //The VM is now panicking. 338 _isPanicking = true; 339 _panicMessage = _sglobalStackIn[$ - 1]; 340 _sglobalStackIn.length--; 341 }+/ 342 } 343 344 /** 345 Marks each coroutine as killed and prevents any new coroutine from spawning. 346 */ 347 private void killAll() { 348 foreach (coroutine; _contexts) { 349 coroutine.pc = cast(uint)(cast(int) _bytecode.opcodes.length - 1); 350 coroutine.isKilled = true; 351 } 352 _contextsToSpawn.reset(); 353 } 354 355 alias getBoolVariable = getVariable!bool; 356 alias getIntVariable = getVariable!GrInt; 357 alias getFloatVariable = getVariable!GrFloat; 358 alias getStringVariable = getVariable!GrString; 359 alias getPtrVariable = getVariable!GrPtr; 360 361 GrObject getObjectVariable(string name) { 362 return cast(GrObject) getVariable!(GrPtr)(name); 363 } 364 365 GrIntArray getIntArrayVariable(string name) { 366 return cast(GrIntArray) getVariable!(GrPtr)(name); 367 } 368 369 GrFloatArray getFloatArrayVariable(string name) { 370 return cast(GrFloatArray) getVariable!(GrPtr)(name); 371 } 372 373 GrStringArray getStringArrayVariable(string name) { 374 return cast(GrStringArray) getVariable!(GrPtr)(name); 375 } 376 377 GrObjectArray getObjectArrayVariable(string name) { 378 return cast(GrObjectArray) getVariable!(GrPtr)(name); 379 } 380 381 GrIntChannel getIntChannelVariable(string name) { 382 return cast(GrIntChannel) getVariable!(GrPtr)(name); 383 } 384 385 GrFloatChannel getFloatChannelVariable(string name) { 386 return cast(GrFloatChannel) getVariable!(GrPtr)(name); 387 } 388 389 GrStringChannel getStringChannelVariable(string name) { 390 return cast(GrStringChannel) getVariable!(GrPtr)(name); 391 } 392 393 GrObjectChannel getObjectChannelVariable(string name) { 394 return cast(GrObjectChannel) getVariable!(GrPtr)(name); 395 } 396 397 T getEnumVariable(T)(string name) { 398 return cast(T) getVariable!int(name); 399 } 400 401 T getForeignVariable(T)(string name) { 402 // We cast to object first to avoid a crash when casting to a parent class 403 return cast(T) cast(Object) getVariable!(GrPtr)(name); 404 } 405 406 private T getVariable(T)(string name) { 407 const auto variable = name in _bytecode.variables; 408 if (variable is null) 409 throw new Exception("no global variable `" ~ name ~ "` defined"); 410 static if (is(T == GrInt)) { 411 if ((variable.typeMask & 0x1) == 0) 412 throw new Exception("variable `" ~ name ~ "` is not an int"); 413 return _iglobals[variable.index]; 414 } 415 else static if (is(T == GrBool)) { 416 if ((variable.typeMask & 0x1) == 0) 417 throw new Exception("variable `" ~ name ~ "` is not an int"); 418 return _iglobals[variable.index] > 0; 419 } 420 else static if (is(T == GrFloat)) { 421 if ((variable.typeMask & 0x2) == 0) 422 throw new Exception("variable `" ~ name ~ "` is not a float"); 423 return _fglobals[variable.index]; 424 } 425 else static if (is(T == GrString)) { 426 if ((variable.typeMask & 0x4) == 0) 427 throw new Exception("variable `" ~ name ~ "` is not a string"); 428 return _sglobals[variable.index]; 429 } 430 else static if (is(T == GrPtr)) { 431 if ((variable.typeMask & 0x8) == 0) 432 throw new Exception("variable `" ~ name ~ "` is not an object"); 433 return _oglobals[variable.index]; 434 } 435 } 436 437 alias setBoolVariable = setVariable!GrBool; 438 alias setIntVariable = setVariable!GrInt; 439 alias setFloatVariable = setVariable!GrFloat; 440 alias setStringVariable = setVariable!GrString; 441 alias setPtrVariable = setVariable!GrPtr; 442 443 void setObjectVariable(string name, GrObject value) { 444 setVariable!(GrPtr)(name, cast(GrPtr) value); 445 } 446 447 void setIntArrayVariable(string name, GrIntArray value) { 448 setVariable!(GrPtr)(name, cast(GrPtr) value); 449 } 450 451 void setFloatArrayVariable(string name, GrFloatArray value) { 452 setVariable!(GrPtr)(name, cast(GrPtr) value); 453 } 454 455 void setStringArrayVariable(string name, GrStringArray value) { 456 setVariable!(GrPtr)(name, cast(GrPtr) value); 457 } 458 459 void setObjectArrayVariable(string name, GrObjectArray value) { 460 setVariable!(GrPtr)(name, cast(GrPtr) value); 461 } 462 463 void setIntChannelVariable(string name, GrIntChannel value) { 464 setVariable!(GrPtr)(name, cast(GrPtr) value); 465 } 466 467 void setFloatChannelVariable(string name, GrFloatChannel value) { 468 setVariable!(GrPtr)(name, cast(GrPtr) value); 469 } 470 471 void setStringChannelVariable(string name, GrStringChannel value) { 472 setVariable!(GrPtr)(name, cast(GrPtr) value); 473 } 474 475 void setObjectChannelVariable(string name, GrObjectChannel value) { 476 setVariable!(GrPtr)(name, cast(GrPtr) value); 477 } 478 479 void setEnumVariable(T)(string name, T value) { 480 setVariable!int(name, cast(int) value); 481 } 482 483 void setForeignVariable(T)(string name, T value) { 484 setVariable!(GrPtr)(name, cast(GrPtr) value); 485 } 486 487 private void setVariable(T)(string name, T value) { 488 const auto variable = name in _bytecode.variables; 489 if (variable is null) 490 throw new Exception("no global variable `" ~ name ~ "` defined"); 491 static if (is(T == GrInt)) { 492 if ((variable.typeMask & 0x1) == 0) 493 throw new Exception("variable `" ~ name ~ "` is not an int"); 494 _iglobals[variable.index] = value; 495 } 496 else static if (is(T == GrBool)) { 497 if ((variable.typeMask & 0x1) == 0) 498 throw new Exception("variable `" ~ name ~ "` is not an int"); 499 _iglobals[variable.index] = value; 500 } 501 else static if (is(T == GrFloat)) { 502 if ((variable.typeMask & 0x2) == 0) 503 throw new Exception("variable `" ~ name ~ "` is not a float"); 504 _fglobals[variable.index] = value; 505 } 506 else static if (is(T == GrString)) { 507 if ((variable.typeMask & 0x4) == 0) 508 throw new Exception("variable `" ~ name ~ "` is not a string"); 509 _sglobals[variable.index] = value; 510 } 511 else static if (is(T == GrPtr)) { 512 if ((variable.typeMask & 0x8) == 0) 513 throw new Exception("variable `" ~ name ~ "` is not an object"); 514 _oglobals[variable.index] = value; 515 } 516 } 517 518 /// Run the vm until all the contexts are finished or in yield. 519 void process() { 520 if (_contextsToSpawn.length) { 521 for (int index = cast(int) _contextsToSpawn.length - 1; index >= 0; index--) 522 _contexts.push(_contextsToSpawn[index]); 523 _contextsToSpawn.reset(); 524 import std.algorithm.mutation : swap; 525 526 swap(_iglobalStackIn, _iglobalStackOut); 527 swap(_fglobalStackIn, _fglobalStackOut); 528 swap(_sglobalStackIn, _sglobalStackOut); 529 swap(_oglobalStackIn, _oglobalStackOut); 530 } 531 contextsLabel: for (uint index = 0u; index < _contexts.length; index++) { 532 GrContext context = _contexts.data[index]; 533 if (context.blocker) { 534 if (!context.blocker.run()) 535 continue; 536 context.blocker = null; 537 } 538 while (isRunning) { 539 const uint opcode = _bytecode.opcodes[context.pc]; 540 final switch (opcode & 0xFF) with (GrOpcode) { 541 case nop: 542 context.pc++; 543 break; 544 case raise_: 545 if (!context.isPanicking) { 546 //Error message. 547 _sglobalStackIn ~= context.sstack[context.sstackPos]; 548 context.sstackPos--; 549 generateStackTrace(context); 550 551 //We indicate that the coroutine is in a panic state until a catch is found. 552 context.isPanicking = true; 553 } 554 555 //Exception handler found in the current function, just jump. 556 if (context.callStack[context.stackPos].exceptionHandlers.length) { 557 context.pc = context.callStack[context.stackPos].exceptionHandlers[$ - 1]; 558 } 559 //No exception handler in the current function, unwinding the deferred code, then return. 560 561 //Check for deferred calls as we will exit the current function. 562 else if (context.callStack[context.stackPos].deferStack.length) { 563 //Pop the last defer and run it. 564 context.pc = context.callStack[context.stackPos].deferStack[$ - 1]; 565 context.callStack[context.stackPos].deferStack.length--; 566 //The search for an exception handler will be done by Unwind after all defer 567 //has been called for this function. 568 } 569 else if (context.stackPos) { 570 //Then returns to the last context, raise will be run again. 571 context.stackPos--; 572 context.ilocalsPos -= context.callStack[context.stackPos].ilocalStackSize; 573 context.flocalsPos -= context.callStack[context.stackPos].flocalStackSize; 574 context.slocalsPos -= context.callStack[context.stackPos].slocalStackSize; 575 context.olocalsPos -= context.callStack[context.stackPos].olocalStackSize; 576 577 if (_isDebug) 578 _debugProfileEnd(); 579 } 580 else { 581 //Kill the others. 582 killAll(); 583 584 //The VM is now panicking. 585 _isPanicking = true; 586 _panicMessage = _sglobalStackIn[$ - 1]; 587 _sglobalStackIn.length--; 588 589 //Every deferred call has been executed, now die. 590 _contexts.markInternalForRemoval(index); 591 continue contextsLabel; 592 } 593 break; 594 case try_: 595 context.callStack[context.stackPos].exceptionHandlers ~= context.pc + grGetInstructionSignedValue( 596 opcode); 597 context.pc++; 598 break; 599 case catch_: 600 context.callStack[context.stackPos].exceptionHandlers.length--; 601 if (context.isPanicking) { 602 context.isPanicking = false; 603 _stackTraces.length = 0; 604 context.pc++; 605 } 606 else { 607 context.pc += grGetInstructionSignedValue(opcode); 608 } 609 break; 610 case task: 611 GrContext newCoro = new GrContext(this); 612 newCoro.pc = grGetInstructionUnsignedValue(opcode); 613 _contextsToSpawn.push(newCoro); 614 context.pc++; 615 break; 616 case anonymousTask: 617 GrContext newCoro = new GrContext(this); 618 newCoro.pc = cast(uint) context.istack[context.istackPos]; 619 context.istackPos--; 620 _contextsToSpawn.push(newCoro); 621 context.pc++; 622 break; 623 case kill_: 624 //Check for deferred calls. 625 if (context.callStack[context.stackPos].deferStack.length) { 626 //Pop the last defer and run it. 627 context.pc = context.callStack[context.stackPos].deferStack[$ - 1]; 628 context.callStack[context.stackPos].deferStack.length--; 629 630 //Flag as killed so the entire stack will be unwinded. 631 context.isKilled = true; 632 } 633 else if (context.stackPos) { 634 //Then returns to the last context. 635 context.stackPos--; 636 context.pc = context.callStack[context.stackPos].retPosition; 637 context.ilocalsPos -= context.callStack[context.stackPos].ilocalStackSize; 638 context.flocalsPos -= context.callStack[context.stackPos].flocalStackSize; 639 context.slocalsPos -= context.callStack[context.stackPos].slocalStackSize; 640 context.olocalsPos -= context.callStack[context.stackPos].olocalStackSize; 641 642 //Flag as killed so the entire stack will be unwinded. 643 context.isKilled = true; 644 } 645 else { 646 //No need to flag if the call stack is empty without any deferred statement. 647 _contexts.markInternalForRemoval(index); 648 continue contextsLabel; 649 } 650 break; 651 case killAll_: 652 killAll(); 653 continue contextsLabel; 654 case yield: 655 context.pc++; 656 continue contextsLabel; 657 case new_: 658 context.ostackPos++; 659 if (context.ostackPos == context.ostack.length) 660 context.ostack.length *= 2; 661 context.ostack[context.ostackPos] = cast(GrPtr) new GrObject( 662 _bytecode.classes[grGetInstructionUnsignedValue(opcode)]); 663 context.pc++; 664 break; 665 case channel_int: 666 context.ostackPos++; 667 if (context.ostackPos == context.ostack.length) 668 context.ostack.length *= 2; 669 context.ostack[context.ostackPos] = cast(GrPtr) new GrIntChannel( 670 grGetInstructionUnsignedValue(opcode)); 671 context.pc++; 672 break; 673 case channel_float: 674 context.ostackPos++; 675 if (context.ostackPos == context.ostack.length) 676 context.ostack.length *= 2; 677 context.ostack[context.ostackPos] = cast(GrPtr) new GrFloatChannel( 678 grGetInstructionUnsignedValue(opcode)); 679 context.pc++; 680 break; 681 case channel_string: 682 context.ostackPos++; 683 if (context.ostackPos == context.ostack.length) 684 context.ostack.length *= 2; 685 context.ostack[context.ostackPos] = cast(GrPtr) new GrStringChannel( 686 grGetInstructionUnsignedValue(opcode)); 687 context.pc++; 688 break; 689 case channel_object: 690 context.ostackPos++; 691 if (context.ostackPos == context.ostack.length) 692 context.ostack.length *= 2; 693 context.ostack[context.ostackPos] = cast(GrPtr) new GrObjectChannel( 694 grGetInstructionUnsignedValue(opcode)); 695 context.pc++; 696 break; 697 case send_int: 698 GrIntChannel chan = cast(GrIntChannel) context.ostack[context.ostackPos]; 699 if (!chan.isOwned) { 700 if (context.isEvaluatingChannel) { 701 context.restoreState(); 702 context.isLocked = true; 703 context.isEvaluatingChannel = false; 704 context.pc = context.selectPositionJump; 705 } 706 else { 707 context.istackPos--; 708 context.ostackPos--; 709 raise(context, "ChannelError"); 710 } 711 } 712 else if (chan.canSend) { 713 context.isLocked = false; 714 chan.send(context.istack[context.istackPos]); 715 context.ostackPos--; 716 context.pc++; 717 } 718 else { 719 context.isLocked = true; 720 if (context.isEvaluatingChannel) { 721 context.restoreState(); 722 context.isEvaluatingChannel = false; 723 context.pc = context.selectPositionJump; 724 } 725 else 726 continue contextsLabel; 727 } 728 break; 729 case send_float: 730 GrFloatChannel chan = cast(GrFloatChannel) context.ostack[context.ostackPos]; 731 if (!chan.isOwned) { 732 if (context.isEvaluatingChannel) { 733 context.restoreState(); 734 context.isLocked = true; 735 context.isEvaluatingChannel = false; 736 context.pc = context.selectPositionJump; 737 } 738 else { 739 context.fstackPos--; 740 context.ostackPos--; 741 raise(context, "ChannelError"); 742 } 743 } 744 else if (chan.canSend) { 745 context.isLocked = false; 746 chan.send(context.fstack[context.fstackPos]); 747 context.ostackPos--; 748 context.pc++; 749 } 750 else { 751 context.isLocked = true; 752 if (context.isEvaluatingChannel) { 753 context.restoreState(); 754 context.isEvaluatingChannel = false; 755 context.pc = context.selectPositionJump; 756 } 757 else 758 continue contextsLabel; 759 } 760 break; 761 case send_string: 762 GrStringChannel chan = cast(GrStringChannel) context.ostack[context.ostackPos]; 763 if (!chan.isOwned) { 764 if (context.isEvaluatingChannel) { 765 context.restoreState(); 766 context.isLocked = true; 767 context.isEvaluatingChannel = false; 768 context.pc = context.selectPositionJump; 769 } 770 else { 771 context.sstackPos--; 772 context.ostackPos--; 773 raise(context, "ChannelError"); 774 } 775 } 776 else if (chan.canSend) { 777 context.isLocked = false; 778 chan.send(context.sstack[context.sstackPos]); 779 context.ostackPos--; 780 context.pc++; 781 } 782 else { 783 context.isLocked = true; 784 if (context.isEvaluatingChannel) { 785 context.restoreState(); 786 context.isEvaluatingChannel = false; 787 context.pc = context.selectPositionJump; 788 } 789 else 790 continue contextsLabel; 791 } 792 break; 793 case send_object: 794 GrObjectChannel chan = cast(GrObjectChannel) context 795 .ostack[context.ostackPos - 1]; 796 if (!chan.isOwned) { 797 if (context.isEvaluatingChannel) { 798 context.restoreState(); 799 context.isLocked = true; 800 context.isEvaluatingChannel = false; 801 context.pc = context.selectPositionJump; 802 } 803 else { 804 context.ostackPos -= 2; 805 raise(context, "ChannelError"); 806 } 807 } 808 else if (chan.canSend) { 809 context.isLocked = false; 810 chan.send(context.ostack[context.ostackPos]); 811 context.ostack[context.ostackPos - 1] = context.ostack[context.ostackPos]; 812 context.ostackPos--; 813 context.pc++; 814 } 815 else { 816 context.isLocked = true; 817 if (context.isEvaluatingChannel) { 818 context.restoreState(); 819 context.isEvaluatingChannel = false; 820 context.pc = context.selectPositionJump; 821 } 822 else 823 continue contextsLabel; 824 } 825 break; 826 case receive_int: 827 GrIntChannel chan = cast(GrIntChannel) context.ostack[context.ostackPos]; 828 if (!chan.isOwned) { 829 if (context.isEvaluatingChannel) { 830 context.restoreState(); 831 context.isLocked = true; 832 context.isEvaluatingChannel = false; 833 context.pc = context.selectPositionJump; 834 } 835 else { 836 context.ostackPos--; 837 raise(context, "ChannelError"); 838 } 839 } 840 else if (chan.canReceive) { 841 context.isLocked = false; 842 context.istackPos++; 843 if (context.istackPos == context.istack.length) 844 context.istack.length *= 2; 845 context.istack[context.istackPos] = chan.receive(); 846 context.ostackPos--; 847 context.pc++; 848 } 849 else { 850 chan.setReceiverReady(); 851 context.isLocked = true; 852 if (context.isEvaluatingChannel) { 853 context.restoreState(); 854 context.isEvaluatingChannel = false; 855 context.pc = context.selectPositionJump; 856 } 857 else 858 continue contextsLabel; 859 } 860 break; 861 case receive_float: 862 GrFloatChannel chan = cast(GrFloatChannel) context.ostack[context.ostackPos]; 863 if (!chan.isOwned) { 864 if (context.isEvaluatingChannel) { 865 context.restoreState(); 866 context.isLocked = true; 867 context.isEvaluatingChannel = false; 868 context.pc = context.selectPositionJump; 869 } 870 else { 871 context.ostackPos--; 872 raise(context, "ChannelError"); 873 } 874 } 875 else if (chan.canReceive) { 876 context.isLocked = false; 877 context.fstackPos++; 878 if (context.fstackPos == context.fstack.length) 879 context.fstack.length *= 2; 880 context.fstack[context.fstackPos] = chan.receive(); 881 context.ostackPos--; 882 context.pc++; 883 } 884 else { 885 chan.setReceiverReady(); 886 context.isLocked = true; 887 if (context.isEvaluatingChannel) { 888 context.restoreState(); 889 context.isEvaluatingChannel = false; 890 context.pc = context.selectPositionJump; 891 } 892 else 893 continue contextsLabel; 894 } 895 break; 896 case receive_string: 897 GrStringChannel chan = cast(GrStringChannel) context.ostack[context.ostackPos]; 898 if (!chan.isOwned) { 899 if (context.isEvaluatingChannel) { 900 context.restoreState(); 901 context.isLocked = true; 902 context.isEvaluatingChannel = false; 903 context.pc = context.selectPositionJump; 904 } 905 else { 906 context.ostackPos--; 907 raise(context, "ChannelError"); 908 } 909 } 910 else if (chan.canReceive) { 911 context.isLocked = false; 912 context.sstackPos++; 913 if (context.sstackPos == context.sstack.length) 914 context.sstack.length *= 2; 915 context.sstack[context.sstackPos] = chan.receive(); 916 context.ostackPos--; 917 context.pc++; 918 } 919 else { 920 chan.setReceiverReady(); 921 context.isLocked = true; 922 if (context.isEvaluatingChannel) { 923 context.restoreState(); 924 context.isEvaluatingChannel = false; 925 context.pc = context.selectPositionJump; 926 } 927 else 928 continue contextsLabel; 929 } 930 break; 931 case receive_object: 932 GrObjectChannel chan = cast(GrObjectChannel) context.ostack[context.ostackPos]; 933 if (!chan.isOwned) { 934 if (context.isEvaluatingChannel) { 935 context.restoreState(); 936 context.isLocked = true; 937 context.isEvaluatingChannel = false; 938 context.pc = context.selectPositionJump; 939 } 940 else { 941 context.ostackPos--; 942 raise(context, "ChannelError"); 943 } 944 } 945 else if (chan.canReceive) { 946 context.isLocked = false; 947 context.ostack[context.ostackPos] = chan.receive(); 948 context.pc++; 949 } 950 else { 951 chan.setReceiverReady(); 952 context.isLocked = true; 953 if (context.isEvaluatingChannel) { 954 context.restoreState(); 955 context.isEvaluatingChannel = false; 956 context.pc = context.selectPositionJump; 957 } 958 else 959 continue contextsLabel; 960 } 961 break; 962 case startSelectChannel: 963 context.pushState(); 964 context.pc++; 965 break; 966 case endSelectChannel: 967 context.popState(); 968 context.pc++; 969 break; 970 case tryChannel: 971 if (context.isEvaluatingChannel) 972 raise(context, "SelectError"); 973 context.isEvaluatingChannel = true; 974 context.selectPositionJump = context.pc + grGetInstructionSignedValue(opcode); 975 context.pc++; 976 break; 977 case checkChannel: 978 if (!context.isEvaluatingChannel) 979 raise(context, "SelectError"); 980 context.isEvaluatingChannel = false; 981 context.restoreState(); 982 context.pc++; 983 break; 984 case shiftStack_int: 985 context.istackPos += grGetInstructionSignedValue(opcode); 986 context.pc++; 987 break; 988 case shiftStack_float: 989 context.fstackPos += grGetInstructionSignedValue(opcode); 990 context.pc++; 991 break; 992 case shiftStack_string: 993 context.sstackPos += grGetInstructionSignedValue(opcode); 994 context.pc++; 995 break; 996 case shiftStack_object: 997 context.ostackPos += grGetInstructionSignedValue(opcode); 998 context.pc++; 999 break; 1000 case localStore_int: 1001 context.ilocals[context.ilocalsPos + grGetInstructionUnsignedValue( 1002 opcode)] = context.istack[context.istackPos]; 1003 context.istackPos--; 1004 context.pc++; 1005 break; 1006 case localStore_float: 1007 context.flocals[context.flocalsPos + grGetInstructionUnsignedValue( 1008 opcode)] = context.fstack[context.fstackPos]; 1009 context.fstackPos--; 1010 context.pc++; 1011 break; 1012 case localStore_string: 1013 context.slocals[context.slocalsPos + grGetInstructionUnsignedValue( 1014 opcode)] = context.sstack[context.sstackPos]; 1015 context.sstackPos--; 1016 context.pc++; 1017 break; 1018 case localStore_object: 1019 context.olocals[context.olocalsPos + grGetInstructionUnsignedValue( 1020 opcode)] = context.ostack[context.ostackPos]; 1021 context.ostackPos--; 1022 context.pc++; 1023 break; 1024 case localStore2_int: 1025 context.ilocals[context.ilocalsPos + grGetInstructionUnsignedValue( 1026 opcode)] = context.istack[context.istackPos]; 1027 context.pc++; 1028 break; 1029 case localStore2_float: 1030 context.flocals[context.flocalsPos + grGetInstructionUnsignedValue( 1031 opcode)] = context.fstack[context.fstackPos]; 1032 context.pc++; 1033 break; 1034 case localStore2_string: 1035 context.slocals[context.slocalsPos + grGetInstructionUnsignedValue( 1036 opcode)] = context.sstack[context.sstackPos]; 1037 context.pc++; 1038 break; 1039 case localStore2_object: 1040 context.olocals[context.olocalsPos + grGetInstructionUnsignedValue( 1041 opcode)] = context.ostack[context.ostackPos]; 1042 context.pc++; 1043 break; 1044 case localLoad_int: 1045 context.istackPos++; 1046 if (context.istackPos == context.istack.length) 1047 context.istack.length *= 2; 1048 context.istack[context.istackPos] 1049 = context.ilocals[context.ilocalsPos + grGetInstructionUnsignedValue( 1050 opcode)]; 1051 context.pc++; 1052 break; 1053 case localLoad_float: 1054 context.fstackPos++; 1055 if (context.fstackPos == context.fstack.length) 1056 context.fstack.length *= 2; 1057 context.fstack[context.fstackPos] 1058 = context.flocals[context.flocalsPos + grGetInstructionUnsignedValue( 1059 opcode)]; 1060 context.pc++; 1061 break; 1062 case localLoad_string: 1063 context.sstackPos++; 1064 if (context.sstackPos == context.sstack.length) 1065 context.sstack.length *= 2; 1066 context.sstack[context.sstackPos] 1067 = context.slocals[context.slocalsPos + grGetInstructionUnsignedValue( 1068 opcode)]; 1069 context.pc++; 1070 break; 1071 case localLoad_object: 1072 context.ostackPos++; 1073 if (context.ostackPos == context.ostack.length) 1074 context.ostack.length *= 2; 1075 context.ostack[context.ostackPos] 1076 = context.olocals[context.olocalsPos + grGetInstructionUnsignedValue( 1077 opcode)]; 1078 context.pc++; 1079 break; 1080 case globalStore_int: 1081 _iglobals[grGetInstructionUnsignedValue(opcode)] = context 1082 .istack[context.istackPos]; 1083 context.istackPos--; 1084 context.pc++; 1085 break; 1086 case globalStore_float: 1087 _fglobals[grGetInstructionUnsignedValue(opcode)] = context 1088 .fstack[context.fstackPos]; 1089 context.fstackPos--; 1090 context.pc++; 1091 break; 1092 case globalStore_string: 1093 _sglobals[grGetInstructionUnsignedValue(opcode)] = context 1094 .sstack[context.sstackPos]; 1095 context.sstackPos--; 1096 context.pc++; 1097 break; 1098 case globalStore_object: 1099 _oglobals[grGetInstructionUnsignedValue(opcode)] = context 1100 .ostack[context.ostackPos]; 1101 context.ostackPos--; 1102 context.pc++; 1103 break; 1104 case globalStore2_int: 1105 _iglobals[grGetInstructionUnsignedValue(opcode)] = context 1106 .istack[context.istackPos]; 1107 context.pc++; 1108 break; 1109 case globalStore2_float: 1110 _fglobals[grGetInstructionUnsignedValue(opcode)] = context 1111 .fstack[context.fstackPos]; 1112 context.pc++; 1113 break; 1114 case globalStore2_string: 1115 _sglobals[grGetInstructionUnsignedValue(opcode)] = context 1116 .sstack[context.sstackPos]; 1117 context.pc++; 1118 break; 1119 case globalStore2_object: 1120 _oglobals[grGetInstructionUnsignedValue(opcode)] = context 1121 .ostack[context.ostackPos]; 1122 context.pc++; 1123 break; 1124 case globalLoad_int: 1125 context.istackPos++; 1126 if (context.istackPos == context.istack.length) 1127 context.istack.length *= 2; 1128 context.istack[context.istackPos] = _iglobals[grGetInstructionUnsignedValue( 1129 opcode)]; 1130 context.pc++; 1131 break; 1132 case globalLoad_float: 1133 context.fstackPos++; 1134 if (context.fstackPos == context.fstack.length) 1135 context.fstack.length *= 2; 1136 context.fstack[context.fstackPos] = _fglobals[grGetInstructionUnsignedValue( 1137 opcode)]; 1138 context.pc++; 1139 break; 1140 case globalLoad_string: 1141 context.sstackPos++; 1142 if (context.sstackPos == context.sstack.length) 1143 context.sstack.length *= 2; 1144 context.sstack[context.sstackPos] = _sglobals[grGetInstructionUnsignedValue( 1145 opcode)]; 1146 context.pc++; 1147 break; 1148 case globalLoad_object: 1149 context.ostackPos++; 1150 if (context.ostackPos == context.ostack.length) 1151 context.ostack.length *= 2; 1152 context.ostack[context.ostackPos] = _oglobals[grGetInstructionUnsignedValue( 1153 opcode)]; 1154 context.pc++; 1155 break; 1156 case refStore_int: 1157 *(cast(GrInt*) context.ostack[context.ostackPos]) = context 1158 .istack[context.istackPos]; 1159 context.ostackPos--; 1160 context.istackPos--; 1161 context.pc++; 1162 break; 1163 case refStore_float: 1164 *(cast(GrFloat*) context.ostack[context.ostackPos]) = context 1165 .fstack[context.fstackPos]; 1166 context.ostackPos--; 1167 context.fstackPos--; 1168 context.pc++; 1169 break; 1170 case refStore_string: 1171 *(cast(GrString*) context.ostack[context.ostackPos]) = context 1172 .sstack[context.sstackPos]; 1173 context.ostackPos--; 1174 context.sstackPos--; 1175 context.pc++; 1176 break; 1177 case refStore_object: 1178 *(cast(GrPtr*) context.ostack[context.ostackPos - 1]) = context 1179 .ostack[context.ostackPos]; 1180 context.ostackPos -= 2; 1181 context.pc++; 1182 break; 1183 case refStore2_int: 1184 *(cast(GrInt*) context.ostack[context.ostackPos]) = context 1185 .istack[context.istackPos]; 1186 context.ostackPos--; 1187 context.pc++; 1188 break; 1189 case refStore2_float: 1190 *(cast(GrFloat*) context.ostack[context.ostackPos]) = context 1191 .fstack[context.fstackPos]; 1192 context.ostackPos--; 1193 context.pc++; 1194 break; 1195 case refStore2_string: 1196 *(cast(GrString*) context.ostack[context.ostackPos]) = context 1197 .sstack[context.sstackPos]; 1198 context.ostackPos--; 1199 context.pc++; 1200 break; 1201 case refStore2_object: 1202 *(cast(GrPtr*) context.ostack[context.ostackPos - 1]) = context 1203 .ostack[context.ostackPos]; 1204 context.ostack[context.ostackPos - 1] = context.ostack[context.ostackPos]; 1205 context.ostackPos--; 1206 context.pc++; 1207 break; 1208 case fieldStore_int: 1209 (cast(GrField) context.ostack[context.ostackPos]).ivalue 1210 = context.istack[context.istackPos]; 1211 context.istackPos += grGetInstructionSignedValue(opcode); 1212 context.ostackPos--; 1213 context.pc++; 1214 break; 1215 case fieldStore_float: 1216 (cast(GrField) context.ostack[context.ostackPos]).fvalue 1217 = context.fstack[context.fstackPos]; 1218 context.fstackPos += grGetInstructionSignedValue(opcode); 1219 context.ostackPos--; 1220 context.pc++; 1221 break; 1222 case fieldStore_string: 1223 (cast(GrField) context.ostack[context.ostackPos]).svalue 1224 = context.sstack[context.sstackPos]; 1225 context.sstackPos += grGetInstructionSignedValue(opcode); 1226 context.ostackPos--; 1227 context.pc++; 1228 break; 1229 case fieldStore_object: 1230 context.ostackPos--; 1231 (cast(GrField) context.ostack[context.ostackPos]).ovalue 1232 = context.ostack[context.ostackPos + 1]; 1233 context.ostack[context.ostackPos] = context.ostack[context.ostackPos + 1]; 1234 context.ostackPos += grGetInstructionSignedValue(opcode); 1235 context.pc++; 1236 break; 1237 case fieldLoad: 1238 if (!context.ostack[context.ostackPos]) { 1239 raise(context, "NullError"); 1240 break; 1241 } 1242 context.ostack[context.ostackPos] = cast(GrPtr)((cast(GrObject) context.ostack[context.ostackPos]) 1243 ._fields[grGetInstructionUnsignedValue(opcode)]); 1244 context.pc++; 1245 break; 1246 case fieldLoad2: 1247 context.ostackPos++; 1248 if (context.ostackPos == context.ostack.length) 1249 context.ostack.length *= 2; 1250 context.ostack[context.ostackPos] = cast(GrPtr)( 1251 (cast(GrObject) context.ostack[context.ostackPos - 1]) 1252 ._fields[grGetInstructionUnsignedValue(opcode)]); 1253 context.pc++; 1254 break; 1255 case fieldLoad_int: 1256 if (!context.ostack[context.ostackPos]) { 1257 raise(context, "NullError"); 1258 break; 1259 } 1260 context.istackPos++; 1261 if (context.istackPos == context.istack.length) 1262 context.istack.length *= 2; 1263 context.istack[context.istackPos] = (cast(GrObject) context.ostack[context.ostackPos]) 1264 ._fields[grGetInstructionUnsignedValue(opcode)].ivalue; 1265 context.ostackPos--; 1266 context.pc++; 1267 break; 1268 case fieldLoad_float: 1269 if (!context.ostack[context.ostackPos]) { 1270 raise(context, "NullError"); 1271 break; 1272 } 1273 context.fstackPos++; 1274 if (context.fstackPos == context.fstack.length) 1275 context.fstack.length *= 2; 1276 context.fstack[context.fstackPos] = (cast(GrObject) context.ostack[context.ostackPos]) 1277 ._fields[grGetInstructionUnsignedValue(opcode)].fvalue; 1278 context.ostackPos--; 1279 context.pc++; 1280 break; 1281 case fieldLoad_string: 1282 if (!context.ostack[context.ostackPos]) { 1283 raise(context, "NullError"); 1284 break; 1285 } 1286 context.sstackPos++; 1287 if (context.sstackPos == context.sstack.length) 1288 context.sstack.length *= 2; 1289 context.sstack[context.sstackPos] = (cast(GrObject) context.ostack[context.ostackPos]) 1290 ._fields[grGetInstructionUnsignedValue(opcode)].svalue; 1291 context.ostackPos--; 1292 context.pc++; 1293 break; 1294 case fieldLoad_object: 1295 if (!context.ostack[context.ostackPos]) { 1296 raise(context, "NullError"); 1297 break; 1298 } 1299 context.ostack[context.ostackPos] = (cast(GrObject) context.ostack[context.ostackPos]) 1300 ._fields[grGetInstructionUnsignedValue(opcode)].ovalue; 1301 context.pc++; 1302 break; 1303 case fieldLoad2_int: 1304 context.istackPos++; 1305 if (context.istackPos == context.istack.length) 1306 context.istack.length *= 2; 1307 GrField field = (cast(GrObject) context.ostack[context.ostackPos]) 1308 ._fields[grGetInstructionUnsignedValue(opcode)]; 1309 context.istack[context.istackPos] = field.ivalue; 1310 context.ostack[context.ostackPos] = cast(GrPtr) field; 1311 context.pc++; 1312 break; 1313 case fieldLoad2_float: 1314 context.fstackPos++; 1315 if (context.fstackPos == context.fstack.length) 1316 context.fstack.length *= 2; 1317 GrField field = (cast(GrObject) context.ostack[context.ostackPos]) 1318 ._fields[grGetInstructionUnsignedValue(opcode)]; 1319 context.fstack[context.fstackPos] = field.fvalue; 1320 context.ostack[context.ostackPos] = cast(GrPtr) field; 1321 context.pc++; 1322 break; 1323 case fieldLoad2_string: 1324 context.sstackPos++; 1325 if (context.sstackPos == context.sstack.length) 1326 context.sstack.length *= 2; 1327 GrField field = (cast(GrObject) context.ostack[context.ostackPos]) 1328 ._fields[grGetInstructionUnsignedValue(opcode)]; 1329 context.sstack[context.sstackPos] = field.svalue; 1330 context.ostack[context.ostackPos] = cast(GrPtr) field; 1331 context.pc++; 1332 break; 1333 case fieldLoad2_object: 1334 context.ostackPos++; 1335 if (context.ostackPos == context.ostack.length) 1336 context.ostack.length *= 2; 1337 GrField field = (cast(GrObject) context.ostack[context.ostackPos - 1]) 1338 ._fields[grGetInstructionUnsignedValue(opcode)]; 1339 context.ostack[context.ostackPos] = field.ovalue; 1340 context.ostack[context.ostackPos - 1] = cast(GrPtr) field; 1341 context.pc++; 1342 break; 1343 case const_int: 1344 context.istackPos++; 1345 if (context.istackPos == context.istack.length) 1346 context.istack.length *= 2; 1347 context.istack[context.istackPos] = _bytecode.iconsts[grGetInstructionUnsignedValue( 1348 opcode)]; 1349 context.pc++; 1350 break; 1351 case const_float: 1352 context.fstackPos++; 1353 if (context.fstackPos == context.fstack.length) 1354 context.fstack.length *= 2; 1355 context.fstack[context.fstackPos] = _bytecode.fconsts[grGetInstructionUnsignedValue( 1356 opcode)]; 1357 context.pc++; 1358 break; 1359 case const_bool: 1360 context.istackPos++; 1361 if (context.istackPos == context.istack.length) 1362 context.istack.length *= 2; 1363 context.istack[context.istackPos] = grGetInstructionUnsignedValue(opcode); 1364 context.pc++; 1365 break; 1366 case const_string: 1367 context.sstackPos++; 1368 if (context.sstackPos == context.sstack.length) 1369 context.sstack.length *= 2; 1370 context.sstack[context.sstackPos] = _bytecode.sconsts[grGetInstructionUnsignedValue( 1371 opcode)]; 1372 context.pc++; 1373 break; 1374 case const_meta: 1375 _meta = _bytecode.sconsts[grGetInstructionUnsignedValue(opcode)]; 1376 context.pc++; 1377 break; 1378 case const_null: 1379 context.ostackPos++; 1380 if (context.ostackPos == context.ostack.length) 1381 context.ostack.length *= 2; 1382 context.ostack[context.ostackPos] = null; 1383 context.pc++; 1384 break; 1385 case globalPush_int: 1386 const uint nbParams = grGetInstructionUnsignedValue(opcode); 1387 for (uint i = 1u; i <= nbParams; i++) 1388 _iglobalStackOut ~= context.istack[(context.istackPos - nbParams) + i]; 1389 context.istackPos -= nbParams; 1390 context.pc++; 1391 break; 1392 case globalPush_float: 1393 const uint nbParams = grGetInstructionUnsignedValue(opcode); 1394 for (uint i = 1u; i <= nbParams; i++) 1395 _fglobalStackOut ~= context.fstack[(context.fstackPos - nbParams) + i]; 1396 context.fstackPos -= nbParams; 1397 context.pc++; 1398 break; 1399 case globalPush_string: 1400 const uint nbParams = grGetInstructionUnsignedValue(opcode); 1401 for (uint i = 1u; i <= nbParams; i++) 1402 _sglobalStackOut ~= context.sstack[(context.sstackPos - nbParams) + i]; 1403 context.sstackPos -= nbParams; 1404 context.pc++; 1405 break; 1406 case globalPush_object: 1407 const uint nbParams = grGetInstructionUnsignedValue(opcode); 1408 for (uint i = 1u; i <= nbParams; i++) 1409 _oglobalStackOut ~= context.ostack[(context.ostackPos - nbParams) + i]; 1410 context.ostackPos -= nbParams; 1411 context.pc++; 1412 break; 1413 case globalPop_int: 1414 context.istackPos++; 1415 if (context.istackPos == context.istack.length) 1416 context.istack.length *= 2; 1417 context.istack[context.istackPos] = _iglobalStackIn[$ - 1]; 1418 _iglobalStackIn.length--; 1419 context.pc++; 1420 break; 1421 case globalPop_float: 1422 context.fstackPos++; 1423 if (context.fstackPos == context.fstack.length) 1424 context.fstack.length *= 2; 1425 context.fstack[context.fstackPos] = _fglobalStackIn[$ - 1]; 1426 _fglobalStackIn.length--; 1427 context.pc++; 1428 break; 1429 case globalPop_string: 1430 context.sstackPos++; 1431 if (context.sstackPos == context.sstack.length) 1432 context.sstack.length *= 2; 1433 context.sstack[context.sstackPos] = _sglobalStackIn[$ - 1]; 1434 _sglobalStackIn.length--; 1435 context.pc++; 1436 break; 1437 case globalPop_object: 1438 context.ostackPos++; 1439 if (context.ostackPos == context.ostack.length) 1440 context.ostack.length *= 2; 1441 context.ostack[context.ostackPos] = _oglobalStackIn[$ - 1]; 1442 _oglobalStackIn.length--; 1443 context.pc++; 1444 break; 1445 case equal_int: 1446 context.istackPos--; 1447 context.istack[context.istackPos] = context.istack[context.istackPos] 1448 == context.istack[context.istackPos + 1]; 1449 context.pc++; 1450 break; 1451 case equal_float: 1452 context.istackPos++; 1453 if (context.istackPos == context.istack.length) 1454 context.istack.length *= 2; 1455 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1456 == context.fstack[context.fstackPos]; 1457 context.fstackPos -= 2; 1458 context.pc++; 1459 break; 1460 case equal_string: 1461 context.istackPos++; 1462 if (context.istackPos == context.istack.length) 1463 context.istack.length *= 2; 1464 context.istack[context.istackPos] = context.sstack[context.sstackPos - 1] 1465 == context.sstack[context.sstackPos]; 1466 context.sstackPos -= 2; 1467 context.pc++; 1468 break; 1469 case notEqual_int: 1470 context.istackPos--; 1471 context.istack[context.istackPos] = context.istack[context.istackPos] 1472 != context.istack[context.istackPos + 1]; 1473 context.pc++; 1474 break; 1475 case notEqual_float: 1476 context.istackPos++; 1477 if (context.istackPos == context.istack.length) 1478 context.istack.length *= 2; 1479 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1480 != context.fstack[context.fstackPos]; 1481 context.fstackPos -= 2; 1482 context.pc++; 1483 break; 1484 case notEqual_string: 1485 context.istackPos++; 1486 if (context.istackPos == context.istack.length) 1487 context.istack.length *= 2; 1488 context.istack[context.istackPos] = context.sstack[context.sstackPos - 1] 1489 != context.sstack[context.sstackPos]; 1490 context.sstackPos -= 2; 1491 context.pc++; 1492 break; 1493 case greaterOrEqual_int: 1494 context.istackPos--; 1495 context.istack[context.istackPos] = context.istack[context.istackPos] 1496 >= context.istack[context.istackPos + 1]; 1497 context.pc++; 1498 break; 1499 case greaterOrEqual_float: 1500 context.istackPos++; 1501 if (context.istackPos == context.istack.length) 1502 context.istack.length *= 2; 1503 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1504 >= context.fstack[context.fstackPos]; 1505 context.fstackPos -= 2; 1506 context.pc++; 1507 break; 1508 case lesserOrEqual_int: 1509 context.istackPos--; 1510 context.istack[context.istackPos] = context.istack[context.istackPos] 1511 <= context.istack[context.istackPos + 1]; 1512 context.pc++; 1513 break; 1514 case lesserOrEqual_float: 1515 context.istackPos++; 1516 if (context.istackPos == context.istack.length) 1517 context.istack.length *= 2; 1518 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1519 <= context.fstack[context.fstackPos]; 1520 context.fstackPos -= 2; 1521 context.pc++; 1522 break; 1523 case greater_int: 1524 context.istackPos--; 1525 context.istack[context.istackPos] = context.istack[context.istackPos] 1526 > context.istack[context.istackPos + 1]; 1527 context.pc++; 1528 break; 1529 case greater_float: 1530 context.istackPos++; 1531 if (context.istackPos == context.istack.length) 1532 context.istack.length *= 2; 1533 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1534 > context.fstack[context.fstackPos]; 1535 context.fstackPos -= 2; 1536 context.pc++; 1537 break; 1538 case lesser_int: 1539 context.istackPos--; 1540 context.istack[context.istackPos] = context.istack[context.istackPos] 1541 < context.istack[context.istackPos + 1]; 1542 context.pc++; 1543 break; 1544 case lesser_float: 1545 context.istackPos++; 1546 if (context.istackPos == context.istack.length) 1547 context.istack.length *= 2; 1548 context.istack[context.istackPos] = context.fstack[context.fstackPos - 1] 1549 < context.fstack[context.fstackPos]; 1550 context.fstackPos -= 2; 1551 context.pc++; 1552 break; 1553 case isNonNull_object: 1554 context.istackPos++; 1555 context.istack[context.istackPos] = (context.ostack[context.ostackPos]!is null); 1556 context.ostackPos--; 1557 context.pc++; 1558 break; 1559 case and_int: 1560 context.istackPos--; 1561 context.istack[context.istackPos] = context.istack[context.istackPos] 1562 && context.istack[context.istackPos + 1]; 1563 context.pc++; 1564 break; 1565 case or_int: 1566 context.istackPos--; 1567 context.istack[context.istackPos] = context.istack[context.istackPos] 1568 || context.istack[context.istackPos + 1]; 1569 context.pc++; 1570 break; 1571 case not_int: 1572 context.istack[context.istackPos] = !context.istack[context.istackPos]; 1573 context.pc++; 1574 break; 1575 case add_int: 1576 context.istackPos--; 1577 context.istack[context.istackPos] += context.istack[context.istackPos + 1]; 1578 context.pc++; 1579 break; 1580 case add_float: 1581 context.fstackPos--; 1582 context.fstack[context.fstackPos] += context.fstack[context.fstackPos + 1]; 1583 context.pc++; 1584 break; 1585 case concatenate_string: 1586 context.sstackPos--; 1587 context.sstack[context.sstackPos] ~= context.sstack[context.sstackPos + 1]; 1588 context.pc++; 1589 break; 1590 case substract_int: 1591 context.istackPos--; 1592 context.istack[context.istackPos] -= context.istack[context.istackPos + 1]; 1593 context.pc++; 1594 break; 1595 case substract_float: 1596 context.fstackPos--; 1597 context.fstack[context.fstackPos] -= context.fstack[context.fstackPos + 1]; 1598 context.pc++; 1599 break; 1600 case multiply_int: 1601 context.istackPos--; 1602 context.istack[context.istackPos] *= context.istack[context.istackPos + 1]; 1603 context.pc++; 1604 break; 1605 case multiply_float: 1606 context.fstackPos--; 1607 context.fstack[context.fstackPos] *= context.fstack[context.fstackPos + 1]; 1608 context.pc++; 1609 break; 1610 case divide_int: 1611 if (context.istack[context.istackPos] == 0) { 1612 raise(context, "ZeroDivisionError"); 1613 break; 1614 } 1615 context.istackPos--; 1616 context.istack[context.istackPos] /= context.istack[context.istackPos + 1]; 1617 context.pc++; 1618 break; 1619 case divide_float: 1620 if (context.fstack[context.fstackPos] == 0f) { 1621 raise(context, "ZeroDivisionError"); 1622 break; 1623 } 1624 context.fstackPos--; 1625 context.fstack[context.fstackPos] /= context.fstack[context.fstackPos + 1]; 1626 context.pc++; 1627 break; 1628 case remainder_int: 1629 if (context.istack[context.istackPos] == 0) { 1630 raise(context, "ZeroDivisionError"); 1631 break; 1632 } 1633 context.istackPos--; 1634 context.istack[context.istackPos] %= context.istack[context.istackPos + 1]; 1635 context.pc++; 1636 break; 1637 case remainder_float: 1638 if (context.fstack[context.fstackPos] == 0f) { 1639 raise(context, "ZeroDivisionError"); 1640 break; 1641 } 1642 context.fstackPos--; 1643 context.fstack[context.fstackPos] %= context.fstack[context.fstackPos + 1]; 1644 context.pc++; 1645 break; 1646 case negative_int: 1647 context.istack[context.istackPos] = -context.istack[context.istackPos]; 1648 context.pc++; 1649 break; 1650 case negative_float: 1651 context.fstack[context.fstackPos] = -context.fstack[context.fstackPos]; 1652 context.pc++; 1653 break; 1654 case increment_int: 1655 context.istack[context.istackPos]++; 1656 context.pc++; 1657 break; 1658 case increment_float: 1659 context.fstack[context.fstackPos] += 1f; 1660 context.pc++; 1661 break; 1662 case decrement_int: 1663 context.istack[context.istackPos]--; 1664 context.pc++; 1665 break; 1666 case decrement_float: 1667 context.fstack[context.fstackPos] -= 1f; 1668 context.pc++; 1669 break; 1670 case copy_int: 1671 context.istackPos++; 1672 if (context.istackPos == context.istack.length) 1673 context.istack.length *= 2; 1674 context.istack[context.istackPos] = context.istack[context.istackPos - 1]; 1675 context.pc++; 1676 break; 1677 case copy_float: 1678 context.fstackPos++; 1679 if (context.fstackPos == context.fstack.length) 1680 context.fstack.length *= 2; 1681 context.fstack[context.fstackPos] = context.fstack[context.fstackPos - 1]; 1682 context.pc++; 1683 break; 1684 case copy_string: 1685 context.sstackPos++; 1686 if (context.sstackPos == context.sstack.length) 1687 context.sstack.length *= 2; 1688 context.sstack[context.sstackPos] = context.sstack[context.sstackPos - 1]; 1689 context.pc++; 1690 break; 1691 case copy_object: 1692 context.ostackPos++; 1693 if (context.ostackPos == context.ostack.length) 1694 context.ostack.length *= 2; 1695 context.ostack[context.ostackPos] = context.ostack[context.ostackPos - 1]; 1696 context.pc++; 1697 break; 1698 case swap_int: 1699 swapAt(context.istack, context.istackPos - 1, context.istackPos); 1700 context.pc++; 1701 break; 1702 case swap_float: 1703 swapAt(context.fstack, context.fstackPos - 1, context.fstackPos); 1704 context.pc++; 1705 break; 1706 case swap_string: 1707 swapAt(context.sstack, context.sstackPos - 1, context.sstackPos); 1708 context.pc++; 1709 break; 1710 case swap_object: 1711 swapAt(context.ostack, context.ostackPos - 1, context.ostackPos); 1712 context.pc++; 1713 break; 1714 case setupIterator: 1715 if (context.istack[context.istackPos] < 0) 1716 context.istack[context.istackPos] = 0; 1717 context.istack[context.istackPos]++; 1718 context.pc++; 1719 break; 1720 case return_: 1721 //If another task was killed by an exception, 1722 //we might end up there if the task has just been spawned. 1723 if (context.stackPos < 0 && context.isKilled) { 1724 _contexts.markInternalForRemoval(index); 1725 continue contextsLabel; 1726 } 1727 //Check for deferred calls. 1728 else if (context.callStack[context.stackPos].deferStack.length) { 1729 //Pop the last defer and run it. 1730 context.pc = context.callStack[context.stackPos].deferStack[$ - 1]; 1731 context.callStack[context.stackPos].deferStack.length--; 1732 } 1733 else { 1734 //Then returns to the last context. 1735 context.stackPos--; 1736 context.pc = context.callStack[context.stackPos].retPosition; 1737 context.ilocalsPos -= context.callStack[context.stackPos].ilocalStackSize; 1738 context.flocalsPos -= context.callStack[context.stackPos].flocalStackSize; 1739 context.slocalsPos -= context.callStack[context.stackPos].slocalStackSize; 1740 context.olocalsPos -= context.callStack[context.stackPos].olocalStackSize; 1741 } 1742 break; 1743 case unwind: 1744 //If another task was killed by an exception, 1745 //we might end up there if the task has just been spawned. 1746 if (context.stackPos < 0) { 1747 _contexts.markInternalForRemoval(index); 1748 continue contextsLabel; 1749 } 1750 //Check for deferred calls. 1751 else if (context.callStack[context.stackPos].deferStack.length) { 1752 //Pop the next defer and run it. 1753 context.pc = context.callStack[context.stackPos].deferStack[$ - 1]; 1754 context.callStack[context.stackPos].deferStack.length--; 1755 } 1756 else if (context.isKilled) { 1757 if (context.stackPos) { 1758 //Then returns to the last context without modifying the pc. 1759 context.stackPos--; 1760 context.ilocalsPos 1761 -= context.callStack[context.stackPos].ilocalStackSize; 1762 context.flocalsPos 1763 -= context.callStack[context.stackPos].flocalStackSize; 1764 context.slocalsPos 1765 -= context.callStack[context.stackPos].slocalStackSize; 1766 context.olocalsPos 1767 -= context.callStack[context.stackPos].olocalStackSize; 1768 1769 if (_isDebug) 1770 _debugProfileEnd(); 1771 } 1772 else { 1773 //Every deferred call has been executed, now die. 1774 _contexts.markInternalForRemoval(index); 1775 continue contextsLabel; 1776 } 1777 } 1778 else if (context.isPanicking) { 1779 //An exception has been raised without any try/catch inside the function. 1780 //So all deferred code is run here before searching in the parent function. 1781 if (context.stackPos) { 1782 //Then returns to the last context without modifying the pc. 1783 context.stackPos--; 1784 context.ilocalsPos 1785 -= context.callStack[context.stackPos].ilocalStackSize; 1786 context.flocalsPos 1787 -= context.callStack[context.stackPos].flocalStackSize; 1788 context.slocalsPos 1789 -= context.callStack[context.stackPos].slocalStackSize; 1790 context.olocalsPos 1791 -= context.callStack[context.stackPos].olocalStackSize; 1792 1793 if (_isDebug) 1794 _debugProfileEnd(); 1795 1796 //Exception handler found in the current function, just jump. 1797 if (context.callStack[context.stackPos].exceptionHandlers.length) { 1798 context.pc 1799 = context.callStack[context.stackPos].exceptionHandlers[$ - 1]; 1800 } 1801 } 1802 else { 1803 //Kill the others. 1804 foreach (coroutine; _contexts) { 1805 coroutine.pc = cast(uint)(cast(int) _bytecode.opcodes.length - 1); 1806 coroutine.isKilled = true; 1807 } 1808 _contextsToSpawn.reset(); 1809 1810 //The VM is now panicking. 1811 _isPanicking = true; 1812 _panicMessage = _sglobalStackIn[$ - 1]; 1813 _sglobalStackIn.length--; 1814 1815 //Every deferred call has been executed, now die. 1816 _contexts.markInternalForRemoval(index); 1817 continue contextsLabel; 1818 } 1819 } 1820 else { 1821 //Then returns to the last context. 1822 context.stackPos--; 1823 context.pc = context.callStack[context.stackPos].retPosition; 1824 context.ilocalsPos -= context.callStack[context.stackPos].ilocalStackSize; 1825 context.flocalsPos -= context.callStack[context.stackPos].flocalStackSize; 1826 context.slocalsPos -= context.callStack[context.stackPos].slocalStackSize; 1827 context.olocalsPos -= context.callStack[context.stackPos].olocalStackSize; 1828 1829 if (_isDebug) 1830 _debugProfileEnd(); 1831 } 1832 break; 1833 case defer: 1834 context.callStack[context.stackPos].deferStack ~= context.pc + grGetInstructionSignedValue( 1835 opcode); 1836 context.pc++; 1837 break; 1838 case localStack_int: 1839 const auto istackSize = grGetInstructionUnsignedValue(opcode); 1840 context.callStack[context.stackPos].ilocalStackSize = istackSize; 1841 if ((context.ilocalsPos + istackSize) >= context.ilocalsLimit) 1842 context.doubleIntLocalsStackSize(context.ilocalsPos + istackSize); 1843 context.pc++; 1844 break; 1845 case localStack_float: 1846 const auto fstackSize = grGetInstructionUnsignedValue(opcode); 1847 context.callStack[context.stackPos].flocalStackSize = fstackSize; 1848 if ((context.flocalsPos + fstackSize) >= context.flocalsLimit) 1849 context.doubleFloatLocalsStackSize(context.flocalsPos + fstackSize); 1850 context.pc++; 1851 break; 1852 case localStack_string: 1853 const auto sstackSize = grGetInstructionUnsignedValue(opcode); 1854 context.callStack[context.stackPos].slocalStackSize = sstackSize; 1855 if ((context.slocalsPos + sstackSize) >= context.slocalsLimit) 1856 context.doubleStringLocalsStackSize(context.slocalsPos + sstackSize); 1857 context.pc++; 1858 break; 1859 case localStack_object: 1860 const auto ostackSize = grGetInstructionUnsignedValue(opcode); 1861 context.callStack[context.stackPos].olocalStackSize = ostackSize; 1862 if ((context.olocalsPos + ostackSize) >= context.olocalsLimit) 1863 context.doubleObjectLocalsStackSize(context.olocalsPos + ostackSize); 1864 context.pc++; 1865 break; 1866 case call: 1867 if ((context.stackPos + 1) >= context.callStackLimit) 1868 context.doubleCallStackSize(); 1869 context.ilocalsPos += context.callStack[context.stackPos].ilocalStackSize; 1870 context.flocalsPos += context.callStack[context.stackPos].flocalStackSize; 1871 context.slocalsPos += context.callStack[context.stackPos].slocalStackSize; 1872 context.olocalsPos += context.callStack[context.stackPos].olocalStackSize; 1873 context.callStack[context.stackPos].retPosition = context.pc + 1u; 1874 context.stackPos++; 1875 context.pc = grGetInstructionUnsignedValue(opcode); 1876 break; 1877 case anonymousCall: 1878 if ((context.stackPos + 1) >= context.callStackLimit) 1879 context.doubleCallStackSize(); 1880 context.ilocalsPos += context.callStack[context.stackPos].ilocalStackSize; 1881 context.flocalsPos += context.callStack[context.stackPos].flocalStackSize; 1882 context.slocalsPos += context.callStack[context.stackPos].slocalStackSize; 1883 context.olocalsPos += context.callStack[context.stackPos].olocalStackSize; 1884 context.callStack[context.stackPos].retPosition = context.pc + 1u; 1885 context.stackPos++; 1886 context.pc = cast(uint) context.istack[context.istackPos]; 1887 context.istackPos--; 1888 break; 1889 case primitiveCall: 1890 _calls[grGetInstructionUnsignedValue(opcode)].call(context); 1891 context.pc++; 1892 if (context.blocker) 1893 continue contextsLabel; 1894 break; 1895 case jump: 1896 context.pc += grGetInstructionSignedValue(opcode); 1897 break; 1898 case jumpEqual: 1899 if (context.istack[context.istackPos]) 1900 context.pc++; 1901 else 1902 context.pc += grGetInstructionSignedValue(opcode); 1903 context.istackPos--; 1904 break; 1905 case jumpNotEqual: 1906 if (context.istack[context.istackPos]) 1907 context.pc += grGetInstructionSignedValue(opcode); 1908 else 1909 context.pc++; 1910 context.istackPos--; 1911 break; 1912 case array_int: 1913 GrIntArray ary = new GrIntArray; 1914 const auto arySize = grGetInstructionUnsignedValue(opcode); 1915 for (int i = arySize - 1; i >= 0; i--) 1916 ary.data ~= context.istack[context.istackPos - i]; 1917 context.istackPos -= arySize; 1918 context.ostackPos++; 1919 if (context.ostackPos == context.ostack.length) 1920 context.ostack.length *= 2; 1921 context.ostack[context.ostackPos] = cast(GrPtr) ary; 1922 context.pc++; 1923 break; 1924 case array_float: 1925 GrFloatArray ary = new GrFloatArray; 1926 const auto arySize = grGetInstructionUnsignedValue(opcode); 1927 for (int i = arySize - 1; i >= 0; i--) 1928 ary.data ~= context.fstack[context.fstackPos - i]; 1929 context.fstackPos -= arySize; 1930 context.ostackPos++; 1931 if (context.ostackPos == context.ostack.length) 1932 context.ostack.length *= 2; 1933 context.ostack[context.ostackPos] = cast(GrPtr) ary; 1934 context.pc++; 1935 break; 1936 case array_string: 1937 GrStringArray ary = new GrStringArray; 1938 const auto arySize = grGetInstructionUnsignedValue(opcode); 1939 for (int i = arySize - 1; i >= 0; i--) 1940 ary.data ~= context.sstack[context.sstackPos - i]; 1941 context.sstackPos -= arySize; 1942 context.ostackPos++; 1943 if (context.ostackPos == context.ostack.length) 1944 context.ostack.length *= 2; 1945 context.ostack[context.ostackPos] = cast(GrPtr) ary; 1946 context.pc++; 1947 break; 1948 case array_object: 1949 GrObjectArray ary = new GrObjectArray; 1950 const auto arySize = grGetInstructionUnsignedValue(opcode); 1951 for (int i = arySize - 1; i >= 0; i--) 1952 ary.data ~= context.ostack[context.ostackPos - i]; 1953 context.ostackPos -= arySize; 1954 context.ostackPos++; 1955 if (context.ostackPos == context.ostack.length) 1956 context.ostack.length *= 2; 1957 context.ostack[context.ostackPos] = cast(GrPtr) ary; 1958 context.pc++; 1959 break; 1960 case index_int: 1961 GrIntArray ary = cast(GrIntArray) context.ostack[context.ostackPos]; 1962 auto idx = context.istack[context.istackPos]; 1963 if (idx < 0) { 1964 idx = (cast(int) ary.data.length) + idx; 1965 } 1966 if (idx >= ary.data.length) { 1967 raise(context, "IndexError"); 1968 break; 1969 } 1970 context.ostack[context.ostackPos] = &ary.data[idx]; 1971 context.istackPos--; 1972 context.pc++; 1973 break; 1974 case index_float: 1975 GrFloatArray ary = cast(GrFloatArray) context.ostack[context.ostackPos]; 1976 auto idx = context.istack[context.istackPos]; 1977 if (idx < 0) { 1978 idx = (cast(int) ary.data.length) + idx; 1979 } 1980 if (idx >= ary.data.length) { 1981 raise(context, "IndexError"); 1982 break; 1983 } 1984 context.ostack[context.ostackPos] = &ary.data[idx]; 1985 context.istackPos--; 1986 context.pc++; 1987 break; 1988 case index_string: 1989 GrStringArray ary = cast(GrStringArray) context.ostack[context.ostackPos]; 1990 auto idx = context.istack[context.istackPos]; 1991 if (idx < 0) { 1992 idx = (cast(int) ary.data.length) + idx; 1993 } 1994 if (idx >= ary.data.length) { 1995 raise(context, "IndexError"); 1996 break; 1997 } 1998 context.ostack[context.ostackPos] = &ary.data[idx]; 1999 context.istackPos--; 2000 context.pc++; 2001 break; 2002 case index_object: 2003 GrObjectArray ary = cast(GrObjectArray) context.ostack[context.ostackPos]; 2004 auto idx = context.istack[context.istackPos]; 2005 if (idx < 0) { 2006 idx = (cast(int) ary.data.length) + idx; 2007 } 2008 if (idx >= ary.data.length) { 2009 raise(context, "IndexError"); 2010 break; 2011 } 2012 context.ostack[context.ostackPos] = &ary.data[idx]; 2013 context.istackPos--; 2014 context.pc++; 2015 break; 2016 case index2_int: 2017 GrIntArray ary = cast(GrIntArray) context.ostack[context.ostackPos]; 2018 auto idx = context.istack[context.istackPos]; 2019 if (idx < 0) { 2020 idx = (cast(int) ary.data.length) + idx; 2021 } 2022 if (idx >= ary.data.length) { 2023 raise(context, "IndexError"); 2024 break; 2025 } 2026 context.istack[context.istackPos] = ary.data[idx]; 2027 context.ostackPos--; 2028 context.pc++; 2029 break; 2030 case index2_float: 2031 GrFloatArray ary = cast(GrFloatArray) context.ostack[context.ostackPos]; 2032 auto idx = context.istack[context.istackPos]; 2033 if (idx < 0) { 2034 idx = (cast(int) ary.data.length) + idx; 2035 } 2036 if (idx >= ary.data.length) { 2037 raise(context, "IndexError"); 2038 break; 2039 } 2040 context.fstackPos++; 2041 if (context.fstackPos == context.fstack.length) 2042 context.fstack.length *= 2; 2043 context.istackPos--; 2044 context.ostackPos--; 2045 context.fstack[context.fstackPos] = ary.data[idx]; 2046 context.pc++; 2047 break; 2048 case index2_string: 2049 GrStringArray ary = cast(GrStringArray) context.ostack[context.ostackPos]; 2050 auto idx = context.istack[context.istackPos]; 2051 if (idx < 0) { 2052 idx = (cast(int) ary.data.length) + idx; 2053 } 2054 if (idx >= ary.data.length) { 2055 raise(context, "IndexError"); 2056 break; 2057 } 2058 context.sstackPos++; 2059 if (context.sstackPos == context.sstack.length) 2060 context.sstack.length *= 2; 2061 context.istackPos--; 2062 context.ostackPos--; 2063 context.sstack[context.sstackPos] = ary.data[idx]; 2064 context.pc++; 2065 break; 2066 case index2_object: 2067 GrObjectArray ary = cast(GrObjectArray) context.ostack[context.ostackPos]; 2068 auto idx = context.istack[context.istackPos]; 2069 if (idx < 0) { 2070 idx = (cast(int) ary.data.length) + idx; 2071 } 2072 if (idx >= ary.data.length) { 2073 raise(context, "IndexError"); 2074 break; 2075 } 2076 context.istackPos--; 2077 context.ostack[context.ostackPos] = ary.data[idx]; 2078 context.pc++; 2079 break; 2080 case index3_int: 2081 GrIntArray ary = cast(GrIntArray) context.ostack[context.ostackPos]; 2082 auto idx = context.istack[context.istackPos]; 2083 if (idx < 0) { 2084 idx = (cast(int) ary.data.length) + idx; 2085 } 2086 if (idx >= ary.data.length) { 2087 raise(context, "IndexError"); 2088 break; 2089 } 2090 context.istack[context.istackPos] = ary.data[idx]; 2091 context.ostack[context.ostackPos] = &ary.data[idx]; 2092 context.pc++; 2093 break; 2094 case index3_float: 2095 GrFloatArray ary = cast(GrFloatArray) context.ostack[context.ostackPos]; 2096 auto idx = context.istack[context.istackPos]; 2097 if (idx < 0) { 2098 idx = (cast(int) ary.data.length) + idx; 2099 } 2100 if (idx >= ary.data.length) { 2101 raise(context, "IndexError"); 2102 break; 2103 } 2104 context.istackPos--; 2105 context.fstackPos++; 2106 context.fstack[context.fstackPos] = ary.data[idx]; 2107 context.ostack[context.ostackPos] = &ary.data[idx]; 2108 context.pc++; 2109 break; 2110 case index3_string: 2111 GrStringArray ary = cast(GrStringArray) context.ostack[context.ostackPos]; 2112 auto idx = context.istack[context.istackPos]; 2113 if (idx < 0) { 2114 idx = (cast(int) ary.data.length) + idx; 2115 } 2116 if (idx >= ary.data.length) { 2117 raise(context, "IndexError"); 2118 break; 2119 } 2120 context.istackPos--; 2121 context.sstackPos++; 2122 context.sstack[context.sstackPos] = ary.data[idx]; 2123 context.ostack[context.ostackPos] = &ary.data[idx]; 2124 context.pc++; 2125 break; 2126 case index3_object: 2127 GrObjectArray ary = cast(GrObjectArray) context.ostack[context.ostackPos]; 2128 auto idx = context.istack[context.istackPos]; 2129 if (idx < 0) { 2130 idx = (cast(int) ary.data.length) + idx; 2131 } 2132 if (idx >= ary.data.length) { 2133 raise(context, "IndexError"); 2134 break; 2135 } 2136 context.istackPos--; 2137 context.ostack[context.ostackPos] = &ary.data[idx]; 2138 context.ostackPos++; 2139 context.ostack[context.ostackPos] = ary.data[idx]; 2140 context.pc++; 2141 break; 2142 case length_int: 2143 context.istackPos++; 2144 if (context.istackPos == context.istack.length) 2145 context.istack.length *= 2; 2146 context.istack[context.istackPos] = cast(int)( 2147 (cast(GrIntArray) context.ostack[context.ostackPos]).data.length); 2148 context.ostackPos--; 2149 context.pc++; 2150 break; 2151 case length_float: 2152 context.istackPos++; 2153 if (context.istackPos == context.istack.length) 2154 context.istack.length *= 2; 2155 context.istack[context.istackPos] = cast(int)( 2156 (cast(GrFloatArray) context.ostack[context.ostackPos]).data.length); 2157 context.ostackPos--; 2158 context.pc++; 2159 break; 2160 case length_string: 2161 context.istackPos++; 2162 if (context.istackPos == context.istack.length) 2163 context.istack.length *= 2; 2164 context.istack[context.istackPos] = cast(int)( 2165 (cast(GrStringArray) context.ostack[context.ostackPos]).data.length); 2166 context.ostackPos--; 2167 context.pc++; 2168 break; 2169 case length_object: 2170 context.istackPos++; 2171 if (context.istackPos == context.istack.length) 2172 context.istack.length *= 2; 2173 context.istack[context.istackPos] = cast(int)( 2174 (cast(GrObjectArray) context.ostack[context.ostackPos]).data.length); 2175 context.ostackPos--; 2176 context.pc++; 2177 break; 2178 case concatenate_intArray: 2179 GrIntArray nArray = new GrIntArray; 2180 context.ostackPos--; 2181 nArray.data = (cast(GrIntArray) context.ostack[context.ostackPos]) 2182 .data ~ (cast(GrIntArray) context.ostack[context.ostackPos + 1]).data; 2183 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2184 context.pc++; 2185 break; 2186 case concatenate_floatArray: 2187 GrFloatArray nArray = new GrFloatArray; 2188 context.ostackPos--; 2189 nArray.data = (cast(GrFloatArray) context.ostack[context.ostackPos]) 2190 .data ~ (cast(GrFloatArray) context.ostack[context.ostackPos + 1]).data; 2191 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2192 context.pc++; 2193 break; 2194 case concatenate_stringArray: 2195 GrStringArray nArray = new GrStringArray; 2196 context.ostackPos--; 2197 nArray.data = (cast(GrStringArray) context.ostack[context.ostackPos]) 2198 .data ~ (cast(GrStringArray) context.ostack[context.ostackPos + 1]).data; 2199 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2200 context.pc++; 2201 break; 2202 case concatenate_objectArray: 2203 GrObjectArray nArray = new GrObjectArray; 2204 context.ostackPos--; 2205 nArray.data = (cast(GrObjectArray) context.ostack[context.ostackPos]) 2206 .data ~ (cast(GrObjectArray) context.ostack[context.ostackPos + 1]).data; 2207 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2208 context.pc++; 2209 break; 2210 case append_int: 2211 GrIntArray nArray = new GrIntArray; 2212 nArray.data = (cast(GrIntArray) context.ostack[context.ostackPos]) 2213 .data ~ context.istack[context.istackPos]; 2214 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2215 context.istackPos--; 2216 context.pc++; 2217 break; 2218 case append_float: 2219 GrFloatArray nArray = new GrFloatArray; 2220 nArray.data = (cast(GrFloatArray) context.ostack[context.ostackPos]) 2221 .data ~ context.fstack[context.fstackPos]; 2222 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2223 context.fstackPos--; 2224 context.pc++; 2225 break; 2226 case append_string: 2227 GrStringArray nArray = new GrStringArray; 2228 nArray.data = (cast(GrStringArray) context.ostack[context.ostackPos]) 2229 .data ~ context.sstack[context.sstackPos]; 2230 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2231 context.sstackPos--; 2232 context.pc++; 2233 break; 2234 case append_object: 2235 GrObjectArray nArray = new GrObjectArray; 2236 context.ostackPos--; 2237 nArray.data = (cast(GrObjectArray) context.ostack[context.ostackPos]) 2238 .data ~ context.ostack[context.ostackPos + 1]; 2239 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2240 context.pc++; 2241 break; 2242 case prepend_int: 2243 GrIntArray nArray = new GrIntArray; 2244 nArray.data = context.istack[context.istackPos] ~ ( 2245 cast(GrIntArray) context.ostack[context.ostackPos]).data; 2246 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2247 context.istackPos--; 2248 context.pc++; 2249 break; 2250 case prepend_float: 2251 GrFloatArray nArray = new GrFloatArray; 2252 nArray.data = context.fstack[context.fstackPos] ~ ( 2253 cast(GrFloatArray) context.ostack[context.ostackPos]).data; 2254 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2255 context.fstackPos--; 2256 context.pc++; 2257 break; 2258 case prepend_string: 2259 GrStringArray nArray = new GrStringArray; 2260 nArray.data = context.sstack[context.sstackPos] ~ ( 2261 cast(GrStringArray) context.ostack[context.ostackPos]).data; 2262 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2263 context.sstackPos--; 2264 context.pc++; 2265 break; 2266 case prepend_object: 2267 GrObjectArray nArray = new GrObjectArray; 2268 context.ostackPos--; 2269 nArray.data = context.ostack[context.ostackPos] ~ (cast( 2270 GrObjectArray) context.ostack[context.ostackPos + 1]).data; 2271 context.ostack[context.ostackPos] = cast(GrPtr) nArray; 2272 context.pc++; 2273 break; 2274 case equal_intArray: 2275 context.istackPos++; 2276 if (context.istackPos == context.istack.length) 2277 context.istack.length *= 2; 2278 context.istack[context.istackPos] = (cast(GrIntArray) context.ostack[context.ostackPos - 1]) 2279 .data == (cast(GrIntArray) context.ostack[context.ostackPos]).data; 2280 context.ostackPos -= 2; 2281 context.pc++; 2282 break; 2283 case equal_floatArray: 2284 context.istackPos++; 2285 if (context.istackPos == context.istack.length) 2286 context.istack.length *= 2; 2287 context.istack[context.istackPos] = (cast(GrFloatArray) context.ostack[context.ostackPos - 1]) 2288 .data == (cast(GrFloatArray) context.ostack[context.ostackPos]).data; 2289 context.ostackPos -= 2; 2290 context.pc++; 2291 break; 2292 case equal_stringArray: 2293 context.istackPos++; 2294 if (context.istackPos == context.istack.length) 2295 context.istack.length *= 2; 2296 context.istack[context.istackPos] = (cast(GrStringArray) context.ostack[context.ostackPos - 1]) 2297 .data == (cast(GrStringArray) context.ostack[context.ostackPos]).data; 2298 context.ostackPos -= 2; 2299 context.pc++; 2300 break; 2301 case notEqual_intArray: 2302 context.istackPos++; 2303 if (context.istackPos == context.istack.length) 2304 context.istack.length *= 2; 2305 context.istack[context.istackPos] = (cast(GrIntArray) context.ostack[context.ostackPos - 1]) 2306 .data != (cast(GrIntArray) context.ostack[context.ostackPos]).data; 2307 context.ostackPos -= 2; 2308 context.pc++; 2309 break; 2310 case notEqual_floatArray: 2311 context.istackPos++; 2312 if (context.istackPos == context.istack.length) 2313 context.istack.length *= 2; 2314 context.istack[context.istackPos] = (cast(GrFloatArray) context.ostack[context.ostackPos - 1]) 2315 .data != (cast(GrFloatArray) context.ostack[context.ostackPos]).data; 2316 context.ostackPos -= 2; 2317 context.pc++; 2318 break; 2319 case notEqual_stringArray: 2320 context.istackPos++; 2321 if (context.istackPos == context.istack.length) 2322 context.istack.length *= 2; 2323 context.istack[context.istackPos] = (cast(GrStringArray) context.ostack[context.ostackPos - 1]) 2324 .data != (cast(GrStringArray) context.ostack[context.ostackPos]).data; 2325 context.ostackPos -= 2; 2326 context.pc++; 2327 break; 2328 case debugProfileBegin: 2329 _debugProfileBegin(opcode, context.pc); 2330 context.pc++; 2331 break; 2332 case debugProfileEnd: 2333 _debugProfileEnd(); 2334 context.pc++; 2335 break; 2336 } 2337 } 2338 } 2339 _contexts.sweepMarkedData(); 2340 } 2341 2342 /// Create a new object. 2343 GrObject createObject(string name) { 2344 int index; 2345 for (; index < _bytecode.classes.length; index++) { 2346 if (name == _bytecode.classes[index].name) 2347 return new GrObject(_bytecode.classes[index]); 2348 } 2349 return null; 2350 } 2351 2352 import core.time : MonoTime, Duration; 2353 2354 private { 2355 bool _isDebug; 2356 DebugFunction[int] _debugFunctions; 2357 DebugFunction[] _debugFunctionsStack; 2358 } 2359 2360 /// Runtime information about every called functions 2361 DebugFunction[int] dumpProfiling() { 2362 return _debugFunctions; 2363 } 2364 2365 /// Prettify the result from `dumpProfiling` 2366 string prettifyProfiling() { 2367 import std.algorithm.comparison : max; 2368 import std.conv : to; 2369 2370 string report; 2371 ulong functionNameLength = 10; 2372 ulong countLength = 10; 2373 ulong totalLength = 10; 2374 ulong averageLength = 10; 2375 foreach (func; dumpProfiling()) { 2376 functionNameLength = max(func.name.length, functionNameLength); 2377 countLength = max(to!string(func.count).length, countLength); 2378 totalLength = max(to!string(func.total.total!"msecs").length, totalLength); 2379 Duration average = func.count ? (func.total / func.count) : Duration.zero; 2380 averageLength = max(to!string(average.total!"msecs").length, averageLength); 2381 } 2382 string header = "| " ~ leftJustify("Function", functionNameLength) ~ " | " ~ leftJustify("Count", 2383 countLength) ~ " | " ~ leftJustify("Total", 2384 totalLength) ~ " | " ~ leftJustify("Average", averageLength) ~ " |"; 2385 2386 string separator = "+" ~ leftJustify("", functionNameLength + 2, 2387 '-') ~ "+" ~ leftJustify("", countLength + 2, '-') ~ "+" ~ leftJustify("", 2388 totalLength + 2, '-') ~ "+" ~ leftJustify("", averageLength + 2, '-') ~ "+"; 2389 report ~= separator ~ "\n" ~ header ~ "\n" ~ separator ~ "\n"; 2390 foreach (func; dumpProfiling()) { 2391 Duration average = func.count ? (func.total / func.count) : Duration.zero; 2392 report ~= "| " ~ leftJustify(func.name, functionNameLength) ~ " | " ~ leftJustify( 2393 to!string(func.count), countLength) ~ " | " ~ leftJustify(to!string(func.total.total!"msecs"), 2394 totalLength) ~ " | " ~ leftJustify(to!string(average.total!"msecs"), 2395 averageLength) ~ " |\n"; 2396 } 2397 report ~= separator ~ "\n"; 2398 return report; 2399 } 2400 2401 /// Runtime information of a called function 2402 final class DebugFunction { 2403 private { 2404 MonoTime _start; 2405 Duration _total; 2406 ulong _count; 2407 int _pc; 2408 string _name; 2409 } 2410 2411 @property { 2412 /// Total execution time passed inside the function 2413 Duration total() const { 2414 return _total; 2415 } 2416 /// Total times the function was called 2417 ulong count() const { 2418 return _count; 2419 } 2420 /// Prettified name of the function 2421 string name() const { 2422 return _name; 2423 } 2424 } 2425 } 2426 2427 private void _debugProfileEnd() { 2428 if (!_debugFunctionsStack.length) 2429 return; 2430 auto p = _debugFunctionsStack[$ - 1]; 2431 _debugFunctionsStack.length--; 2432 p._total += MonoTime.currTime() - p._start; 2433 p._count++; 2434 } 2435 2436 private void _debugProfileBegin(uint opcode, int pc) { 2437 _isDebug = true; 2438 auto p = (pc in _debugFunctions); 2439 if (p) { 2440 p._start = MonoTime.currTime(); 2441 _debugFunctionsStack ~= *p; 2442 } 2443 else { 2444 auto debugFunc = new DebugFunction; 2445 debugFunc._pc = pc; 2446 debugFunc._name = _bytecode.sconsts[grGetInstructionUnsignedValue(opcode)]; 2447 debugFunc._start = MonoTime.currTime(); 2448 _debugFunctions[pc] = debugFunc; 2449 _debugFunctionsStack ~= debugFunc; 2450 } 2451 } 2452 }