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 }