Skip to content

Commit 0a6764a

Browse files
committed
Delaying lambdas working
1 parent 2b1e29c commit 0a6764a

File tree

4 files changed

+84
-57
lines changed

4 files changed

+84
-57
lines changed

src/fsharp/CompileOptions.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ let SetOptimizeOn(tcConfigB: TcConfigBuilder) =
395395
tcConfigB.optSettings <- { tcConfigB.optSettings with jitOptUser = Some true }
396396
tcConfigB.optSettings <- { tcConfigB.optSettings with localOptUser = Some true }
397397
tcConfigB.optSettings <- { tcConfigB.optSettings with crossModuleOptUser = Some true }
398-
tcConfigB.optSettings <- { tcConfigB.optSettings with lambdaInlineThreshold = 6 }
398+
tcConfigB.optSettings <- { tcConfigB.optSettings with lambdaInlineThreshold = Optimizer.LambdaInlineThresholdDefault }
399399
tcConfigB.doDetuple <- true
400400
tcConfigB.doTLR <- true
401401
tcConfigB.doFinalSimplify <- true

src/fsharp/IlxGen.fs

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,9 +2353,7 @@ and CodeGenMethodForExpr cenv mgbuf (spReq, entryPointInfo, methodName, eenv, al
23532353
CodeGenMethod cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs,
23542354
(fun cgbuf eenv -> GenExpr cenv cgbuf eenv spReq expr0 sequel0),
23552355
expr0.Range)
2356-
code
2357-
2358-
2356+
code
23592357

23602358
//--------------------------------------------------------------------------
23612359
// Generate sequels
@@ -4305,9 +4303,65 @@ and GenGenericParams cenv eenv tps =
43054303
and GenGenericArgs m (tyenv: TypeReprEnv) tps =
43064304
tps |> DropErasedTypars |> List.map (fun c -> (mkILTyvarTy tyenv.[c, m]))
43074305

4306+
and DelayGenMethodForLambda cenv mgbuf eenv args =
4307+
cenv.delayedGenMethods.Enqueue(fun cenv -> GenMethodForLambda cenv mgbuf eenv args)
4308+
4309+
and GenMethodForLambda cenv mgbuf eenv (entryPointInfo, cloinfo, eenvinner, body, isLocalTypeFunc, m) =
4310+
let g = cenv.g
4311+
let ilCloBody = CodeGenMethodForExpr cenv mgbuf (SPAlways, entryPointInfo, cloinfo.cloName, eenvinner, 1, body, Return)
4312+
let ilCloTypeRef = cloinfo.cloSpec.TypeRef
4313+
let cloTypeDefs =
4314+
if isLocalTypeFunc then
4315+
4316+
// Work out the contract type and generate a class with an abstract method for this type
4317+
let (ilContractGenericParams, ilContractMethTyargs, ilContractTySpec: ILTypeSpec, ilContractFormalRetTy) = GenNamedLocalTypeFuncContractInfo cenv eenv m cloinfo
4318+
let ilContractTypeRef = ilContractTySpec.TypeRef
4319+
let ilContractTy = mkILFormalBoxedTy ilContractTypeRef ilContractGenericParams
4320+
let ilContractCtor = mkILNonGenericEmptyCtor None g.ilg.typ_Object
4321+
4322+
let ilContractMeths = [ilContractCtor; mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, ilContractMethTyargs, [], mkILReturn ilContractFormalRetTy, MethodBody.Abstract) ]
4323+
let ilContractTypeDef =
4324+
ILTypeDef(name = ilContractTypeRef.Name,
4325+
layout = ILTypeDefLayout.Auto,
4326+
attributes = enum 0,
4327+
genericParams = ilContractGenericParams,
4328+
customAttrs = mkILCustomAttrs [mkCompilationMappingAttr g (int SourceConstructFlags.Closure) ],
4329+
fields = emptyILFields,
4330+
events= emptyILEvents,
4331+
properties = emptyILProperties,
4332+
methods= mkILMethods ilContractMeths,
4333+
methodImpls= emptyILMethodImpls,
4334+
nestedTypes=emptyILTypeDefs,
4335+
implements = [],
4336+
extends= Some g.ilg.typ_Object,
4337+
securityDecls= emptyILSecurityDecls)
4338+
4339+
// the contract type is an abstract type and not sealed
4340+
let ilContractTypeDef =
4341+
ilContractTypeDef
4342+
.WithAbstract(true)
4343+
.WithAccess(ComputeTypeAccess ilContractTypeRef true)
4344+
.WithSerializable(true)
4345+
.WithSpecialName(true)
4346+
.WithLayout(ILTypeDefLayout.Auto)
4347+
.WithInitSemantics(ILTypeInit.BeforeField)
4348+
.WithEncoding(ILDefaultPInvokeEncoding.Auto)
4349+
4350+
mgbuf.AddTypeDef(ilContractTypeRef, ilContractTypeDef, false, false, None)
4351+
4352+
let ilCtorBody = mkILMethodBody (true, [], 8, nonBranchingInstrsToCode (mkCallBaseConstructor(ilContractTy, [])), None )
4353+
let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.cloILFormalRetTy), MethodBody.IL ilCloBody) ]
4354+
let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCtorBody, cloMethods, [], ilContractTy, [])
4355+
cloTypeDefs
4356+
4357+
else
4358+
GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCloBody, [], [], g.ilg.typ_Object, [])
4359+
CountClosure()
4360+
for cloTypeDef in cloTypeDefs do
4361+
mgbuf.AddTypeDef(ilCloTypeRef, cloTypeDef, false, false, None)
4362+
43084363
/// Generate the closure class for a function
43094364
and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc selfv expr =
4310-
let g = cenv.g
43114365
match expr with
43124366
| Expr.Lambda (_, _, _, _, _, m, _)
43134367
| Expr.TyLambda (_, _, _, m, _) ->
@@ -4319,57 +4373,7 @@ and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc selfv expr
43194373
| Some v -> [(v, BranchCallClosure (cloinfo.cloArityInfo))]
43204374
| _ -> []
43214375

