@@ -14,6 +14,7 @@ open System.Collections.Concurrent
14
14
open System.Collections .Generic
15
15
open System.Diagnostics
16
16
open System.IO
17
+ open System.IO .MemoryMappedFiles
17
18
open System.Runtime .InteropServices
18
19
open System.Text
19
20
open Internal.Utilities
@@ -184,124 +185,6 @@ type RawMemoryFile(fileName: string, obj: obj, addr: nativeint, length: int) =
184
185
interface BinaryFile with
185
186
override __.GetView () = view :>_
186
187
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
-
305
188
/// Read file from memory blocks
306
189
type ByteView ( bytes : byte []) =
307
190
inherit BinaryView()
@@ -3989,19 +3872,24 @@ let createByteFileChunk opts fileName chunk =
3989
3872
| Some ( start, length) -> File.ReadBinaryChunk( fileName, start, length)
3990
3873
ByteFile( fileName, bytes) :> BinaryFile
3991
3874
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
4005
3893
4006
3894
let OpenILModuleReaderFromBytes fileName bytes opts =
4007
3895
let pefile = ByteFile( fileName, bytes) :> BinaryFile
@@ -4067,7 +3955,7 @@ let OpenILModuleReader fileName opts =
4067
3955
4068
3956
// For metadata-only, always use a temporary, short-lived PE file reader, preferably over a memory mapped file.
4069
3957
// Then use the metadata blob as the long-lived memory resource.
4070
- let disposer , pefileEager = tryMemoryMapWholeFile opts fullPath
3958
+ let disposer , pefileEager = createMemoryMapFile fullPath
4071
3959
use _disposer = disposer
4072
3960
let ( metadataPhysLoc , metadataSize , peinfo , pectxtEager , pevEager , _pdb ) = openPEFileReader ( fullPath, pefileEager, None, false )
4073
3961
let mdfile =
@@ -4106,7 +3994,7 @@ let OpenILModuleReader fileName opts =
4106
3994
// still use an in-memory ByteFile
4107
3995
let _disposer , pefile =
4108
3996
if alwaysMemoryMapFSC || stableFileHeuristicApplies fullPath then
4109
- tryMemoryMapWholeFile opts fullPath
3997
+ createMemoryMapFile fullPath
4110
3998
else
4111
3999
let pefile = createByteFileChunk opts fullPath None
4112
4000
let disposer = { new IDisposable with member __.Dispose () = () }
0 commit comments