Skip to content

Commit 7b25d7f

Browse files
TIHancartermp
authored andcommitted
Use MemoryMappedFile API instead of p/invoke win32 calls (#7944)
* Remove win32 mmf calls. Use .NET MemoryMappedFile API instead * Use DangerousGetHandle as it's an implementation detail * minor cleanup
1 parent 2fbd4d8 commit 7b25d7f

File tree

1 file changed

+21
-133
lines changed

1 file changed

+21
-133
lines changed

src/absil/ilread.fs

Lines changed: 21 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ open System.Collections.Concurrent
1414
open System.Collections.Generic
1515
open System.Diagnostics
1616
open System.IO
17+
open System.IO.MemoryMappedFiles
1718
open System.Runtime.InteropServices
1819
open System.Text
1920
open Internal.Utilities
@@ -184,124 +185,6 @@ type RawMemoryFile(fileName: string, obj: obj, addr: nativeint, length: int) =
184185
interface BinaryFile with
185186
override __.GetView() = view :>_
186187

187-
/// Read from memory mapped files.
188-
module MemoryMapping =
189-
190-
type HANDLE = nativeint
191-
type ADDR = nativeint
192-
type SIZE_T = nativeint
193-
194-
[<DllImport("kernel32", SetLastError=true)>]
195-
extern bool CloseHandle (HANDLE _handler)
196-
197-
[<DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)>]
198-
extern HANDLE CreateFile (string _lpFileName,
199-
int _dwDesiredAccess,
200-
int _dwShareMode,
201-
HANDLE _lpSecurityAttributes,
202-
int _dwCreationDisposition,
203-
int _dwFlagsAndAttributes,
204-
HANDLE _hTemplateFile)
205-
206-
[<DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)>]
207-
extern HANDLE CreateFileMapping (HANDLE _hFile,
208-
HANDLE _lpAttributes,
209-
int _flProtect,
210-
int _dwMaximumSizeLow,
211-
int _dwMaximumSizeHigh,
212-
string _lpName)
213-
214-
[<DllImport("kernel32", SetLastError=true)>]
215-
extern ADDR MapViewOfFile (HANDLE _hFileMappingObject,
216-
int _dwDesiredAccess,
217-
int _dwFileOffsetHigh,
218-
int _dwFileOffsetLow,
219-
SIZE_T _dwNumBytesToMap)
220-
221-
[<DllImport("kernel32", SetLastError=true)>]
222-
extern bool UnmapViewOfFile (ADDR _lpBaseAddress)
223-
224-
let INVALID_HANDLE = new IntPtr(-1)
225-
let MAP_READ = 0x0004
226-
let GENERIC_READ = 0x80000000
227-
let NULL_HANDLE = IntPtr.Zero
228-
let FILE_SHARE_NONE = 0x0000
229-
let FILE_SHARE_READ = 0x0001
230-
let FILE_SHARE_WRITE = 0x0002
231-
let FILE_SHARE_READ_WRITE = 0x0003
232-
let CREATE_ALWAYS = 0x0002
233-
let OPEN_EXISTING = 0x0003
234-
let OPEN_ALWAYS = 0x0004
235-
236-
/// A view over a raw pointer to memory given by a memory mapped file.
237-
/// NOTE: we should do more checking of validity here.
238-
type MemoryMapView(start: nativeint) =
239-
inherit BinaryView()
240-
241-
override m.ReadByte i =
242-
Marshal.ReadByte(start + nativeint i)
243-
244-
override m.ReadBytes i n =
245-
let res = Bytes.zeroCreate n
246-
Marshal.Copy(start + nativeint i, res, 0, n)
247-
res
248-
249-
override m.ReadInt32 i =
250-
Marshal.ReadInt32(start + nativeint i)
251-
252-
override m.ReadUInt16 i =
253-
uint16(Marshal.ReadInt16(start + nativeint i))
254-
255-
override m.CountUtf8String i =
256-
let pStart = start + nativeint i
257-
let mutable p = start
258-
while Marshal.ReadByte p <> 0uy do
259-
p <- p + 1n
260-
int (p - pStart)
261-
262-
override m.ReadUTF8String i =
263-
let n = m.CountUtf8String i
264-
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(start + nativeint i, n)
265-
266-
/// Memory maps a file and creates a single view over the entirety of its contents. The
267-
/// lock on the file is only released when the object is disposed.
268-
/// For memory mapping we currently take one view and never release it.
269-
[<DebuggerDisplay("{FileName}")>]
270-
type MemoryMapFile(fileName: string, view: MemoryMapView, hMap: MemoryMapping.HANDLE, hView: nativeint) =
271-
272-
do stats.memoryMapFileOpenedCount <- stats.memoryMapFileOpenedCount + 1
273-
let mutable closed = false
274-
static member Create fileName =
275-
let hFile = MemoryMapping.CreateFile (fileName, MemoryMapping.GENERIC_READ, MemoryMapping.FILE_SHARE_READ_WRITE, IntPtr.Zero, MemoryMapping.OPEN_EXISTING, 0, IntPtr.Zero )
276-
if hFile.Equals MemoryMapping.INVALID_HANDLE then
277-
failwithf "CreateFile(0x%08x)" (Marshal.GetHRForLastWin32Error())
278-
let protection = 0x00000002
279-
let hMap = MemoryMapping.CreateFileMapping (hFile, IntPtr.Zero, protection, 0, 0, null )
280-
ignore(MemoryMapping.CloseHandle hFile)
281-
if hMap.Equals MemoryMapping.NULL_HANDLE then
282-
failwithf "CreateFileMapping(0x%08x)" (Marshal.GetHRForLastWin32Error())
283-
284-
let hView = MemoryMapping.MapViewOfFile (hMap, MemoryMapping.MAP_READ, 0, 0, 0n)
285-
286-
if hView.Equals IntPtr.Zero then
287-
failwithf "MapViewOfFile(0x%08x)" (Marshal.GetHRForLastWin32Error())
288-
289-
let view = MemoryMapView hView
290-
291-
MemoryMapFile(fileName, view, hMap, hView)
292-
293-
member __.FileName = fileName
294-
295-
member __.Close() =
296-
stats.memoryMapFileClosedCount <- stats.memoryMapFileClosedCount + 1
297-
if not closed then
298-
closed <- true
299-
MemoryMapping.UnmapViewOfFile hView |> ignore
300-
MemoryMapping.CloseHandle hMap |> ignore
301-
302-
interface BinaryFile with
303-
override __.GetView() = (view :> BinaryView)
304-
305188
/// Read file from memory blocks
306189
type ByteView(bytes: byte[]) =
307190
inherit BinaryView()
@@ -3989,19 +3872,24 @@ let createByteFileChunk opts fileName chunk =
39893872
| Some (start, length) -> File.ReadBinaryChunk(fileName, start, length)
39903873
ByteFile(fileName, bytes) :> BinaryFile
39913874