4322-
let ilCloBody = CodeGenMethodForExpr cenv cgbuf.mgbuf (SPAlways, entryPointInfo, cloinfo.cloName, eenvinner, 1, body, Return)
4323-
let ilCloTypeRef = cloinfo.cloSpec.TypeRef
4324-
let cloTypeDefs =
4325-
if isLocalTypeFunc then
4326-
4327-
// Work out the contract type and generate a class with an abstract method for this type
4328-
let (ilContractGenericParams, ilContractMethTyargs, ilContractTySpec: ILTypeSpec, ilContractFormalRetTy) = GenNamedLocalTypeFuncContractInfo cenv eenv m cloinfo
4329-
let ilContractTypeRef = ilContractTySpec.TypeRef
4330-
let ilContractTy = mkILFormalBoxedTy ilContractTypeRef ilContractGenericParams
4331-
let ilContractCtor = mkILNonGenericEmptyCtor None g.ilg.typ_Object
4332-
4333-
let ilContractMeths = [ilContractCtor; mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, ilContractMethTyargs, [], mkILReturn ilContractFormalRetTy, MethodBody.Abstract) ]
4334-
let ilContractTypeDef =
4335-
ILTypeDef(name = ilContractTypeRef.Name,
4336-
layout = ILTypeDefLayout.Auto,
4337-
attributes = enum 0,
4338-
genericParams = ilContractGenericParams,
4339-
customAttrs = mkILCustomAttrs [mkCompilationMappingAttr g (int SourceConstructFlags.Closure) ],
4340-
fields = emptyILFields,
4341-
events= emptyILEvents,
4342-
properties = emptyILProperties,
4343-
methods= mkILMethods ilContractMeths,
4344-
methodImpls= emptyILMethodImpls,
4345-
nestedTypes=emptyILTypeDefs,
4346-
implements = [],
4347-
extends= Some g.ilg.typ_Object,
4348-
securityDecls= emptyILSecurityDecls)
4349-
4350-
// the contract type is an abstract type and not sealed
4351-
let ilContractTypeDef =
4352-
ilContractTypeDef
4353-
.WithAbstract(true)
4354-
.WithAccess(ComputeTypeAccess ilContractTypeRef true)
4355-
.WithSerializable(true)
4356-
.WithSpecialName(true)
4357-
.WithLayout(ILTypeDefLayout.Auto)
4358-
.WithInitSemantics(ILTypeInit.BeforeField)
4359-
.WithEncoding(ILDefaultPInvokeEncoding.Auto)
4360-
4361-
cgbuf.mgbuf.AddTypeDef(ilContractTypeRef, ilContractTypeDef, false, false, None)
4362-
4363-
let ilCtorBody = mkILMethodBody (true, [], 8, nonBranchingInstrsToCode (mkCallBaseConstructor(ilContractTy, [])), None )
4364-
let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.cloILFormalRetTy), MethodBody.IL ilCloBody) ]
4365-
let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCtorBody, cloMethods, [], ilContractTy, [])
4366-
cloTypeDefs
4367-
4368-
else
4369-
GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCloBody, [], [], g.ilg.typ_Object, [])
4370-
CountClosure()
4371-
for cloTypeDef in cloTypeDefs do
4372-
cgbuf.mgbuf.AddTypeDef(ilCloTypeRef, cloTypeDef, false, false, None)
4376+
DelayGenMethodForLambda cenv cgbuf.mgbuf eenv (entryPointInfo, cloinfo, eenvinner, body, isLocalTypeFunc, m)
43734377
cloinfo, m
43744378

