2
0
Эх сурвалжийг харах

Improved debugging for MediaMachine.

David Piuva 3 жил өмнө
parent
commit
8341fb0db0

+ 29 - 4
Source/DFPSR/api/mediaMachineAPI.cpp

@@ -54,9 +54,21 @@ public:
 		switch(type) {
 		switch(type) {
 			case DataType_FixedPoint:
 			case DataType_FixedPoint:
 				if (sourceArg.argType == ArgumentType::Immediate) {
 				if (sourceArg.argType == ArgumentType::Immediate) {
+					#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+						printText(U"Storing: FixedPoint[", targetStackIndex, U"] <- immediate ", sourceArg.value, U".\n");
+					#endif
 					this->FixedPointMemory.accessByStackIndex(targetStackIndex) = sourceArg.value;
 					this->FixedPointMemory.accessByStackIndex(targetStackIndex) = sourceArg.value;
 				} else {
 				} else {
-					this->FixedPointMemory.accessByStackIndex(targetStackIndex) = this->FixedPointMemory.accessByGlobalIndex(sourceArg.value.getMantissa(), sourceFramePointer);
+					int globalIndex = sourceArg.value.getMantissa();
+					FixedPoint value = this->FixedPointMemory.accessByGlobalIndex(globalIndex, sourceFramePointer);
+					#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+						if (globalIndex < 0) {
+							printText(U"Storing: FixedPoint[", targetStackIndex, U"] <- FixedPoint[", -(globalIndex + 1), U"] = ", value, U".\n");
+						} else {
+							printText(U"Storing: FixedPoint[", targetStackIndex, U"] <- FixedPoint[fp(", sourceFramePointer, U") + ", globalIndex, U"] = ", value, U".\n");
+						}
+					#endif
+					this->FixedPointMemory.accessByStackIndex(targetStackIndex) = value;
 				}
 				}
 			break;
 			break;
 			case DataType_ImageU8:
 			case DataType_ImageU8:
@@ -71,15 +83,16 @@ public:
 		}
 		}
 	}
 	}
 	void load(int sourceStackIndex, const VMA& targetArg, int targetFramePointer, DataType type) override {
 	void load(int sourceStackIndex, const VMA& targetArg, int targetFramePointer, DataType type) override {
+		int globalIndex = targetArg.value.getMantissa();
 		switch(type) {
 		switch(type) {
 			case DataType_FixedPoint:
 			case DataType_FixedPoint:
-				this->FixedPointMemory.accessByGlobalIndex(targetArg.value.getMantissa(), targetFramePointer) = this->FixedPointMemory.accessByStackIndex(sourceStackIndex);
+				this->FixedPointMemory.accessByGlobalIndex(globalIndex, targetFramePointer) = this->FixedPointMemory.accessByStackIndex(sourceStackIndex);
 			break;
 			break;
 			case DataType_ImageU8:
 			case DataType_ImageU8:
-				this->AlignedImageU8Memory.accessByGlobalIndex(targetArg.value.getMantissa(), targetFramePointer) = this->AlignedImageU8Memory.accessByStackIndex(sourceStackIndex);
+				this->AlignedImageU8Memory.accessByGlobalIndex(globalIndex, targetFramePointer) = this->AlignedImageU8Memory.accessByStackIndex(sourceStackIndex);
 			break;
 			break;
 			case DataType_ImageRgbaU8:
 			case DataType_ImageRgbaU8:
-				this->OrderedImageRgbaU8Memory.accessByGlobalIndex(targetArg.value.getMantissa(), targetFramePointer) = this->OrderedImageRgbaU8Memory.accessByStackIndex(sourceStackIndex);
+				this->OrderedImageRgbaU8Memory.accessByGlobalIndex(globalIndex, targetFramePointer) = this->OrderedImageRgbaU8Memory.accessByStackIndex(sourceStackIndex);
 			break;
 			break;
 			default:
 			default:
 				throwError("Loading element of unhandled type!\n");
 				throwError("Loading element of unhandled type!\n");
@@ -960,18 +973,30 @@ static T& accessOutputByIndex(MemoryPlane<T>& stack, int framePointer, Method& m
 // Set input by argument index
 // Set input by argument index
 //   Indexed arguments are confirmed to be inputs during compilation of the script
 //   Indexed arguments are confirmed to be inputs during compilation of the script
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, int32_t input) {
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, int32_t input) {
+	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+		printText("Input ", inputIndex, " of ", machine->methods[methodIndex].inputCount, " (", machine->methods[methodIndex].locals[inputIndex].name, ") to ", machine->methods[methodIndex].name, " = ", input, "\n");
+	#endif
 	checkMethodIndex(machine, methodIndex);
 	checkMethodIndex(machine, methodIndex);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->FixedPointMemory, machine->memory->current.framePointer[DataType_FixedPoint], machine->methods[methodIndex], DataType_FixedPoint, inputIndex, FixedPoint::fromWhole(input));
 	setInputByIndex(((MediaMemory*)machine->memory.get())->FixedPointMemory, machine->memory->current.framePointer[DataType_FixedPoint], machine->methods[methodIndex], DataType_FixedPoint, inputIndex, FixedPoint::fromWhole(input));
 }
 }
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const FixedPoint& input) {
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const FixedPoint& input) {
+	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+		printText("Input ", inputIndex, " of ", machine->methods[methodIndex].inputCount, " (", machine->methods[methodIndex].locals[inputIndex].name, ") to ", machine->methods[methodIndex].name, " = ", input, "\n");
+	#endif
 	checkMethodIndex(machine, methodIndex);
 	checkMethodIndex(machine, methodIndex);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->FixedPointMemory, machine->memory->current.framePointer[DataType_FixedPoint], machine->methods[methodIndex], DataType_FixedPoint, inputIndex, input);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->FixedPointMemory, machine->memory->current.framePointer[DataType_FixedPoint], machine->methods[methodIndex], DataType_FixedPoint, inputIndex, input);
 }
 }
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const AlignedImageU8& input) {
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const AlignedImageU8& input) {
+	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+		printText("Input ", inputIndex, " of ", machine->methods[methodIndex].inputCount, " (", machine->methods[methodIndex].locals[inputIndex].name, ") to ", machine->methods[methodIndex].name, " = monochrome image of ", image_getWidth(input), "x", image_getHeight(input), " pixels\n");
+	#endif
 	checkMethodIndex(machine, methodIndex);
 	checkMethodIndex(machine, methodIndex);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->AlignedImageU8Memory, machine->memory->current.framePointer[DataType_ImageU8], machine->methods[methodIndex], DataType_ImageU8, inputIndex, input);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->AlignedImageU8Memory, machine->memory->current.framePointer[DataType_ImageU8], machine->methods[methodIndex], DataType_ImageU8, inputIndex, input);
 }
 }
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const OrderedImageRgbaU8& input) {
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const OrderedImageRgbaU8& input) {
+	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+		printText("Input ", inputIndex, " of ", machine->methods[methodIndex].inputCount, " (", machine->methods[methodIndex].locals[inputIndex].name, ") to ", machine->methods[methodIndex].name, " = rgba image of ", image_getWidth(input), "x", image_getHeight(input), " pixels\n");
+	#endif
 	checkMethodIndex(machine, methodIndex);
 	checkMethodIndex(machine, methodIndex);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->OrderedImageRgbaU8Memory, machine->memory->current.framePointer[DataType_ImageRgbaU8], machine->methods[methodIndex], DataType_ImageRgbaU8, inputIndex, input);
 	setInputByIndex(((MediaMemory*)machine->memory.get())->OrderedImageRgbaU8Memory, machine->memory->current.framePointer[DataType_ImageRgbaU8], machine->methods[methodIndex], DataType_ImageRgbaU8, inputIndex, input);
 }
 }

