33/// Byte arrays
44namespace FSharp.Compiler.AbstractIL.Internal
55
6+ open System
7+ open System.IO
8+ open System.IO .MemoryMappedFiles
9+ open System.Runtime .InteropServices
10+ open System.Runtime .CompilerServices
11+ open FSharp.NativeInterop
612
13+ #nowarn " 9"
714
815module internal Bytes =
916 let b0 n = ( n &&& 0xFF )
@@ -26,10 +33,286 @@ module internal Bytes =
2633 Array.append ( System.Text.Encoding.UTF8.GetBytes s) ( ofInt32Array [| 0x0 |])
2734
2835 let stringAsUnicodeNullTerminated ( s : string ) =
29- Array.append ( System.Text.Encoding.Unicode.GetBytes s) ( ofInt32Array [| 0x0 ; 0x0 |])
36+ Array.append ( System.Text.Encoding.Unicode.GetBytes s) ( ofInt32Array [| 0x0 ; 0x0 |])
37+
38+ [<AbstractClass>]
39+ type ByteMemory () =
40+
41+ abstract Item: int -> byte with get, set
42+
43+ abstract Length: int
44+
45+ abstract ReadBytes: pos : int * count : int -> byte []
46+
47+ abstract ReadInt32: pos : int -> int
48+
49+ abstract ReadUInt16: pos : int -> uint16
50+
51+ abstract ReadUtf8String: pos : int * count : int -> string
52+
53+ abstract Slice: pos : int * count : int -> ByteMemory
54+
55+ abstract CopyTo: Stream -> unit
56+
57+ abstract Copy: srcOffset : int * dest : byte [] * destOffset : int * count : int -> unit
58+
59+ abstract ToArray: unit -> byte []
60+
61+ abstract AsStream: unit -> Stream
62+
63+ abstract AsReadOnlyStream: unit -> Stream
64+
65+ [<Sealed>]
66+ type ByteArrayMemory ( bytes : byte [], offset , length ) =
67+ inherit ByteMemory()
68+
69+ do
70+ if length <= 0 || length > bytes.Length then
71+ raise ( ArgumentOutOfRangeException( " length" ))
72+
73+ if offset < 0 || ( offset + length) > bytes.Length then
74+ raise ( ArgumentOutOfRangeException( " offset" ))
75+
76+ override _.Item
77+ with get i = bytes.[ offset + i]
78+ and set i v = bytes.[ offset + i] <- v
79+
80+ override _.Length = length
81+
82+ override _.ReadBytes ( pos , count ) =
83+ Array.sub bytes ( offset + pos) count
84+
85+ override _.ReadInt32 pos =
86+ let finalOffset = offset + pos
87+ ( uint32 bytes.[ finalOffset]) |||
88+ (( uint32 bytes.[ finalOffset + 1 ]) <<< 8 ) |||
89+ (( uint32 bytes.[ finalOffset + 2 ]) <<< 16 ) |||
90+ (( uint32 bytes.[ finalOffset + 3 ]) <<< 24 )
91+ |> int
92+
93+ override _.ReadUInt16 pos =
94+ let finalOffset = offset + pos
95+ ( uint16 bytes.[ finalOffset]) |||
96+ (( uint16 bytes.[ finalOffset + 1 ]) <<< 8 )
97+
98+ override _.ReadUtf8String ( pos , count ) =
99+ System.Text.Encoding.UTF8.GetString( bytes, offset + pos, count)
100+
101+ override _.Slice ( pos , count ) =
102+ ByteArrayMemory( bytes, offset + pos, count) :> ByteMemory
103+
104+ override _.CopyTo stream =
105+ stream.Write( bytes, offset, length)
106+
107+ override _.Copy ( srcOffset , dest , destOffset , count ) =
108+ Array.blit bytes ( offset + srcOffset) dest destOffset count
109+
110+ override _.ToArray () =
111+ Array.sub bytes offset length
112+
113+ override _.AsStream () =
114+ new MemoryStream( bytes, offset, length) :> Stream
115+
116+ override _.AsReadOnlyStream () =
117+ new MemoryStream( bytes, offset, length, false ) :> Stream
118+
119+ [<Sealed>]
120+ type RawByteMemory ( addr : nativeptr < byte >, length : int , hold : obj ) =
121+ inherit ByteMemory ()
122+
123+ let check i =
124+ if i < 0 || i >= length then
125+ raise ( ArgumentOutOfRangeException( " i" ))
126+
127+ do
128+ if length <= 0 then
129+ raise ( ArgumentOutOfRangeException( " length" ))
130+
131+ override _.Item
132+ with get i =
133+ check i
134+ NativePtr.add addr i
135+ |> NativePtr.read
136+ and set i v =
137+ check i
138+ NativePtr.set addr i v
139+
140+ override _.Length = length
141+
142+ override _.ReadUtf8String ( pos , count ) =
143+ check pos
144+ check ( pos + count - 1 )
145+ System.Text.Encoding.UTF8.GetString( NativePtr.add addr pos, count)
146+
147+ override _.ReadBytes ( pos , count ) =
148+ check pos
149+ check ( pos + count - 1 )
150+ let res = Bytes.zeroCreate count
151+ Marshal.Copy( NativePtr.toNativeInt addr + nativeint pos, res, 0 , count)
152+ res
153+
154+ override _.ReadInt32 pos =
155+ check pos
156+ check ( pos + 3 )
157+ Marshal.ReadInt32( NativePtr.toNativeInt addr + nativeint pos)
158+
159+ override _.ReadUInt16 pos =
160+ check pos
161+ check ( pos + 1 )
162+ uint16( Marshal.ReadInt16( NativePtr.toNativeInt addr + nativeint pos))
163+
164+ override _.Slice ( pos , count ) =
165+ check pos
166+ check ( pos + count - 1 )
167+ RawByteMemory( NativePtr.add addr pos, count, hold) :> ByteMemory
168+
169+ override x.CopyTo stream =
170+ use stream2 = x.AsStream()
171+ stream2.CopyTo stream
172+
173+ override x.Copy ( srcOffset , dest , destOffset , count ) =
174+ check srcOffset
175+ Marshal.Copy( NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count)
176+
177+ override _.ToArray () =
178+ let res = Array.zeroCreate< byte> length
179+ Marshal.Copy( NativePtr.toNativeInt addr, res, 0 , res.Length)
180+ res
181+
182+ override _.AsStream () =
183+ new UnmanagedMemoryStream( addr, int64 length) :> Stream
184+
185+ override _.AsReadOnlyStream () =
186+ new UnmanagedMemoryStream( addr, int64 length, int64 length, FileAccess.Read) :> Stream
187+
188+ [<Struct; NoEquality; NoComparison>]
189+ type ReadOnlyByteMemory ( bytes : ByteMemory ) =
190+
191+ member _.Item with [<MethodImpl( MethodImplOptions.AggressiveInlining) >] get i = bytes.[ i]
192+
193+ member _.Length with [<MethodImpl( MethodImplOptions.AggressiveInlining) >] get () = bytes.Length
194+
195+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
196+ member _.ReadBytes ( pos , count ) = bytes.ReadBytes( pos, count)
197+
198+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
199+ member _.ReadInt32 pos = bytes.ReadInt32 pos
200+
201+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
202+ member _.ReadUInt16 pos = bytes.ReadUInt16 pos
203+
204+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
205+ member _.ReadUtf8String ( pos , count ) = bytes.ReadUtf8String( pos, count)
206+
207+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
208+ member _.Slice ( pos , count ) = bytes.Slice( pos, count) |> ReadOnlyByteMemory
209+
210+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
211+ member _.CopyTo stream = bytes.CopyTo stream
212+
213+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
214+ member _.Copy ( srcOffset , dest , destOffset , count ) = bytes.Copy( srcOffset, dest, destOffset, count)
215+
216+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
217+ member _.ToArray () = bytes.ToArray()
218+
219+ [<MethodImpl( MethodImplOptions.AggressiveInlining) >]
220+ member _.AsStream () = bytes.AsReadOnlyStream()
221+
222+ type ByteMemory with
223+
224+ member x.AsReadOnly () = ReadOnlyByteMemory x
225+
226+ static member CreateMemoryMappedFile ( bytes : ReadOnlyByteMemory ) =
227+ let length = int64 bytes.Length
228+ let mmf =
229+ let mmf =
230+ MemoryMappedFile.CreateNew(
231+ null ,
232+ length,
233+ MemoryMappedFileAccess.ReadWrite,
234+ MemoryMappedFileOptions.None,
235+ HandleInheritability.None)
236+ use stream = mmf.CreateViewStream( 0 L, length, MemoryMappedFileAccess.ReadWrite)
237+ bytes.CopyTo stream
238+ mmf
239+
240+ let accessor = mmf.CreateViewAccessor( 0 L, length, MemoryMappedFileAccess.ReadWrite)
241+
242+ let safeHolder =
243+ { new obj() with
244+ override x.Finalize () =
245+ ( x :?> IDisposable ). Dispose ()
246+ interface IDisposable with
247+ member x.Dispose () =
248+ GC.SuppressFinalize x
249+ accessor.Dispose()
250+ mmf.Dispose() }
251+ RawByteMemory.FromUnsafePointer( accessor.SafeMemoryMappedViewHandle.DangerousGetHandle(), int length, safeHolder)
252+
253+ static member FromFile ( path , access , ? canShadowCopy : bool ) =
254+ let canShadowCopy = defaultArg canShadowCopy false
255+
256+ let memoryMappedFileAccess =
257+ match access with
258+ | FileAccess.Read -> MemoryMappedFileAccess.Read
259+ | FileAccess.Write -> MemoryMappedFileAccess.Write
260+ | _ -> MemoryMappedFileAccess.ReadWrite
261+
262+ let mmf , accessor , length =
263+ let fileStream = File.Open( path, FileMode.Open, access, FileShare.Read)
264+ let length = fileStream.Length
265+ let mmf =
266+ if canShadowCopy then
267+ let mmf =
268+ MemoryMappedFile.CreateNew(
269+ null ,
270+ length,
271+ MemoryMappedFileAccess.ReadWrite,
272+ MemoryMappedFileOptions.None,
273+ HandleInheritability.None)
274+ use stream = mmf.CreateViewStream( 0 L, length, MemoryMappedFileAccess.ReadWrite)
275+ fileStream.CopyTo( stream)
276+ fileStream.Dispose()
277+ mmf
278+ else
279+ MemoryMappedFile.CreateFromFile(
280+ fileStream,
281+ null ,
282+ length,
283+ memoryMappedFileAccess,
284+ HandleInheritability.None,
285+ leaveOpen= false )
286+ mmf, mmf.CreateViewAccessor( 0 L, length, memoryMappedFileAccess), length
287+
288+ match access with
289+ | FileAccess.Read when not accessor.CanRead -> failwith " Cannot read file"
290+ | FileAccess.Write when not accessor.CanWrite -> failwith " Cannot write file"
291+ | _ when not accessor.CanRead || not accessor.CanWrite -> failwith " Cannot read or write file"
292+ | _ -> ()
293+
294+ let safeHolder =
295+ { new obj() with
296+ override x.Finalize () =
297+ ( x :?> IDisposable ). Dispose ()
298+ interface IDisposable with
299+ member x.Dispose () =
300+ GC.SuppressFinalize x
301+ accessor.Dispose()
302+ mmf.Dispose() }
303+ RawByteMemory.FromUnsafePointer( accessor.SafeMemoryMappedViewHandle.DangerousGetHandle(), int length, safeHolder)
304+
305+ static member FromUnsafePointer ( addr , length , hold : obj ) =
306+ RawByteMemory( NativePtr.ofNativeInt addr, length, hold) :> ByteMemory
307+
308+ static member FromArray ( bytes , offset , length ) =
309+ ByteArrayMemory( bytes, offset, length) :> ByteMemory
310+
311+ static member FromArray bytes =
312+ ByteArrayMemory.FromArray( bytes, 0 , bytes.Length)
30313
31314type internal ByteStream =
32- { bytes: byte []
315+ { bytes: ReadOnlyByteMemory
33316 mutable pos: int
34317 max: int }
35318 member b.ReadByte () =
@@ -38,18 +321,18 @@ type internal ByteStream =
38321 b.pos <- b.pos + 1
39322 res
40323 member b.ReadUtf8String n =
41- let res = System.Text.Encoding.UTF8.GetString ( b.bytes, b.pos, n)
324+ let res = b.bytes.ReadUtf8String ( b.pos, n)
42325 b.pos <- b.pos + n; res
43326
44- static member FromBytes ( b : byte [] ,n , len ) =
327+ static member FromBytes ( b : ReadOnlyByteMemory , n , len ) =
45328 if n < 0 || ( n+ len) > b.Length then failwith " FromBytes"
46329 { bytes = b; pos = n; max = n+ len }
47330
48331 member b.ReadBytes n =
49332 if b.pos + n > b.max then failwith " ReadBytes: end of stream"
50- let res = Bytes.sub b.bytes b.pos n
333+ let res = b.bytes.Slice ( b.pos, n )
51334 b.pos <- b.pos + n
52- res
335+ res
53336
54337 member b.Position = b.pos
55338#if LAZY_ UNPICKLE
@@ -108,6 +391,13 @@ type internal ByteBuffer =
108391 Bytes.blit i 0 buf.bbArray buf.bbCurrent n
109392 buf.bbCurrent <- newSize
110393
394+ member buf.EmitByteMemory ( i : ReadOnlyByteMemory ) =
395+ let n = i.Length
396+ let newSize = buf.bbCurrent + n
397+ buf.Ensure newSize
398+ i.Copy( 0 , buf.bbArray, buf.bbCurrent, n)
399+ buf.bbCurrent <- newSize
400+
111401 member buf.EmitInt32AsUInt16 n =
112402 let newSize = buf.bbCurrent + 2
113403 buf.Ensure newSize
0 commit comments