43754379
| _ -> failwith "GenLambda: not a lambda"

src/fsharp/Optimizer.fs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ let [<Literal>] localOptDefault = true
278278

279279
let [<Literal>] crossModuleOptDefault = true
280280

281+
let [<Literal>] LambdaInlineThresholdDefault = 6
282+
281283
type OptimizationSettings =
282284
{ abstractBigTargets : bool
283285

@@ -315,7 +317,7 @@ type OptimizationSettings =
315317
bigTargetSize = 100
316318
veryBigExprSize = 3000
317319
crossModuleOptUser = None
318-
lambdaInlineThreshold = 6
320+
lambdaInlineThreshold = LambdaInlineThresholdDefault
319321
reportingPhase = false
320322
reportNoNeedToTailcall = false
321323
reportFunctionSizes = false
@@ -419,6 +421,14 @@ type IncrementalOptimizationEnv =
419421

420422
override x.ToString() = "<IncrementalOptimizationEnv>"
421423

424+
let SetAbstractBigTargetsOn cenv =
425+
{ cenv with
426+
settings =
427+
{ cenv.settings with
428+
abstractBigTargets = true
429+
}
430+
}
431+
422432
//-------------------------------------------------------------------------
423433
// IsPartialExprVal - is the expr fully known?
424434
//-------------------------------------------------------------------------
@@ -2911,6 +2921,15 @@ and OptimizeLambdas (vspec: Val option) cenv env topValInfo e ety =
29112921
let env = Option.foldBack (BindInternalValToUnknown cenv) baseValOpt env
29122922
let env = BindTypeVarsToUnknown tps env
29132923
let env = List.foldBack (BindInternalValsToUnknown cenv) vsl env
2924+
2925+
let cenv =
2926+
match env.functionVal with
2927+
// If the lambda is compiler generated and we are in the reporing phase, allow lambda to be split.
2928+
// As an example, allows generated GetHashCode/Equals/CompareTo/etc methods to be split even if optimizations were off.
2929+
// This helps prevent stack overflows in IlxGen.fs.
2930+
| Some (v, _) when v.IsCompilerGenerated && cenv.settings.reportingPhase -> SetAbstractBigTargetsOn cenv
2931+
| _ -> cenv
2932+
29142933
let env = BindInternalValsToUnknown cenv (Option.toList baseValOpt) env
29152934
let bodyR, bodyinfo = OptimizeExpr cenv env body
29162935
let exprR = mkMemberLambdas m tps ctorThisValOpt baseValOpt vsl (bodyR, bodyty)

src/fsharp/Optimizer.fsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,7 @@ val UnionOptimizationInfos: seq<ImplFileOptimizationInfo> -> CcuOptimizationInfo
6262
val ExprHasEffect: TcGlobals -> Expr -> bool
6363

6464
val internal u_CcuOptimizationInfo : TastPickle.ReaderState -> CcuOptimizationInfo
65+
66+
// REVIEW: We need to put the literal at the end of a file due to a bug that causes a compiler error when a literal is put in the middle other signature constructs.
67+
[<Literal>]
68+
val LambdaInlineThresholdDefault : int = 6

0 commit comments

Comments
 (0)