3992-
let tryMemoryMapWholeFile opts fileName =
3993-
let file =
3994-
try
3995-
MemoryMapFile.Create fileName :> BinaryFile
3996-
with _ ->
3997-
createByteFileChunk opts fileName None
3998-
let disposer =
3999-
{ new IDisposable with
4000-
member __.Dispose() =
4001-
match file with
4002-
| :? MemoryMapFile as m -> m.Close() // Note that the PE file reader is not required after this point for metadata-only reading
4003-
| _ -> () }
4004-
disposer, file
3875+
let createMemoryMapFile fileName =
3876+
let mmf, accessor, length =
3877+
let fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)
3878+
let length = fileStream.Length
3879+
let mmf = MemoryMappedFile.CreateFromFile(fileStream, null, length, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen=false)
3880+
mmf, mmf.CreateViewAccessor(0L, fileStream.Length, MemoryMappedFileAccess.Read), length
3881+
let safeHolder =
3882+
{ new obj() with
3883+
override x.Finalize() =
3884+
(x :?> IDisposable).Dispose()
3885+
interface IDisposable with
3886+
member x.Dispose() =
3887+
GC.SuppressFinalize x
3888+
accessor.Dispose()
3889+
mmf.Dispose()
3890+
stats.memoryMapFileClosedCount <- stats.memoryMapFileClosedCount + 1 }
3891+
stats.memoryMapFileOpenedCount <- stats.memoryMapFileOpenedCount + 1
3892+
safeHolder, RawMemoryFile(fileName, safeHolder, accessor.SafeMemoryMappedViewHandle.DangerousGetHandle(), int length) :> BinaryFile
40053893

40063894
let OpenILModuleReaderFromBytes fileName bytes opts =
40073895
let pefile = ByteFile(fileName, bytes) :> BinaryFile
@@ -4067,7 +3955,7 @@ let OpenILModuleReader fileName opts =
40673955

40683956
// For metadata-only, always use a temporary, short-lived PE file reader, preferably over a memory mapped file.
40693957
// Then use the metadata blob as the long-lived memory resource.
4070-
let disposer, pefileEager = tryMemoryMapWholeFile opts fullPath
3958+
let disposer, pefileEager = createMemoryMapFile fullPath
40713959
use _disposer = disposer
40723960
let (metadataPhysLoc, metadataSize, peinfo, pectxtEager, pevEager, _pdb) = openPEFileReader (fullPath, pefileEager, None, false)
40733961
let mdfile =
@@ -4106,7 +3994,7 @@ let OpenILModuleReader fileName opts =
41063994
// still use an in-memory ByteFile
41073995
let _disposer, pefile =
41083996
if alwaysMemoryMapFSC || stableFileHeuristicApplies fullPath then
4109-
tryMemoryMapWholeFile opts fullPath
3997+
createMemoryMapFile fullPath
41103998
else
41113999
let pefile = createByteFileChunk opts fullPath None
41124000
let disposer = { new IDisposable with member __.Dispose() = () }

0 commit comments

Comments
 (0)