+ 32 - 24
Source/DFPSR/machine/VirtualMachine.cpp

@@ -252,7 +252,7 @@ void VirtualMachine::addReturnInstruction() {
 }
 }
 void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 	if (arguments.length() < 1) {
 	if (arguments.length() < 1) {
-		throwError("Cannot make a call without the name of a method!\n");
+		throwError(U"Cannot make a call without the name of a method!\n");
 	}
 	}
 	// TODO: Allow calling methods that aren't defined yet.
 	// TODO: Allow calling methods that aren't defined yet.
 	int currentMethodIndex = this->methods.length() - 1;
 	int currentMethodIndex = this->methods.length() - 1;
@@ -260,7 +260,7 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 	// Check the total number of arguments
 	// Check the total number of arguments
 	Method* calledMethod = &this->methods[calledMethodIndex];
 	Method* calledMethod = &this->methods[calledMethodIndex];
 	if (arguments.length() - 1 != calledMethod->outputCount + calledMethod->inputCount) {
 	if (arguments.length() - 1 != calledMethod->outputCount + calledMethod->inputCount) {
-		throwError("Wrong argument count to \"", calledMethod->name, "\"! Call arguments should start with the method to call, continue with output references and end with inputs.\n");
+		throwError(U"Wrong argument count to \"", calledMethod->name, U"\"! Call arguments should start with the method to call, continue with output references and end with inputs.\n");
 	}
 	}
 	// Split assembler arguments into separate input and output arguments for machine instructions
 	// Split assembler arguments into separate input and output arguments for machine instructions
 	List<VMA> inputArguments;
 	List<VMA> inputArguments;
