@@ -14,6 +14,7 @@ open System.Collections.Concurrent
1414open System.Collections .Generic
1515open System.Diagnostics
1616open System.IO
17+ open System.IO .MemoryMappedFiles
1718open System.Runtime .InteropServices
1819open System.Text
1920open 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 <> 0 uy do
259- p <- p + 1 n
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 , 0 n)
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
306189type 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( 0 L, 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
40063894let 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