@@ -19,6 +19,31 @@ open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
1919open Microsoft.FSharp .Compiler .ErrorLogger
2020open Microsoft.FSharp .Compiler .Range
2121
22+
23+ type BlobBuildingStream () =
24+ inherit Stream()
25+
26+ static let chunkSize = 32 * 1024
27+ let builder = new BlobBuilder( chunkSize)
28+
29+ override this.CanWrite with get() = true
30+ override this.CanRead with get() = false
31+ override this.CanSeek with get() = false
32+ override this.Length with get() = int64( builder.Count)
33+
34+ override this.Write ( buffer : byte array , offset : int , count : int ) = builder.WriteBytes( buffer, offset, count)
35+ override this.WriteByte ( value : byte ) = builder.WriteByte( value)
36+ member this.WriteInt32 ( value : int ) = builder.WriteInt32( value)
37+ member this.ToImmutableArray () = builder.ToImmutableArray()
38+ member this.TryWriteBytes ( stream : Stream , length : int ) = builder.TryWriteBytes( stream, length)
39+
40+ override this.Flush () = ()
41+ override this.Dispose ( _disposing : bool ) = ()
42+ override this.Seek ( _offset : int64 , _origin : SeekOrigin ) = raise ( new NotSupportedException())
43+ override this.Read ( _buffer : byte array , _offset : int , _count : int ) = raise ( new NotSupportedException())
44+ override this.SetLength ( _value : int64 ) = raise ( new NotSupportedException())
45+ override val Position = 0 L with get, set
46+
2247// --------------------------------------------------------------------
2348// PDB types
2449// --------------------------------------------------------------------
@@ -227,7 +252,7 @@ let fixupOverlappingSequencePoints fixupSPs showTimes methods =
227252 Array.sortInPlaceBy fst allSps
228253 spCounts, allSps
229254
230- let generatePortablePdb fixupSPs showTimes ( info : PdbData ) =
255+ let generatePortablePdb fixupSPs ( embedAllSource : bool ) ( embedSourceList : string list ) showTimes ( info : PdbData ) =
231256 sortMethods showTimes info
232257 let _spCounts , _allSps = fixupOverlappingSequencePoints fixupSPs showTimes info.Methods
233258 let externalRowCounts = getRowCounts info.TableRowCounts
@@ -253,23 +278,71 @@ let generatePortablePdb fixupSPs showTimes (info:PdbData) =
253278 metadata.GetOrAddBlob( writer)
254279
255280 let corSymLanguageTypeFSharp = System.Guid( 0xAB4F38C9 u, 0xB6E6 us, 0x43ba us, 0xBE uy, 0x3B uy, 0x58 uy, 0x08 uy, 0x0B uy, 0x2C uy, 0xCC uy, 0xE3 uy)
281+ let embeddedSource = System.Guid( 0x0e8a571b u, 0x6926 us, 0x466e us, 0xb4 uy, 0xad uy, 0x8a uy, 0xb0 uy, 0x46 uy, 0x11 uy, 0xf5 uy, 0xfe uy)
282+
283+ /// <summary>
284+ /// The maximum number of bytes in to write out uncompressed.
285+ ///
286+ /// This prevents wasting resources on compressing tiny files with little to negative gain
287+ /// in PDB file size.
288+ ///
289+ /// Chosen as the point at which we start to see > 10% blob size reduction using all
290+ /// current source files in corefx and roslyn as sample data.
291+ /// </summary>
292+ let sourceCompressionThreshold = 200
293+
256294 let documentIndex =
295+ let includeSource file =
296+ let isInList =
297+ if embedSourceList |> List.length = 0 then false
298+ else
299+ match embedSourceList |> List.tryFind( fun f -> String.Compare( file, f, StringComparison.OrdinalIgnoreCase ) = 0 ) with
300+ | Some _ -> true
301+ | None -> false
302+
303+ if not embedAllSource && not isInList || not ( File.Exists( file)) then
304+ None
305+ else
306+ let stream = File.OpenRead( file)
307+ let length64 = stream.Length
308+ if length64 > int64( Int32.MaxValue) then raise ( new IOException( " File is too long" ))
309+
310+ let builder = new BlobBuildingStream()
311+ let length = int( length64)
312+ if length < sourceCompressionThreshold then
313+ builder.WriteInt32( 0 )
314+ builder.TryWriteBytes( stream, length) |> ignore
315+ else
316+ builder.WriteInt32( length) |> ignore
317+ use deflater = new DeflateStream( builder, CompressionMode.Compress, true )
318+ stream.CopyTo( deflater) |> ignore
319+ Some ( builder.ToImmutableArray())
320+
257321 let mutable index = new Dictionary< string, DocumentHandle>( docs.Length)
258322 metadata.SetCapacity( TableIndex.Document, docs.Length)
259323 for doc in docs do
260324 let handle =
261325 match checkSum doc.File with
262326 | Some ( hashAlg, checkSum) ->
263- serializeDocumentName doc.File,
264- metadata.GetOrAddGuid( hashAlg),
265- metadata.GetOrAddBlob( checkSum.ToImmutableArray()),
266- metadata.GetOrAddGuid( corSymLanguageTypeFSharp)
327+ let h =
328+ ( serializeDocumentName doc.File,
329+ metadata.GetOrAddGuid( hashAlg),
330+ metadata.GetOrAddBlob( checkSum.ToImmutableArray()),
331+ metadata.GetOrAddGuid( corSymLanguageTypeFSharp)) |> metadata.AddDocument
332+ match includeSource doc.File with
333+ | None -> ()
334+ | Some blob ->
335+ metadata.AddCustomDebugInformation( DocumentHandle.op_ Implicit( h),
336+ metadata.GetOrAddGuid( embeddedSource),
337+ metadata.GetOrAddBlob( blob)) |> ignore
338+ h
267339 | None ->
268- serializeDocumentName doc.File,
269- metadata.GetOrAddGuid( System.Guid.Empty),
270- metadata.GetOrAddBlob( ImmutableArray< byte>. Empty),
271- metadata.GetOrAddGuid( corSymLanguageTypeFSharp)
272- |> metadata.AddDocument
340+ let h =
341+ ( serializeDocumentName doc.File,
342+ metadata.GetOrAddGuid( System.Guid.Empty),
343+ metadata.GetOrAddBlob( ImmutableArray< byte>. Empty),
344+ metadata.GetOrAddGuid( corSymLanguageTypeFSharp)) |> metadata.AddDocument
345+ h
273346 index.Add( doc.File, handle)
274347 index
275348
@@ -291,7 +364,7 @@ let generatePortablePdb fixupSPs showTimes (info:PdbData) =
291364 else
292365 match documentIndex.TryGetValue( docs.[ d]. File) with
293366 | false , _ -> Unchecked.defaultof< DocumentHandle>
294- | true , f -> f
367+ | true , h -> h
295368
296369 if sps.Length = 0 then
297370 Unchecked.defaultof< DocumentHandle>, Unchecked.defaultof< BlobHandle>
@@ -306,7 +379,6 @@ let generatePortablePdb fixupSPs showTimes (info:PdbData) =
306379 singleDocumentIndex
307380
308381 let builder = new BlobBuilder()
309-
310382 builder.WriteCompressedInteger( minfo.LocalSignatureToken)
311383
312384 // Initial document: When sp's spread over more than one document we put the initial document here.
0 commit comments