@@ -284,16 +284,16 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 		// Output
 		// Output
 		Variable* variable = &calledMethod->locals[a - 1 + calledMethod->inputCount];
 		Variable* variable = &calledMethod->locals[a - 1 + calledMethod->inputCount];
 		if (outputArguments[a].argType != ArgumentType::Reference) {
 		if (outputArguments[a].argType != ArgumentType::Reference) {
-			throwError("Output argument for \"", variable->name, "\" in \"", calledMethod->name, "\" must be a reference to allow writing its result!\n");
+			throwError(U"Output argument for \"", variable->name, U"\" in \"", calledMethod->name, U"\" must be a reference to allow writing its result!\n");
 		} else if (outputArguments[a].dataType != variable->typeDescription->dataType) {
 		} else if (outputArguments[a].dataType != variable->typeDescription->dataType) {
-			throwError("Output argument for \"", variable->name, "\" in \"", calledMethod->name, "\" must have the type \"", variable->typeDescription->name, "\"!\n");
+			throwError(U"Output argument for \"", variable->name, U"\" in \"", calledMethod->name, U"\" must have the type \"", variable->typeDescription->name, U"\"!\n");
 		}
 		}
 	}
 	}
 	for (int a = 1; a < inputArguments.length(); a++) {
 	for (int a = 1; a < inputArguments.length(); a++) {
 		// Input
 		// Input
 		Variable* variable = &calledMethod->locals[a - 1];
 		Variable* variable = &calledMethod->locals[a - 1];
 		if (inputArguments[a].dataType != variable->typeDescription->dataType) {
 		if (inputArguments[a].dataType != variable->typeDescription->dataType) {
-			throwError("Input argument for \"", variable->name, "\" in \"", calledMethod->name, "\" must have the type \"", variable->typeDescription->name, "\"!\n");
+			throwError(U"Input argument for \"", variable->name, U"\" in \"", calledMethod->name, U"\" must have the type \"", variable->typeDescription->name, U"\"!\n");
 		}
 		}
 	}
 	}
 	addMachineWord([](VirtualMachine& machine, PlanarMemory& memory, const List<VMA>& args) {
 	addMachineWord([](VirtualMachine& machine, PlanarMemory& memory, const List<VMA>& args) {
@@ -302,7 +302,7 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 		int oldMethodIndex = memory.current.methodIndex;
 		int oldMethodIndex = memory.current.methodIndex;
 		Method* calledMethod = &machine.methods[calledMethodIndex];
 		Method* calledMethod = &machine.methods[calledMethodIndex];
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
-			printText("Calling \"", calledMethod->name, "\".\n");
+			printText(U"Calling \"", calledMethod->name, U"\".\n");
 		#endif
 		#endif
 		// Calculate new frame pointers
 		// Calculate new frame pointers
 		int32_t newFramePointer[MAX_TYPE_COUNT] = {};
 		int32_t newFramePointer[MAX_TYPE_COUNT] = {};
@@ -310,6 +310,14 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 		for (int t = 0; t < MAX_TYPE_COUNT; t++) {
 		for (int t = 0; t < MAX_TYPE_COUNT; t++) {
 			newFramePointer[t] = memory.current.stackPointer[t];
 			newFramePointer[t] = memory.current.stackPointer[t];
 			newStackPointer[t] = memory.current.stackPointer[t] + machine.methods[calledMethodIndex].count[t];
 			newStackPointer[t] = memory.current.stackPointer[t] + machine.methods[calledMethodIndex].count[t];
+			#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
+				printText(U"Allocating stack memory for type ", t, U".\n");
+				printText(U"    old frame pointer = ", memory.current.framePointer[t], U"\n");
+				printText(U"    old stack pointer = ", memory.current.stackPointer[t], U"\n");
+				printText(U"    needed elements = ", machine.methods[oldMethodIndex].count[t], U"\n");
+				printText(U"    new frame pointer = ", newFramePointer[t], U"\n");
+				printText(U"    new stack pointer = ", newStackPointer[t], U"\n");
+			#endif
 		}
 		}
 		// Assign inputs
 		// Assign inputs
 		for (int a = 1; a < args.length(); a++) {
 		for (int a = 1; a < args.length(); a++) {
@@ -332,7 +340,7 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 		int calledMethodIndex = args[0].value.getMantissa();
 		int calledMethodIndex = args[0].value.getMantissa();
 		Method* calledMethod = &machine.methods[calledMethodIndex];
 		Method* calledMethod = &machine.methods[calledMethodIndex];
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
-			printText("Writing results after call to \"", calledMethod->name, "\":\n");
+			printText(U"Writing results after call to \"", calledMethod->name, U"\":\n");
 		#endif
 		#endif
 		// Assign outputs
 		// Assign outputs
 		for (int a = 1; a < args.length(); a++) {
 		for (int a = 1; a < args.length(); a++) {
@@ -341,11 +349,11 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 			int sourceStackIndex = source->getStackIndex(memory.current.stackPointer[typeIndex]);
 			int sourceStackIndex = source->getStackIndex(memory.current.stackPointer[typeIndex]);
 			memory.load(sourceStackIndex, args[a], memory.current.framePointer[typeIndex], typeIndex);
 			memory.load(sourceStackIndex, args[a], memory.current.framePointer[typeIndex], typeIndex);
 			#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 			#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
-				printText("  ");
+				printText(U"  ");
 				machine.debugArgument(VMA(typeIndex, source->getGlobalIndex()), calledMethodIndex, memory.current.stackPointer, false);
 				machine.debugArgument(VMA(typeIndex, source->getGlobalIndex()), calledMethodIndex, memory.current.stackPointer, false);
-				printText(" -> ");
+				printText(U" -> ");
 				machine.debugArgument(args[a], memory.current.methodIndex, memory.current.framePointer, false);
 				machine.debugArgument(args[a], memory.current.methodIndex, memory.current.framePointer, false);
-				printText("\n");
+				printText(U"\n");
 			#endif
 			#endif
 		}
 		}
 		// TODO: Decrease reference counts for images by zeroing memory above the new stack-pointer
 		// TODO: Decrease reference counts for images by zeroing memory above the new stack-pointer
@@ -360,12 +368,12 @@ void VirtualMachine::addCallInstructions(const List<String>& arguments) {
 
 
 void VirtualMachine::interpretMachineWord(const ReadableString& command, const List<String>& arguments) {
 void VirtualMachine::interpretMachineWord(const ReadableString& command, const List<String>& arguments) {
 	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 	#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
-		printText("interpretMachineWord @", this->machineWords.length(), " ", command, "(");
+		printText(U"interpretMachineWord @", this->machineWords.length(), U" ", command, U"(");
 		for (int a = 0; a < arguments.length(); a++) {
 		for (int a = 0; a < arguments.length(); a++) {
-			if (a > 0) { printText(", "); }
+			if (a > 0) { printText(U", "); }
 			printText(getArg(arguments, a));
 			printText(getArg(arguments, a));
 		}
 		}
-		printText(")\n");
+		printText(U")\n");
 	#endif
 	#endif
 	if (string_caseInsensitiveMatch(command, U"Begin")) {
 	if (string_caseInsensitiveMatch(command, U"Begin")) {
 		if (this->methods.length() == 1) {
 		if (this->methods.length() == 1) {
@@ -407,7 +415,7 @@ void VirtualMachine::executeMethod(int methodIndex) {
 	#ifdef VIRTUAL_MACHINE_PROFILE
 	#ifdef VIRTUAL_MACHINE_PROFILE
 		if (rootMethod->instructionCount < 1) {
 		if (rootMethod->instructionCount < 1) {
 			// TODO: Assert that each method ends with a return or jump instruction after compiling
 			// TODO: Assert that each method ends with a return or jump instruction after compiling
-			printText("Cannot call \"", rootMethod->name, "\", because it doesn't have any instructions.\n");
+			printText(U"Cannot call \"", rootMethod->name, U"\", because it doesn't have any instructions.\n");
 			return;
 			return;
 		}
 		}
 	#endif
 	#endif
@@ -425,7 +433,7 @@ void VirtualMachine::executeMethod(int methodIndex) {
 		this->debugPrintMemory();
 		this->debugPrintMemory();
 	#endif
 	#endif
 	#ifdef VIRTUAL_MACHINE_PROFILE
 	#ifdef VIRTUAL_MACHINE_PROFILE
-		printText("Calling \"", rootMethod->name, "\":\n");
+		printText(U"Calling \"", rootMethod->name, U"\":\n");
 		double startTime = time_getSeconds();
 		double startTime = time_getSeconds();
 	#endif
 	#endif
 
 
@@ -435,7 +443,7 @@ void VirtualMachine::executeMethod(int methodIndex) {
 		if (pc < 0 || pc >= this->machineWords.length()) {
 		if (pc < 0 || pc >= this->machineWords.length()) {
 			// Return statements will set the program counter to -1 if there are no more callers saved in the stack
 			// Return statements will set the program counter to -1 if there are no more callers saved in the stack
 			if (pc != -1) {
 			if (pc != -1) {
-				throwError("Unexpected program counter! @", pc, " outside of 0..", (this->machineWords.length() - 1), "\n");
+				throwError(U"Unexpected program counter! @", pc, U" outside of 0..", (this->machineWords.length() - 1), U"\n");
 			}
 			}
 			break;
 			break;
 		}
 		}
@@ -443,37 +451,37 @@ void VirtualMachine::executeMethod(int methodIndex) {
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 			const InsSig* signature = getMachineInstructionFromFunction(word->operation);
 			const InsSig* signature = getMachineInstructionFromFunction(word->operation);
 			if (signature) {
 			if (signature) {
-				printText("Executing @", pc, " ", signature->name, "(");
+				printText(U"Executing @", pc, U" ", signature->name, U"(");
 				for (int a = signature->targetCount; a < word->args.length(); a++) {
 				for (int a = signature->targetCount; a < word->args.length(); a++) {
 					if (a > signature->targetCount) {
 					if (a > signature->targetCount) {
-						printText(", ");
+						printText(U", ");
 					}
 					}
 					debugArgument(word->args[a], this->memory->current.methodIndex, this->memory->current.framePointer, false);
 					debugArgument(word->args[a], this->memory->current.methodIndex, this->memory->current.framePointer, false);
 				}
 				}
-				printText(")");
+				printText(U")");
 			}
 			}
 			word->operation(*this, *(this->memory.get()), word->args);
 			word->operation(*this, *(this->memory.get()), word->args);
 			if (signature) {
 			if (signature) {
 				if (signature->targetCount > 0) {
 				if (signature->targetCount > 0) {
-					printText(" -> ");
+					printText(U" -> ");
 					for (int a = 0; a < signature->targetCount; a++) {
 					for (int a = 0; a < signature->targetCount; a++) {
 						if (a > 0) {
 						if (a > 0) {
-							printText(", ");
+							printText(U", ");
 						}
 						}
 						debugArgument(word->args[a], this->memory->current.methodIndex, this->memory->current.framePointer, true);
 						debugArgument(word->args[a], this->memory->current.methodIndex, this->memory->current.framePointer, true);
 					}
 					}
 				}
 				}
 			}
 			}
-			printText("\n");
+			printText(U"\n");
 		#else
 		#else
 			word->operation(*this, *(this->memory.get()), word->args);
 			word->operation(*this, *(this->memory.get()), word->args);
 		#endif
 		#endif
 	}
 	}
 	#ifdef VIRTUAL_MACHINE_PROFILE
 	#ifdef VIRTUAL_MACHINE_PROFILE
 		double endTime = time_getSeconds();
 		double endTime = time_getSeconds();
-		printText("Done calling \"", rootMethod->name, "\" after ", (endTime - startTime) * 1000000.0, " microseconds.\n");
+		printText(U"Done calling \"", rootMethod->name, U"\" after ", (endTime - startTime) * 1000000.0, U" microseconds.\n");
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
 		#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
-			printText(" (debug prints are active)\n");
+			printText(U" (debug prints are active)\n");
 		#endif
 		#endif
 	#endif
 	#endif
 }
 }

+ 22 - 19
Source/DFPSR/machine/VirtualMachine.h

@@ -36,7 +36,8 @@
 
 
 namespace dsr {
 namespace dsr {
 
 
-#define MAX_TYPE_COUNT 4
+// TODO: Can this be a template argument?
+#define MAX_TYPE_COUNT 3
 
 
 // Forward declarations
 // Forward declarations
 struct VirtualMachine;
 struct VirtualMachine;
@@ -122,8 +123,9 @@ struct MemoryPlane {
 	T& accessByStackIndex(int32_t stackIndex) {
 	T& accessByStackIndex(int32_t stackIndex) {
 		return this->stack[stackIndex];
 		return this->stack[stackIndex];
 	}
 	}
+	// globalIndex uses the negative values starting from -1 to access global memory, and from 0 and up to access local variables on top of the type's own frame pointer.
 	T& accessByGlobalIndex(int32_t globalIndex, int32_t framePointer) {
 	T& accessByGlobalIndex(int32_t globalIndex, int32_t framePointer) {
-		int32_t stackIndex = globalIndex < 0 ? -(globalIndex + 1) : framePointer + globalIndex;
+		int32_t stackIndex = (globalIndex < 0) ? -(globalIndex + 1) : (framePointer + globalIndex);
 		return this->stack[stackIndex];
 		return this->stack[stackIndex];
 	}
 	}
 	T& getRef(const VMA& arg, int32_t framePointer) {
 	T& getRef(const VMA& arg, int32_t framePointer) {
@@ -226,7 +228,7 @@ struct Method {
 	String name;
 	String name;
 
 
 	// Global instruction space
 	// Global instruction space
-	const int32_t startAddress; // Index to machineWords
+	const int32_t startAddress = 0; // Index to machineWords
 	int32_t instructionCount = 0; // Number of machine words (safer than return statements in case of memory corruption)
 	int32_t instructionCount = 0; // Number of machine words (safer than return statements in case of memory corruption)
 
 
 	// Unified local space
 	// Unified local space
@@ -357,12 +359,12 @@ struct VirtualMachine {
 				if (typeDefinition) {
 				if (typeDefinition) {
 					typeDefinition->debugPrinter(*(this->memory.get()), *variable, globalIndex, framePointer, fullContent);
 					typeDefinition->debugPrinter(*(this->memory.get()), *variable, globalIndex, framePointer, fullContent);
 					if (globalIndex < 0) {
 					if (globalIndex < 0) {
-						printText(" @gi(", globalIndex, ")");
+						printText(U" @gi(", globalIndex, U")");
 					} else {
 					} else {
-						printText(" @gi(", globalIndex, ")+fp(", framePointer[typeDefinition->dataType], ")");
+						printText(U" @gi(", globalIndex, U") + fp(", framePointer[typeDefinition->dataType], U")");
 					}
 					}
 				} else {
 				} else {
-					printText("?");
+					printText(U"?");
 				}
 				}
 			}
 			}
 		}
 		}
@@ -370,35 +372,36 @@ struct VirtualMachine {
 			Method* method = &this->methods[methodIndex];
 			Method* method = &this->methods[methodIndex];
 			for (int i = 0; i < method->locals.length(); i++) {
 			for (int i = 0; i < method->locals.length(); i++) {
 				Variable* variable = &method->locals[i];
 				Variable* variable = &method->locals[i];
-				printText(indentation, "* ", getName(variable->access), " ");
+				printText(indentation, U"* ", getName(variable->access), U" ");
 				const VMTypeDef* typeDefinition = getMachineType(variable->typeDescription->dataType);
 				const VMTypeDef* typeDefinition = getMachineType(variable->typeDescription->dataType);
 				if (typeDefinition) {
 				if (typeDefinition) {
 					typeDefinition->debugPrinter(*(this->memory.get()), *variable, variable->getGlobalIndex(), framePointer, false);
 					typeDefinition->debugPrinter(*(this->memory.get()), *variable, variable->getGlobalIndex(), framePointer, false);
 				} else {
 				} else {
-					printText("?");
+					printText(U"?");
 				}
 				}
-				printText("\n");
+				printText(U"\n");
 			}
 			}
 		}
 		}
-		void debugPrintMethod(int methodIndex, int32_t* framePointer, const ReadableString& indentation) {
+		void debugPrintMethod(int methodIndex, int32_t* framePointer, int32_t* stackPointer, const ReadableString& indentation) {
 			printText("  ", this->methods[methodIndex].name, ":\n");
 			printText("  ", this->methods[methodIndex].name, ":\n");
 			for (int t = 0; t < this->machineTypeCount; t++) {
 			for (int t = 0; t < this->machineTypeCount; t++) {
-				printText("    FramePointer[", t, "] = ", framePointer[t], " Count[", t, "] = ", this->methods[methodIndex].count[t], "\n");
+				printText(U"    FramePointer[", t, "] = ", framePointer[t], U" Count[", t, "] = ", this->methods[methodIndex].count[t], U" StackPointer[", t, "] = ", stackPointer[t], U"\n");
 			}
 			}
 			debugPrintVariables(methodIndex, framePointer, indentation);
 			debugPrintVariables(methodIndex, framePointer, indentation);
-			printText("\n");
+			printText(U"\n");
 		}
 		}
 		void debugPrintMemory() {
 		void debugPrintMemory() {
 			int methodIndex = this->memory->current.methodIndex;
 			int methodIndex = this->memory->current.methodIndex;
-			printText("\nMemory:\n");
-			if (methodIndex > 0) {
-				int32_t globalFramePointer[MAX_TYPE_COUNT] = {};
-				debugPrintMethod(0, globalFramePointer, U"    ");
-			}
+			printText(U"\nMemory:\n");
+			// Global memory is at the bottom of the stack.
+			int32_t globalFramePointer[MAX_TYPE_COUNT] = {};
+			debugPrintMethod(0, globalFramePointer, this->methods[0].count, U"    ");
+			// Stack memory for each calling method.
 			for (int i = 0; i < memory->callStack.length(); i++) {
 			for (int i = 0; i < memory->callStack.length(); i++) {
-				debugPrintMethod(memory->callStack[i].methodIndex, memory->callStack[i].framePointer, U"    ");
+				debugPrintMethod(memory->callStack[i].methodIndex, memory->callStack[i].framePointer, memory->callStack[i].stackPointer, U"    ");
 			}
 			}
-			debugPrintMethod(methodIndex, this->memory->current.framePointer, U"    ");
+			// Stack memory for the current method, which is not in the call stack because that would be slow to access.
+			debugPrintMethod(methodIndex, this->memory->current.framePointer, this->memory->current.stackPointer, U"    ");
 		}
 		}
 	#endif
 	#endif
 	void executeMethod(int methodIndex);
 	void executeMethod(int methodIndex);