diff --git a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs index ab9768ceb7..15ea7f37f8 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs @@ -120,15 +120,13 @@ namespace BizHawk.Emulation.Cores.Waterbox data = File.ReadAllBytes(path); } - var retobj = new ReturnData(); - NativeImpl.wbx_create_host(nativeOpts, opt.Filename, Reader(new MemoryStream(data, false)), IntPtr.Zero, retobj); + NativeImpl.wbx_create_host(nativeOpts, opt.Filename, Reader(new MemoryStream(data, false)), IntPtr.Zero, out var retobj); _nativeHost = retobj.GetDataOrThrow(); } public IntPtr GetProcAddrOrZero(string entryPoint) { - var retobj = new ReturnData(); - NativeImpl.wbx_get_proc_addr_raw(_nativeHost, entryPoint, retobj); + NativeImpl.wbx_get_proc_addr_raw(_nativeHost, entryPoint, out var retobj); return retobj.GetDataOrThrow(); } @@ -147,22 +145,19 @@ namespace BizHawk.Emulation.Cores.Waterbox public IntPtr GetCallbackProcAddr(IntPtr exitPoint, int slot) { - var retobj = new ReturnData(); - NativeImpl.wbx_get_callback_addr(_nativeHost, exitPoint, slot, retobj); + NativeImpl.wbx_get_callback_addr(_nativeHost, exitPoint, slot, out var retobj); return retobj.GetDataOrThrow(); } public IntPtr GetCallinProcAddr(IntPtr entryPoint) { - var retobj = new ReturnData(); - NativeImpl.wbx_get_callin_addr(_nativeHost, entryPoint, retobj); + NativeImpl.wbx_get_callin_addr(_nativeHost, entryPoint, out var retobj); return retobj.GetDataOrThrow(); } public void Seal() { - var retobj = new ReturnData(); - NativeImpl.wbx_seal(_nativeHost, retobj); + NativeImpl.wbx_seal(_nativeHost, out var retobj); retobj.GetDataOrThrow(); Console.WriteLine("WaterboxHost Sealed!"); } @@ -174,8 +169,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// the filename that the unmanaged core will access the file by public void AddReadonlyFile(byte[] data, string name) { - var retobj = new ReturnData(); - NativeImpl.wbx_mount_file(_nativeHost, name, Reader(new MemoryStream(data, false)), IntPtr.Zero, false, retobj); + NativeImpl.wbx_mount_file(_nativeHost, name, Reader(new MemoryStream(data, false)), IntPtr.Zero, false, out var retobj); retobj.GetDataOrThrow(); } @@ -185,8 +179,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// public void RemoveReadonlyFile(string name) { - var retobj = new ReturnData(); - NativeImpl.wbx_unmount_file(_nativeHost, name, null, IntPtr.Zero, retobj); + NativeImpl.wbx_unmount_file(_nativeHost, name, null, IntPtr.Zero, out var retobj); retobj.GetDataOrThrow(); } @@ -196,8 +189,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// public void AddTransientFile(byte[] data, string name) { - var retobj = new ReturnData(); - NativeImpl.wbx_mount_file(_nativeHost, name, Reader(new MemoryStream(data, false)), IntPtr.Zero, true, retobj); + NativeImpl.wbx_mount_file(_nativeHost, name, Reader(new MemoryStream(data, false)), IntPtr.Zero, true, out var retobj); retobj.GetDataOrThrow(); } @@ -207,9 +199,8 @@ namespace BizHawk.Emulation.Cores.Waterbox /// The state of the file when it was removed public byte[] RemoveTransientFile(string name) { - var retobj = new ReturnData(); var ms = new MemoryStream(); - NativeImpl.wbx_unmount_file(_nativeHost, name, Writer(ms), IntPtr.Zero, retobj); + NativeImpl.wbx_unmount_file(_nativeHost, name, Writer(ms), IntPtr.Zero, out var retobj); retobj.GetDataOrThrow(); return ms.ToArray(); } @@ -262,13 +253,13 @@ namespace BizHawk.Emulation.Cores.Waterbox private class WaterboxPagesDomain : MemoryDomain { - protected readonly WaterboxHost _host; + private readonly WaterboxHost _host; + public WaterboxPagesDomain(WaterboxHost host) { _host = host; - var retobj = new ReturnData(); - NativeImpl.wbx_get_page_len(_host._nativeHost, retobj); + NativeImpl.wbx_get_page_len(_host._nativeHost, out var retobj); Name = "Waterbox PageData"; Size = (long)retobj.GetDataOrThrow(); @@ -279,8 +270,7 @@ namespace BizHawk.Emulation.Cores.Waterbox public override byte PeekByte(long addr) { - var retobj = new ReturnData(); - NativeImpl.wbx_get_page_data(_host._nativeHost, Z.SU(addr), retobj); + NativeImpl.wbx_get_page_data(_host._nativeHost, Z.SU(addr), out var retobj); return (byte)retobj.GetDataOrThrow(); } @@ -292,15 +282,13 @@ namespace BizHawk.Emulation.Cores.Waterbox public void SaveStateBinary(BinaryWriter bw) { - var retobj = new ReturnData(); - NativeImpl.wbx_save_state(_nativeHost, Writer(bw.BaseStream), IntPtr.Zero, retobj); + NativeImpl.wbx_save_state(_nativeHost, Writer(bw.BaseStream), IntPtr.Zero, out var retobj); retobj.GetDataOrThrow(); } public void LoadStateBinary(BinaryReader br) { - var retobj = new ReturnData(); - NativeImpl.wbx_load_state(_nativeHost, Reader(br.BaseStream), IntPtr.Zero, retobj); + NativeImpl.wbx_load_state(_nativeHost, Reader(br.BaseStream), IntPtr.Zero, out var retobj); retobj.GetDataOrThrow(); } @@ -308,8 +296,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { if (_enterCount == 0) { - var retobj = new ReturnData(); - NativeImpl.wbx_activate_host(_nativeHost, retobj); + NativeImpl.wbx_activate_host(_nativeHost, out var retobj); retobj.GetDataOrThrow(); } _enterCount++; @@ -317,16 +304,16 @@ namespace BizHawk.Emulation.Cores.Waterbox public void Exit() { - if (_enterCount <= 0) + switch (_enterCount) { - throw new InvalidOperationException(); - } - else if (_enterCount == 1) - { - var retobj = new ReturnData(); - NativeImpl.wbx_deactivate_host(_nativeHost, retobj); - retobj.GetDataOrThrow(); + case <= 0: + throw new InvalidOperationException(); + case 1: + NativeImpl.wbx_deactivate_host(_nativeHost, out var retobj); + retobj.GetDataOrThrow(); + break; } + _enterCount--; } @@ -334,13 +321,12 @@ namespace BizHawk.Emulation.Cores.Waterbox { if (_nativeHost != IntPtr.Zero) { - var retobj = new ReturnData(); if (_enterCount != 0) { - NativeImpl.wbx_deactivate_host(_nativeHost, retobj); + NativeImpl.wbx_deactivate_host(_nativeHost, out _); Console.Error.WriteLine("Warn: Disposed of WaterboxHost which was active"); } - NativeImpl.wbx_destroy_host(_nativeHost, retobj); + NativeImpl.wbx_destroy_host(_nativeHost, out _); _enterCount = 0; _nativeHost = IntPtr.Zero; GC.SuppressFinalize(this); diff --git a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHostNative.cs b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHostNative.cs index 46e7b59070..75ef24948c 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHostNative.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHostNative.cs @@ -6,21 +6,19 @@ using BizHawk.Common; namespace BizHawk.Emulation.Cores.Waterbox { - public unsafe abstract class WaterboxHostNative + public abstract class WaterboxHostNative { - [StructLayout(LayoutKind.Explicit)] - public class ReturnData + [StructLayout(LayoutKind.Sequential)] + public unsafe struct ReturnData { - [FieldOffset(0)] - public byte ErrorMessageStart; - [FieldOffset(1024)] + public fixed byte ErrorMessage[1024]; public IntPtr Data; public IntPtr GetDataOrThrow() { - if (ErrorMessageStart != 0) + if (ErrorMessage[0] != 0) { - fixed(byte* p = &ErrorMessageStart) + fixed (byte* p = ErrorMessage) throw new InvalidOperationException(Mershul.PtrToStringUtf8((IntPtr)p)); } return Data; @@ -73,15 +71,15 @@ namespace BizHawk.Emulation.Cores.Waterbox // public delegate UIntPtr /*MissingFileResult*/ FileCallback(IntPtr userdata, UIntPtr /*string*/ name); - public static WriteCallback MakeCallbackForWriter(Stream s) + public static unsafe WriteCallback MakeCallbackForWriter(Stream s) { var ss = SpanStream.GetOrBuild(s); - return (_unused, data, size) => + return (_, data, size) => { try { var count = (int)size; - ss.Write(new ReadOnlySpan((void*)data, (int)size)); + ss.Write(new((void*)data, (int)size)); return 0; } catch @@ -90,15 +88,15 @@ namespace BizHawk.Emulation.Cores.Waterbox } }; } - public static ReadCallback MakeCallbackForReader(Stream s) + public static unsafe ReadCallback MakeCallbackForReader(Stream s) { var ss = SpanStream.GetOrBuild(s); - return (_unused, data, size) => + return (_, data, size) => { try { var count = (int)size; - var n = ss.Read(new Span((void*)data, count)); + var n = ss.Read(new((void*)data, count)); return Z.SS(n); } catch @@ -124,13 +122,13 @@ namespace BizHawk.Emulation.Cores.Waterbox /// which will not be used after this call. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_create_host(MemoryLayoutTemplate layout, string moduleName, ReadCallback wbx, IntPtr userdata, ReturnData /*WaterboxHost*/ ret); + public abstract void wbx_create_host(MemoryLayoutTemplate layout, string moduleName, ReadCallback wbx, IntPtr userdata, out ReturnData /*WaterboxHost*/ ret); /// /// Tear down a host environment. If called while the environment is active, will deactivate it first. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_destroy_host(IntPtr /*WaterboxHost*/ obj, ReturnData /*void*/ ret); + public abstract void wbx_destroy_host(IntPtr /*WaterboxHost*/ obj, out ReturnData /*void*/ ret); /// /// Activate a host environment. This swaps it into memory and makes it available for use. @@ -139,21 +137,21 @@ namespace BizHawk.Emulation.Cores.Waterbox /// Ignored if host is already active. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_activate_host(IntPtr /*WaterboxHost*/ obj, ReturnData /*void*/ ret); + public abstract void wbx_activate_host(IntPtr /*WaterboxHost*/ obj, out ReturnData /*void*/ ret); /// /// Deactivates a host environment, and releases the mutex. /// Ignored if host is not active /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_deactivate_host(IntPtr /*WaterboxHost*/ obj, ReturnData /*void*/ ret); + public abstract void wbx_deactivate_host(IntPtr /*WaterboxHost*/ obj, out ReturnData /*void*/ ret); /// /// Returns a thunk suitable for calling an exported function from the guest executable. This pointer is only valid /// while the host is active. A missing proc is not an error and simply returns 0. The guest function must be, /// and the returned callback will be, sysv abi, and will only pass up to 6 int/ptr args and no other arg types. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_proc_addr(IntPtr /*WaterboxHost*/ obj, string name, ReturnData /*UIntPtr*/ ret); + public abstract void wbx_get_proc_addr(IntPtr /*WaterboxHost*/ obj, string name, out ReturnData /*UIntPtr*/ ret); /// /// Returns a thunk suitable for calling an arbitrary entry point into the guest executable. This pointer is only valid /// while the host is active. wbx_get_proc_addr already calls this internally on pointers it returns, so this call is @@ -161,14 +159,14 @@ namespace BizHawk.Emulation.Cores.Waterbox /// a pointer to another function). /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_callin_addr(IntPtr /*WaterboxHost*/ obj, IntPtr ptr, ReturnData /*UIntPtr*/ ret); + public abstract void wbx_get_callin_addr(IntPtr /*WaterboxHost*/ obj, IntPtr ptr, out ReturnData /*UIntPtr*/ ret); /// /// Returns the raw address of a function exported from the guest. `wbx_get_proc_addr()` is equivalent to /// `wbx_get_callin_addr(wbx_get_proc_addr_raw()). Most things should not use this directly, as the returned /// pointer will not have proper stack hygiene and will crash on syscalls from the guest. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_proc_addr_raw(IntPtr /*WaterboxHost*/ obj, string name, ReturnData /*UIntPtr*/ ret); + public abstract void wbx_get_proc_addr_raw(IntPtr /*WaterboxHost*/ obj, string name, out ReturnData /*UIntPtr*/ ret); /// /// Returns a function pointer suitable for passing to the guest to allow it to call back while active. /// Slot number is an integer that is used to keep pointers consistent across runs: If the host is loaded @@ -177,12 +175,12 @@ namespace BizHawk.Emulation.Cores.Waterbox /// The returned thunk will be, and the callback must be, sysv abi and will only pass up to 6 int/ptr args and no other arg types. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_callback_addr(IntPtr /*WaterboxHost*/ obj, IntPtr callback, int slot, ReturnData /*UIntPtr*/ ret); + public abstract void wbx_get_callback_addr(IntPtr /*WaterboxHost*/ obj, IntPtr callback, int slot, out ReturnData /*UIntPtr*/ ret); /// /// Calls the seal operation, which is a one time action that prepares the host to save states. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_seal(IntPtr /*WaterboxHost*/ obj, ReturnData /*void*/ ret); + public abstract void wbx_seal(IntPtr /*WaterboxHost*/ obj, out ReturnData /*void*/ ret); /// /// Mounts a file in the environment. All data will be immediately consumed from the reader, which will not be used after this call. @@ -190,7 +188,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// in every savestate, or never appear in any savestates. All savestateable files must be added in the same order for every run. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_mount_file(IntPtr /*WaterboxHost*/ obj, string name, ReadCallback reader, IntPtr userdata, bool writable, ReturnData /*void*/ ret); + public abstract void wbx_mount_file(IntPtr /*WaterboxHost*/ obj, string name, ReadCallback reader, IntPtr userdata, bool writable, out ReturnData /*void*/ ret); /// /// Remove a file previously added. Writer is optional; if provided, the contents of the file at time of removal will be dumped to it. @@ -198,7 +196,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// If the file has been used in savestates, it does not make sense to remove it here, but nothing will stop you. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_unmount_file(IntPtr /*WaterboxHost*/ obj, string name, WriteCallback writer, IntPtr userdata, ReturnData /*void*/ ret); + public abstract void wbx_unmount_file(IntPtr /*WaterboxHost*/ obj, string name, WriteCallback writer, IntPtr userdata, out ReturnData /*void*/ ret); #if false /// @@ -217,7 +215,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// Must always be called with the same sequence and contents of readonly files. /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_save_state(IntPtr /*WaterboxHost*/ obj, WriteCallback writer, IntPtr userdata, ReturnData /*void*/ ret); + public abstract void wbx_save_state(IntPtr /*WaterboxHost*/ obj, WriteCallback writer, IntPtr userdata, out ReturnData /*void*/ ret); /// /// Load state. Must not be called before seal. Must not be called with any writable files mounted. @@ -226,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// Errors generally poison the environment; sorry! /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_load_state(IntPtr /*WaterboxHost*/ obj, ReadCallback reader, IntPtr userdata, ReturnData /*void*/ ret); + public abstract void wbx_load_state(IntPtr /*WaterboxHost*/ obj, ReadCallback reader, IntPtr userdata, out ReturnData /*void*/ ret); /// /// Control whether the host automatically evicts blocks from memory when they are not active. For the best performance, @@ -240,7 +238,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// Retrieve the number of pages of guest memory that this host is tracking /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_page_len(IntPtr /*WaterboxHost*/ obj, ReturnData /*UIntPtr*/ ret); + public abstract void wbx_get_page_len(IntPtr /*WaterboxHost*/ obj, out ReturnData /*UIntPtr*/ ret); /// /// Retrieve basic information for a tracked guest page. Index should be in 0..wbx_get_page_len(). @@ -253,6 +251,6 @@ namespace BizHawk.Emulation.Cores.Waterbox /// 0x80 - dirty /// [BizImport(CallingConvention.Cdecl)] - public abstract void wbx_get_page_data(IntPtr /*WaterboxHost*/ obj, UIntPtr index, ReturnData /*byte*/ ret); + public abstract void wbx_get_page_data(IntPtr /*WaterboxHost*/ obj, UIntPtr index, out ReturnData /*byte*/ ret); } }