diff --git a/src/Compiler/AbstractIL/ilsign.fs b/src/Compiler/AbstractIL/ilsign.fs index 5d4d37c97fb..80418aeca48 100644 --- a/src/Compiler/AbstractIL/ilsign.fs +++ b/src/Compiler/AbstractIL/ilsign.fs @@ -40,7 +40,7 @@ let getResourceString (_, str) = str [] type ByteArrayUnion = [] - val UnderlyingArray: byte[] + val UnderlyingArray: byte array [] val ImmutableArray: ImmutableArray @@ -73,7 +73,7 @@ let hashAssembly (peReader: PEReader) (hashAlgorithm: IncrementalHash) = peHeaderOffset + peHeaderSize + int peHeaders.CoffHeader.NumberOfSections * 0x28 // sizeof(IMAGE_SECTION_HEADER) let allHeaders = - let array: byte[] = Array.zeroCreate allHeadersSize + let array = Array.zeroCreate allHeadersSize peReader.GetEntireImage().GetContent().CopyTo(0, array, 0, allHeadersSize) array @@ -121,9 +121,9 @@ let hashAssembly (peReader: PEReader) (hashAlgorithm: IncrementalHash) = hashAlgorithm.GetHashAndReset() type BlobReader = - val mutable _blob: byte[] + val mutable _blob: byte array val mutable _offset: int - new(blob: byte[]) = { _blob = blob; _offset = 0 } + new(blob: byte array) = { _blob = blob; _offset = 0 } member x.ReadInt32() : int = let offset = x._offset @@ -134,13 +134,13 @@ type BlobReader = ||| (int x._blob[offset + 2] <<< 16) ||| (int x._blob[offset + 3] <<< 24) - member x.ReadBigInteger(length: int) : byte[] = - let arr: byte[] = Array.zeroCreate length + member x.ReadBigInteger(length: int) : byte array = + let arr = Array.zeroCreate length Array.Copy(x._blob, x._offset, arr, 0, length) x._offset <- x._offset + length arr |> Array.rev -let RSAParamatersFromBlob (blob: byte[]) keyType = +let RSAParamatersFromBlob blob keyType = let mutable reader = BlobReader blob if reader.ReadInt32() <> 0x00000207 && keyType = KeyType.KeyPair then @@ -169,14 +169,14 @@ let RSAParamatersFromBlob (blob: byte[]) keyType = key.D <- reader.ReadBigInteger byteLen key -let validateRSAField (field: byte[] MaybeNull) expected (name: string) = +let validateRSAField (field: byte array MaybeNull) expected (name: string) = match field with | Null -> () | NonNull field -> if field.Length <> expected then raise (CryptographicException(String.Format(getResourceString (FSComp.SR.ilSignInvalidRSAParams ()), name))) -let toCLRKeyBlob (rsaParameters: RSAParameters) (algId: int) : byte[] = +let toCLRKeyBlob (rsaParameters: RSAParameters) (algId: int) : byte array = // The original FCall this helper emulates supports other algId's - however, the only algid we need to support is CALG_RSA_KEYX. We will not port the codepaths dealing with other algid's. if algId <> CALG_RSA_KEYX then @@ -249,7 +249,7 @@ let toCLRKeyBlob (rsaParameters: RSAParameters) (algId: int) : byte[] = key -let createSignature (hash: byte[]) (keyBlob: byte[]) keyType = +let createSignature hash keyBlob keyType = use rsa = RSA.Create() rsa.ImportParameters(RSAParamatersFromBlob keyBlob keyType) @@ -258,7 +258,7 @@ let createSignature (hash: byte[]) (keyBlob: byte[]) keyType = signature |> Array.rev -let patchSignature (stream: Stream) (peReader: PEReader) (signature: byte[]) = +let patchSignature (stream: Stream) (peReader: PEReader) (signature: byte array) = let peHeaders = peReader.PEHeaders let signatureDirectory = peHeaders.CorHeader.StrongNameSignatureDirectory @@ -289,7 +289,7 @@ let signStream stream keyBlob = let signature = createSignature hash keyBlob KeyType.KeyPair patchSignature stream peReader signature -let signatureSize (pk: byte[]) = +let signatureSize (pk: byte array) = if pk.Length < 25 then raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ()))) @@ -313,9 +313,9 @@ let getPublicKeyForKeyPair keyBlob = // Key signing type keyContainerName = string -type keyPair = byte[] -type pubkey = byte[] -type pubkeyOptions = byte[] * bool +type keyPair = byte array +type pubkey = byte array +type pubkeyOptions = byte array * bool let signerGetPublicKeyForKeyPair (kp: keyPair) : pubkey = getPublicKeyForKeyPair kp diff --git a/src/Compiler/AbstractIL/ilsign.fsi b/src/Compiler/AbstractIL/ilsign.fsi index 9dcdbf8ecda..8e7b2fdc751 100644 --- a/src/Compiler/AbstractIL/ilsign.fsi +++ b/src/Compiler/AbstractIL/ilsign.fsi @@ -15,12 +15,12 @@ open System.IO //--------------------------------------------------------------------- [] type ILStrongNameSigner = - member PublicKey: byte[] + member PublicKey: byte array static member OpenPublicKeyOptions: byte array -> bool -> ILStrongNameSigner - static member OpenPublicKey: byte[] -> ILStrongNameSigner - static member OpenKeyPairFile: byte[] -> ILStrongNameSigner + static member OpenPublicKey: byte array -> ILStrongNameSigner + static member OpenKeyPairFile: byte array -> ILStrongNameSigner static member OpenKeyContainer: string -> ILStrongNameSigner member IsFullySigned: bool - member PublicKey: byte[] + member PublicKey: byte array member SignatureSize: int member SignStream: Stream -> unit diff --git a/src/Compiler/AbstractIL/ilwrite.fs b/src/Compiler/AbstractIL/ilwrite.fs index d804ba2fb53..c2480f23636 100644 --- a/src/Compiler/AbstractIL/ilwrite.fs +++ b/src/Compiler/AbstractIL/ilwrite.fs @@ -3731,7 +3731,6 @@ let writePdb ( stream.WriteTo fs getInfoForPortablePdb contentId pdbfile pathMap debugDataChunk debugDeterministicPdbChunk debugChecksumPdbChunk algorithmName checkSum embeddedPDB deterministic | None -> [| |] - reportTime "Generate PDB Info" // Now we have the debug data we can go back and fill in the debug directory in the image use fs2 = reopenOutput() @@ -3759,6 +3758,7 @@ let writePdb ( reportTime "Finalize PDB" signImage () os2.Dispose() + reportTime "Generate PDB Info" with exn -> failwith ("Error while writing debug directory entry: " + exn.Message) (try os2.Dispose(); FileSystem.FileDeleteShim outfile with _ -> ()) diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index ec9bb7cf34d..c0d03d8474a 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1328,6 +1328,36 @@ let internal mkBoundValueTypedImpl tcGlobals m moduleName name ty = let qname = QualifiedNameOfFile.QualifiedNameOfFile(Ident(moduleName, m)) entity, v, CheckedImplFile.CheckedImplFile(qname, [], mty, contents, false, false, StampMap.Empty, Map.empty) + +let scriptingSymbolsPath = + let createDirectory path = + lazy + try + if not (Directory.Exists(path)) then + Directory.CreateDirectory(path) |> ignore + + path + with _ -> + path + + createDirectory (Path.Combine(Path.GetTempPath(), $"{DateTime.Now:s}-{Guid.NewGuid():n}".Replace(':', '-'))) + +let deleteScriptingSymbols () = + try +#if !DEBUG + if scriptingSymbolsPath.IsValueCreated then + if Directory.Exists(scriptingSymbolsPath.Value) then + Directory.Delete(scriptingSymbolsPath.Value, true) +#else + () +#endif + with _ -> + () + +AppDomain.CurrentDomain.ProcessExit |> Event.add (fun _ -> deleteScriptingSymbols ()) + +let dynamicCcuName = "FSI-ASSEMBLY" + /// Encapsulates the coordination of the typechecking, optimization and code generation /// components of the F# compiler for interactively executed fragments of code. /// @@ -1350,12 +1380,12 @@ type internal FsiDynamicCompiler( let outfile = "TMPFSCI.exe" - let dynamicCcuName = "FSI-ASSEMBLY" - let valueBoundEvent = Control.Event<_>() let mutable fragmentId = 0 + static let mutable dynamicAssemblyId = 0 + static let maxVersion = int Int16.MaxValue let mutable prevIt : ValRef option = None @@ -1387,7 +1417,8 @@ type internal FsiDynamicCompiler( /// Add attributes let CreateModuleFragment (tcConfigB: TcConfigBuilder, dynamicCcuName, codegenResults) = if progress then fprintfn fsiConsoleOutput.Out "Creating main module..." - let mainModule = mkILSimpleModule dynamicCcuName (GetGeneratedILModuleName tcConfigB.target dynamicCcuName) (tcConfigB.target = CompilerTarget.Dll) tcConfigB.subsystemVersion tcConfigB.useHighEntropyVA (mkILTypeDefs codegenResults.ilTypeDefs) None None 0x0 (mkILExportedTypes []) "" + let mainModule = + mkILSimpleModule dynamicCcuName (GetGeneratedILModuleName tcConfigB.target dynamicCcuName) (tcConfigB.target = CompilerTarget.Dll) tcConfigB.subsystemVersion tcConfigB.useHighEntropyVA (mkILTypeDefs codegenResults.ilTypeDefs) None None 0x0 (mkILExportedTypes []) "" { mainModule with Manifest = (let man = mainModule.ManifestOfAssembly @@ -1402,7 +1433,7 @@ type internal FsiDynamicCompiler( let manifest = let manifest = ilxMainModule.Manifest.Value let attrs = [ - tcGlobals.MakeInternalsVisibleToAttribute(ilxMainModule.ManifestOfAssembly.Name) + tcGlobals.MakeInternalsVisibleToAttribute(dynamicCcuName) yield! manifest.CustomAttrs.AsList() ] { manifest with @@ -1412,7 +1443,7 @@ type internal FsiDynamicCompiler( CustomAttrsStored = storeILCustomAttrs (mkILCustomAttrs attrs) } - // The name of the assembly is "FSI-ASSEMBLY" for all submissions. This number is used for the Version + // The name of the assembly is "FSI-ASSEMBLY" for all submissions. This number is used for the Version dynamicAssemblyId <- (dynamicAssemblyId + 1) % maxVersion let ilxMainModule = { ilxMainModule with Manifest = Some manifest } @@ -1421,44 +1452,43 @@ type internal FsiDynamicCompiler( let ilxMainModule = ilxMainModule |> Morphs.morphILTypeRefsInILModuleMemoized emEnv.MapTypeRef - let opts = - { ilg = tcGlobals.ilg - // This is not actually written, because we are writing to a stream, - // but needs to be set for some logic of ilwrite to function. - outfile = multiAssemblyName + ".dll" - // This is not actually written, because we embed debug info, - // but needs to be set for some logic of ilwrite to function. - pdbfile = (if tcConfig.debuginfo then Some (multiAssemblyName + ".pdb") else None) - emitTailcalls = tcConfig.emitTailcalls - deterministic = tcConfig.deterministic - // we always use portable for F# Interactive debug emit - portablePDB = true - // we don't use embedded for F# Interactive debug emit - embeddedPDB = false - embedAllSource = tcConfig.embedAllSource - embedSourceList = tcConfig.embedSourceList - // we don't add additional source files to the debug document set - allGivenSources = [] - sourceLink = tcConfig.sourceLink - checksumAlgorithm = tcConfig.checksumAlgorithm - signer = None - dumpDebugInfo = tcConfig.dumpDebugInfo - referenceAssemblyOnly = false - referenceAssemblyAttribOpt = None - pathMap = tcConfig.pathMap } - - let normalizeAssemblyRefs = id - - let assemblyBytes, pdbBytes = WriteILBinaryInMemory (opts, ilxMainModule, normalizeAssemblyRefs) + let opts = { + ilg = tcGlobals.ilg + outfile = multiAssemblyName + ".dll" + pdbfile = Some (Path.Combine(scriptingSymbolsPath.Value, $"{multiAssemblyName}-{dynamicAssemblyId}.pdb")) + emitTailcalls = tcConfig.emitTailcalls + deterministic = tcConfig.deterministic + portablePDB = true + embeddedPDB = false + embedAllSource = false + embedSourceList = [] + allGivenSources = [] + sourceLink = tcConfig.sourceLink + checksumAlgorithm = tcConfig.checksumAlgorithm + signer = None + dumpDebugInfo = tcConfig.dumpDebugInfo + referenceAssemblyOnly = false + referenceAssemblyAttribOpt = None + pathMap = tcConfig.pathMap + } + + let assemblyBytes, pdbBytes = WriteILBinaryInMemory (opts, ilxMainModule, id) let asm = + match opts.pdbfile, pdbBytes with + | (Some pdbfile), (Some pdbBytes) -> + File.WriteAllBytes(pdbfile, pdbBytes) + | _ -> () + match pdbBytes with | None -> Assembly.Load(assemblyBytes) | Some pdbBytes -> Assembly.Load(assemblyBytes, pdbBytes) - dynamicAssemblies.Add(asm) - let loadedTypes = [ for t in asm.GetTypes() -> t] - ignore loadedTypes + // Force generated types to load + for t in asm.GetTypes() do ignore t + + // remember this assembly + dynamicAssemblies.Add(asm) let ilScopeRef = ILScopeRef.Assembly (ILAssemblyRef.FromAssemblyName(asm.GetName())) @@ -1475,7 +1505,7 @@ type internal FsiDynamicCompiler( let execs = [ for edef in entries do if edef.ArgCount = 0 then - yield (fun () -> + yield (fun () -> let typ = asm.GetType(edef.DeclaringTypeRef.BasicQualifiedName) try ignore (typ.InvokeMember (edef.Name, BindingFlags.InvokeMethod ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.Static, null, null, [| |], Globalization.CultureInfo.InvariantCulture)) @@ -2513,7 +2543,7 @@ type internal MagicAssemblyResolution () = let res = CommitOperationResult overallSearchResult match res with | Choice1Of2 assemblyName -> - if simpleAssemName <> "Mono.Posix" then fsiConsoleOutput.uprintfn "%s" (FSIstrings.SR.fsiBindingSessionTo(assemblyName)) + if simpleAssemName <> "Mono.Posix" && progress then fsiConsoleOutput.uprintfn "%s" (FSIstrings.SR.fsiBindingSessionTo(assemblyName)) if isRunningOnCoreClr then assemblyLoadFrom assemblyName else