private static void OutputString(IntPtr bufferPtr, int size) { byte[] data = new byte[size]; Marshal.Copy(bufferPtr, data, 0, size); string str = Encoding.UTF8.GetString(data); _runtimeServices.Output(str); }
public void ExecuteFunctionTopLevel(string functionName) { if (_loading) { throw new InvalidOperationException("Cannot call ExecuteFunctionTopLevel before calling FinalizeLoad"); } try { Function function = _loadedFunctions[functionName]; byte[] code = function.Code; int ip = 0; bool executing = true; var operandStack = new Stack <int>(); int stackBottom = _stackOffset; int stackTop = stackBottom; GrowStack(ref stackTop, function.LocalSize); while (executing) { int nextIP = ip + 1; OpCodes opcode = (OpCodes)code[ip]; switch (opcode) { case OpCodes.Ret: executing = false; break; case OpCodes.Branch: { nextIP = BitConverter.ToInt32(code, ip + 1); } break; case OpCodes.BranchIfFalse: { nextIP = ip + 5; int value = operandStack.Pop(); if (value == 0) { nextIP = BitConverter.ToInt32(code, ip + 1); } } break; case OpCodes.LoadIntegerImmediate: { int value = BitConverter.ToInt32(code, ip + 1); operandStack.Push(value); nextIP = ip + 5; } break; case OpCodes.LoadLocalAddress: { byte localIndex = code[ip + 1]; int localAddress = stackBottom + function.LocalOffsets[localIndex]; operandStack.Push(localAddress); nextIP = ip + 2; } break; case OpCodes.LoadStaticAddress: { int staticAddress = BitConverter.ToInt32(code, ip + 1); operandStack.Push(staticAddress); nextIP = ip + 5; } break; case OpCodes.StoreInteger: case OpCodes.StorePointer: { int value = operandStack.Pop(), address = operandStack.Pop(); #if LOG_MEMORY_ACCESS Log.WriteLine($"{opcode} {value} at {address}"); #endif DataHelpers.WriteIntToByteArray(value, _memory, address); string message = $"Stored {value} at {address}"; } break; case OpCodes.DerefInteger: case OpCodes.DerefPointer: { int address = operandStack.Pop(); int value = BitConverter.ToInt32(_memory, address); #if LOG_MEMORY_ACCESS Log.WriteLine($"{opcode} {value} from {address}"); #endif operandStack.Push(value); } break; case OpCodes.Add: case OpCodes.Subtract: case OpCodes.Multiply: case OpCodes.Divide: case OpCodes.And: case OpCodes.Or: case OpCodes.Xor: case OpCodes.Gt: case OpCodes.Gte: case OpCodes.Lt: case OpCodes.Lte: case OpCodes.Eq: case OpCodes.Neq: { int rhs = operandStack.Pop(); int lhs = operandStack.Pop(); int result = 0; switch (opcode) { case OpCodes.Add: result = lhs + rhs; break; case OpCodes.Subtract: result = lhs - rhs; break; case OpCodes.Multiply: result = lhs * rhs; break; case OpCodes.Divide: result = lhs / rhs; break; case OpCodes.And: result = lhs & rhs; break; case OpCodes.Or: result = lhs | rhs; break; case OpCodes.Xor: result = lhs ^ rhs; break; case OpCodes.Gt: result = (lhs > rhs) ? 1 : 0; break; case OpCodes.Gte: result = (lhs >= rhs) ? 1 : 0; break; case OpCodes.Lt: result = (lhs < rhs) ? 1 : 0; break; case OpCodes.Lte: result = (lhs <= rhs) ? 1 : 0; break; case OpCodes.Eq: result = (lhs == rhs) ? 1 : 0; break; case OpCodes.Neq: result = (lhs != rhs) ? 1 : 0; break; } operandStack.Push(result); } break; case OpCodes.Dup: { int value = operandStack.Pop(); operandStack.Push(value); operandStack.Push(value); } break; case OpCodes.Swap: { int top = operandStack.Pop(), next = operandStack.Pop(); operandStack.Push(top); operandStack.Push(next); } break; case OpCodes.ExchangeBytes_TEMP: { int size = operandStack.Pop(), address1 = operandStack.Pop(), address2 = operandStack.Pop(); int tempAddress = stackTop; GrowStack(ref stackTop, size); CopyBytes(address1, tempAddress, size); CopyBytes(address2, address1, size); CopyBytes(tempAddress, address2, size); GrowStack(ref stackTop, -size); } break; case OpCodes.OutputString_TEMP: { int size = operandStack.Pop(); int stringBufferAddress = operandStack.Pop(); #if LOG_MEMORY_ACCESS Log.WriteLine($"OutputString with {size} bytes from {stringBufferAddress}"); #endif string str = Encoding.UTF8.GetString(_memory, stringBufferAddress, size); _runtimeServices.Output(str); } break; case OpCodes.CopyBytes_TEMP: { int size = operandStack.Pop(), toAddress = operandStack.Pop(), fromAddress = operandStack.Pop(); CopyBytes(fromAddress, toAddress, size); } break; case OpCodes.Alloc_TEMP: { int size = operandStack.Pop(); size = Math.Max(1, size).RoundUpToNearest(4); if (_heapOffset + size <= _memory.Length) { operandStack.Push(_heapOffset); _heapOffset += size; } else { throw new InvalidOperationException("Ran out of heap memory"); } } break; case OpCodes.Output_TEMP: { int value = operandStack.Pop(); _runtimeServices.Output(value.ToString()); } break; default: throw new NotSupportedException("Invalid opcode: " + opcode); } ip = nextIP; } } catch (Exception) { } }
private static void OutputBool(bool value) { _runtimeServices.Output(value ? "true" : "false"); }