Skip to content

Commit 623c6d4

Browse files
committed
Specialize signature-hidden values
1 parent 22cd8a8 commit 623c6d4

2 files changed

Lines changed: 101 additions & 6 deletions

File tree

src/Compiler/Optimize/Optimizer.fs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ type cenv =
438438
realsig: bool
439439

440440
specializedInlineVals: HashMultiMap<Stamp, TType * Expr>
441+
442+
signatureHidingInfo: SignatureHidingInfo
441443
}
442444

443445
override x.ToString() = "<cenv>"
@@ -3459,8 +3461,14 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
34593461
let allTyargsAreGeneric =
34603462
tyargs |> List.forall (fun t -> not (freeInType CollectTyparsNoCaching t).FreeTypars.IsEmpty)
34613463

3464+
// When inside an inline function body being prepared for export (!cenv.optimizing),
3465+
// only emit a direct call if the callee is publicly accessible. Non-public vals
3466+
// (e.g. in internal modules, or hidden by .fsi) can't be called by consumers,
3467+
// so route those through the specialization path which inlines the body.
3468+
let isHiddenBySignature = cenv.signatureHidingInfo.HiddenVals.Contains vref.Deref
34623469
let canCallDirectly =
3463-
hasNoTraits || (allTyargsAreGeneric && vref.ValReprInfo.IsSome)
3470+
(cenv.optimizing || (vref.Accessibility.IsPublic && not isHiddenBySignature)) &&
3471+
(hasNoTraits || (allTyargsAreGeneric && vref.ValReprInfo.IsSome))
34643472

34653473
let argsR = args |> List.map (OptimizeExpr cenv env >> fst)
34663474
let info = { TotalSize = 1; FunctionSize = 1; HasEffect = true; MightMakeCriticalTailcall = false; Info = UnknownValue }
@@ -4324,17 +4332,23 @@ and OptimizeBindings cenv isRec env xs =
43244332

43254333
and OptimizeModuleExprWithSig cenv env mty def =
43264334
let g = cenv.g
4327-
// Optimize the module implementation
4328-
let (def, info), (_env, bindInfosColl) = OptimizeModuleContents cenv (env, []) def
4329-
let bindInfosColl = List.concat bindInfosColl
4330-
4335+
43314336
// Compute the elements truly hidden by the module signature.
43324337
// The hidden set here must contain NOT MORE THAN the set of values made inaccessible by
43334338
// the application of the signature. If it contains extra elements we'll accidentally eliminate
43344339
// bindings.
4335-
4340+
// This only walks structural elements (Val/Entity declarations), not expressions,
4341+
// so it gives the same result before and after optimization.
43364342
let _renaming, hidden as rpi = ComputeRemappingFromImplementationToSignature g def mty
43374343

4344+
// Make hiding info available during optimization so TryInlineApplication
4345+
// can avoid emitting direct calls to vals hidden by signature.
4346+
let cenv = { cenv with signatureHidingInfo = hidden }
4347+
4348+
// Optimize the module implementation
4349+
let (def, info), (_env, bindInfosColl) = OptimizeModuleContents cenv (env, []) def
4350+
let bindInfosColl = List.concat bindInfosColl
4351+
43384352
let def =
43394353
if not cenv.settings.LocalOptimizationsEnabled then def else
43404354

@@ -4500,6 +4514,7 @@ let OptimizeImplFile (settings, ccu, tcGlobals, tcVal, importMap, optEnv, isIncr
45004514
stackGuard = StackGuard("OptimizerStackGuardDepth")
45014515
realsig = tcGlobals.realsig
45024516
specializedInlineVals = HashMultiMap(HashIdentity.Structural, true)
4517+
signatureHidingInfo = SignatureHidingInfo.Empty
45034518
}
45044519

45054520
let env, _, _, _ as results = OptimizeImplFileInternal cenv optEnv isIncrementalFragment hidden mimpls

tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall.fs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,86 @@ open Module
922922
let main _ =
923923
let result = T.Invoke<MyNum>(3.14)
924924
if result.Value = 3.14 then 0 else 1
925+
"""
926+
|> withDebug
927+
|> withNoOptimize
928+
|> withReferences [library]
929+
|> asExe
930+
|> compileAndRun
931+
|> shouldSucceed
932+
933+
[<Fact>]
934+
let ``Accessibility 06`` () =
935+
let impl =
936+
FsSource """
937+
module Lib
938+
939+
module internal Impl =
940+
let inline implFn (x: int) =
941+
x * x
942+
943+
let inline publicFn (x: int) =
944+
Impl.implFn x + 1
945+
"""
946+
let fsi = Fsi """
947+
module Lib
948+
949+
val inline publicFn: x: int -> int
950+
"""
951+
let library =
952+
fsi
953+
|> withAdditionalSourceFile impl
954+
|> withDebug
955+
|> withNoOptimize
956+
|> asLibrary
957+
958+
FSharp """
959+
open Lib
960+
961+
[<EntryPoint>]
962+
let main _ =
963+
let i = publicFn 3
964+
if i = 10 then 0 else 1
965+
"""
966+
|> withDebug
967+
|> withNoOptimize
968+
|> withReferences [library]
969+
|> asExe
970+
|> compileAndRun
971+
|> shouldSucceed
972+
973+
[<Fact>]
974+
let ``Accessibility 07`` () =
975+
let impl =
976+
FsSource """
977+
module Lib
978+
979+
module Impl =
980+
let inline implFn (x: int) =
981+
x * x
982+
983+
let inline publicFn (x: int) =
984+
Impl.implFn x + 1
985+
"""
986+
let fsi = Fsi """
987+
module Lib
988+
989+
val inline publicFn: x: int -> int
990+
"""
991+
let library =
992+
fsi
993+
|> withAdditionalSourceFile impl
994+
|> withDebug
995+
|> withNoOptimize
996+
|> asLibrary
997+
998+
FSharp """
999+
open Lib
1000+
1001+
[<EntryPoint>]
1002+
let main _ =
1003+
let i = publicFn 3
1004+
if i = 10 then 0 else 1
9251005
"""
9261006
|> withDebug
9271007
|> withNoOptimize

0 commit comments

Comments
 (0)