Skip to content
This repository has been archived by the owner on Dec 23, 2024. It is now read-only.

Commit

Permalink
Stack-overflow fix (dotnet#10868)
Browse files Browse the repository at this point in the history
* Backing out stackoverflow fix by delayed gen methods

* Trying to lazily gen IL

* Making ILMethodBody.IL be lazy

* Consolidating lazy methodbodies by removing ILLazyMethodBody

* Updating baseline and fixing build

* Minor change
  • Loading branch information
TIHan authored and nosami committed Feb 22, 2021
1 parent 242bd44 commit fd12a2e
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 140 deletions.
49 changes: 30 additions & 19 deletions src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4371,7 +4371,7 @@ and GenObjectMethod cenv eenvinner (cgbuf: CodeGenBuffer) useMethodImpl tmethod
GenGenericParams cenv eenvUnderTypars methTyparsOfOverridingMethod,
ilParamsOfOverridingMethod,
ilReturnOfOverridingMethod,
MethodBody.IL ilMethodBody)
MethodBody.IL (lazy ilMethodBody))
// fixup attributes to generate a method impl
let mdef = if useMethodImpl then fixupMethodImplFlags mdef else mdef
let mdef = fixupVirtualSlotFlags mdef
Expand Down Expand Up @@ -4473,20 +4473,20 @@ and GenSequenceExpr
CG.EmitInstr cgbuf (pop ilCloAllFreeVars.Length) (Push [ilCloRetTyInner]) (I_newobj (formalClospec.Constructor, None))
GenSequel cenv eenv.cloc cgbuf Return),
m)
mkILNonGenericVirtualMethod("GetFreshEnumerator", ILMemberAccess.Public, [], mkILReturn ilCloEnumeratorTy, MethodBody.IL mbody)
mkILNonGenericVirtualMethod("GetFreshEnumerator", ILMemberAccess.Public, [], mkILReturn ilCloEnumeratorTy, MethodBody.IL (lazy mbody))
|> AddNonUserCompilerGeneratedAttribs g

let closeMethod =
// Note: We suppress the first sequence point in the body of this method since it is the initial state machine jump
let spReq = SPSuppress
let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf (spReq, [], "Close", eenvinner, 1, closeExpr, discardAndReturnVoid)
mkILNonGenericVirtualMethod("Close", ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL ilCode)
mkILNonGenericVirtualMethod("Close", ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL (lazy ilCode))

let checkCloseMethod =
// Note: We suppress the first sequence point in the body of this method since it is the initial state machine jump
let spReq = SPSuppress
let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf (spReq, [], "get_CheckClose", eenvinner, 1, checkCloseExpr, Return)
mkILNonGenericVirtualMethod("get_CheckClose", ILMemberAccess.Public, [], mkILReturn g.ilg.typ_Bool, MethodBody.IL ilCode)
mkILNonGenericVirtualMethod("get_CheckClose", ILMemberAccess.Public, [], mkILReturn g.ilg.typ_Bool, MethodBody.IL (lazy ilCode))

let generateNextMethod =
// Note: We suppress the first sequence point in the body of this method since it is the initial state machine jump
Expand All @@ -4495,12 +4495,12 @@ and GenSequenceExpr
let eenvinner = eenvinner |> AddStorageForLocalVals g [ (nextEnumeratorValRef.Deref, Arg 1) ]
let ilParams = [mkILParamNamed("next", ILType.Byref ilCloEnumerableTy)]
let ilReturn = mkILReturn g.ilg.typ_Int32
let ilCode = MethodBody.IL (CodeGenMethodForExpr cenv cgbuf.mgbuf (spReq, [], "GenerateNext", eenvinner, 2, generateNextExpr, Return))
let ilCode = MethodBody.IL (lazy (CodeGenMethodForExpr cenv cgbuf.mgbuf (spReq, [], "GenerateNext", eenvinner, 2, generateNextExpr, Return)))
mkILNonGenericVirtualMethod("GenerateNext", ILMemberAccess.Public, ilParams, ilReturn, ilCode)

let lastGeneratedMethod =
let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf (SPSuppress, [], "get_LastGenerated", eenvinner, 1, exprForValRef m currvref, Return)
mkILNonGenericVirtualMethod("get_LastGenerated", ILMemberAccess.Public, [], mkILReturn ilCloSeqElemTy, MethodBody.IL ilCode)
mkILNonGenericVirtualMethod("get_LastGenerated", ILMemberAccess.Public, [], mkILReturn ilCloSeqElemTy, MethodBody.IL (lazy ilCode))
|> AddNonUserCompilerGeneratedAttribs g

let ilCtorBody =
Expand Down Expand Up @@ -4543,7 +4543,7 @@ and GenClosureTypeDefs cenv (tref: ILTypeRef, ilGenParams, attrs, ilCloAllFreeVa
let fspec = mkILFieldSpec (cloSpec.GetStaticFieldSpec().FieldRef, cloTy)
let ctorSpec = mkILMethSpecForMethRefInTy (cloSpec.Constructor.MethodRef, cloTy, [])
let ilCode = mkILMethodBody (true, [], 8, nonBranchingInstrsToCode ([ I_newobj (ctorSpec, None); mkNormalStsfld fspec ]), None)
let cctor = mkILClassCtor (MethodBody.IL ilCode)
let cctor = mkILClassCtor (MethodBody.IL (lazy ilCode))
let ilFieldDef = mkILStaticField(fspec.Name, fspec.FormalType, None, None, ILMemberAccess.Assembly).WithInitOnly(true)
(cctor :: mdefs), [ ilFieldDef ]
else
Expand Down Expand Up @@ -4642,7 +4642,7 @@ and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc thisVars e
cgbuf.mgbuf.AddTypeDef(ilContractTypeRef, ilContractTypeDef, false, false, None)

let ilCtorBody = mkILMethodBody (true, [], 8, nonBranchingInstrsToCode (mkCallBaseConstructor(ilContractTy, [])), None )
let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.ilCloFormalReturnTy), MethodBody.IL ilCloBody) ]
let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.ilCloFormalReturnTy), MethodBody.IL(lazy ilCloBody)) ]
let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.ilCloAllFreeVars, cloinfo.ilCloLambdas, ilCtorBody, cloMethods, [], ilContractTy, [], Some cloinfo.cloSpec)
cloTypeDefs

Expand Down Expand Up @@ -5039,7 +5039,7 @@ and GenDelegateExpr cenv cgbuf eenvouter expr (TObjExprMethod((TSlotSig(_, deleg
ILMemberAccess.Assembly,
ilDelegeeParams,
ilDelegeeRet,
MethodBody.IL ilMethodBody)
MethodBody.IL(lazy ilMethodBody))
let delegeeCtorMeth = mkILSimpleStorageCtor(None, Some g.ilg.typ_Object.TypeSpec, ilDelegeeTyInner, [], [], ILMemberAccess.Assembly)
let ilCtorBody = delegeeCtorMeth.MethodBody

Expand Down Expand Up @@ -5616,8 +5616,7 @@ and GenBindingAfterDebugPoint cenv cgbuf eenv sp (TBind(vspec, rhsExpr, _)) star

CommitStartScope cgbuf startScopeMarkOpt

// if we have any expression recursion depth, we should delay the generation of a method to prevent stack overflows
let generator = if cenv.exprRecursionDepth > 0 then DelayGenMethodForBinding else GenMethodForBinding
let generator = GenMethodForBinding
let hasWitnessEntry = cenv.g.generateWitnesses && not witnessInfos.IsEmpty

generator cenv cgbuf.mgbuf eenv (vspec, mspec, hasWitnessEntry, false, access, ctps, mtps, [], curriedArgInfos, paramInfos, argTys, retInfo, topValInfo, methLambdaCtorThisValOpt, methLambdaBaseValOpt, methLambdaTypars, methLambdaVars, methLambdaBody, methLambdaBodyTy)
Expand Down Expand Up @@ -5645,7 +5644,8 @@ and GenBindingAfterDebugPoint cenv cgbuf eenv sp (TBind(vspec, rhsExpr, _)) star
cgbuf.mgbuf.AddOrMergePropertyDef(ilGetterMethSpec.MethodRef.DeclaringTypeRef, ilPropDef, m)

let ilMethodDef =
let ilMethodBody = MethodBody.IL(CodeGenMethodForExpr cenv cgbuf.mgbuf (SPSuppress, [], ilGetterMethSpec.Name, eenv, 0, rhsExpr, Return))
let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf (SPSuppress, [], ilGetterMethSpec.Name, eenv, 0, rhsExpr, Return)
let ilMethodBody = MethodBody.IL(lazy ilCode)
(mkILStaticMethod ([], ilGetterMethSpec.Name, access, [], mkILReturn ilTy, ilMethodBody)).WithSpecialName
|> AddNonUserCompilerGeneratedAttribs g

Expand Down Expand Up @@ -6188,10 +6188,20 @@ and GenMethodForBinding
else
body

let ilCode = CodeGenMethodForExpr cenv mgbuf (SPAlways, tailCallInfo, mspec.Name, eenvForMeth, 0, bodyExpr, sequel)
let ilCodeLazy = lazy CodeGenMethodForExpr cenv mgbuf (SPAlways, tailCallInfo, mspec.Name, eenvForMeth, 0, bodyExpr, sequel)

// This is the main code generation for most methods
false, MethodBody.IL ilCode, false
false, MethodBody.IL(ilCodeLazy), false

match ilMethodBody with
| MethodBody.IL(ilCodeLazy) ->
if cenv.exprRecursionDepth > 0 then
cenv.delayedGenMethods.Enqueue(fun _ -> ilCodeLazy.Force() |> ignore)
else
// Eagerly codegen if we are not in an expression depth.
ilCodeLazy.Force() |> ignore
| _ ->
()

// Do not generate DllImport attributes into the code - they are implicit from the P/Invoke
let attrs =
Expand Down Expand Up @@ -6396,7 +6406,7 @@ and GenPInvokeMethod (nm, dll, namedArgs) =

let hasPreserveSigNamedArg = decoder.FindBool "PreserveSig" true
hasPreserveSigNamedArg,
MethodBody.PInvoke
let pinvoke =
{ Where=mkSimpleModRef dll
Name=decoder.FindString "EntryPoint" nm
CallingConv=
Expand All @@ -6417,7 +6427,8 @@ and GenPInvokeMethod (nm, dll, namedArgs) =
NoMangle= decoder.FindBool "ExactSpelling" false
LastError= decoder.FindBool "SetLastError" false
ThrowOnUnmappableChar= if (decoder.FindBool "ThrowOnUnmappableChar" false) then PInvokeThrowOnUnmappableChar.Enabled else PInvokeThrowOnUnmappableChar.UseAssembly
CharBestFit=if (decoder.FindBool "BestFitMapping" false) then PInvokeCharBestFit.Enabled else PInvokeCharBestFit.UseAssembly }
CharBestFit=if (decoder.FindBool "BestFitMapping" false) then PInvokeCharBestFit.Enabled else PInvokeCharBestFit.UseAssembly } : PInvokeMethod
MethodBody.PInvoke(lazy pinvoke)

and GenBindings cenv cgbuf eenv binds = List.iter (GenBinding cenv cgbuf eenv) binds

Expand Down Expand Up @@ -7033,7 +7044,7 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: TypedI
// This adds the explicit init of the .cctor to the explicit entry point main method
mgbuf.AddExplicitInitToSpecificMethodDef((fun md -> md.IsEntryPoint), tref, fspec, GenPossibleILSourceMarker cenv m, feefee, seqpt))

let cctorMethDef = mkILClassCtor (MethodBody.IL topCode)
let cctorMethDef = mkILClassCtor (MethodBody.IL (lazy topCode))
mgbuf.AddMethodDef(initClassTy.TypeRef, cctorMethDef)

// Final file, implicit entry point. We generate no .cctor.
Expand All @@ -7048,7 +7059,7 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: TypedI

// generate main@
let ilMainMethodDef =
let mdef = mkILNonGenericStaticMethod(mainMethName, ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL topCode)
let mdef = mkILNonGenericStaticMethod(mainMethName, ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL (lazy topCode))
mdef.With(isEntryPoint= true, customAttrs = ilAttrs)

mgbuf.AddMethodDef(initClassTy.TypeRef, ilMainMethodDef)
Expand All @@ -7058,7 +7069,7 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: TypedI
| None ->
if doesSomething then
// Add the cctor
let cctorMethDef = mkILClassCtor (MethodBody.IL topCode)
let cctorMethDef = mkILClassCtor (MethodBody.IL (lazy topCode))
mgbuf.AddMethodDef(initClassTy.TypeRef, cctorMethDef)

// Commit the directed initializations
Expand Down
67 changes: 31 additions & 36 deletions src/fsharp/absil/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,28 +1498,18 @@ type ILMethodVirtualInfo =

[<RequireQualifiedAccess>]
type MethodBody =
| IL of ILMethodBody
| PInvoke of PInvokeMethod (* platform invoke to native *)
| IL of Lazy<ILMethodBody>
| PInvoke of Lazy<PInvokeMethod> (* platform invoke to native *)
| Abstract
| Native
| NotAvailable

type ILLazyMethodBody =
| ILLazyMethodBody of Lazy<MethodBody >

member x.Contents = let (ILLazyMethodBody mb) = x in mb.Force()
static member NotAvailable = ILLazyMethodBody (notlazy MethodBody.NotAvailable)

[<RequireQualifiedAccess>]
type MethodCodeKind =
| IL
| Native
| Runtime

let mkMethBodyAux mb = ILLazyMethodBody (notlazy mb)

let mkMethBodyLazyAux mb = ILLazyMethodBody mb

let typesOfILParams (ps: ILParameters) : ILTypes = ps |> List.map (fun p -> p.Type)

[<StructuralEquality; StructuralComparison>]
Expand Down Expand Up @@ -1575,13 +1565,15 @@ let NoMetadataIdx = -1

[<NoComparison; NoEquality>]
type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: MethodImplAttributes, callingConv: ILCallingConv,
parameters: ILParameters, ret: ILReturn, body: ILLazyMethodBody, isEntryPoint: bool, genericParams: ILGenericParameterDefs,
parameters: ILParameters, ret: ILReturn, body: Lazy<MethodBody>, isEntryPoint: bool, genericParams: ILGenericParameterDefs,
securityDeclsStored: ILSecurityDeclsStored, customAttrsStored: ILAttributesStored, metadataIndex: int32) =

new (name, attributes, implAttributes, callingConv, parameters, ret, body, isEntryPoint, genericParams, securityDecls, customAttrs) =
ILMethodDef (name, attributes, implAttributes, callingConv, parameters, ret, body, isEntryPoint, genericParams,
storeILSecurityDecls securityDecls, storeILCustomAttrs customAttrs, NoMetadataIdx)

member private _.LazyBody = body

// The captured data - remember the object will be as large as the data captured by these members
member _.Name = name

Expand All @@ -1595,7 +1587,7 @@ type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: Me

member _.Return = ret

member _.Body = body
member _.Body = body.Value

member _.SecurityDeclsStored = securityDeclsStored

Expand All @@ -1609,7 +1601,7 @@ type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: Me

member x.With (?name: string, ?attributes: MethodAttributes, ?implAttributes: MethodImplAttributes,
?callingConv: ILCallingConv, ?parameters: ILParameters, ?ret: ILReturn,
?body: ILLazyMethodBody, ?securityDecls: ILSecurityDecls, ?isEntryPoint: bool,
?body: Lazy<MethodBody>, ?securityDecls: ILSecurityDecls, ?isEntryPoint: bool,
?genericParams: ILGenericParameterDefs, ?customAttrs: ILAttributes) =

ILMethodDef (name = defaultArg name x.Name,
Expand All @@ -1618,7 +1610,7 @@ type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: Me
callingConv = defaultArg callingConv x.CallingConv,
parameters = defaultArg parameters x.Parameters,
ret = defaultArg ret x.Return,
body = defaultArg body x.Body,
body = defaultArg body x.LazyBody,
securityDecls = (match securityDecls with None -> x.SecurityDecls | Some attrs -> attrs),
isEntryPoint = defaultArg isEntryPoint x.IsEntryPoint,
genericParams = defaultArg genericParams x.GenericParams,
Expand All @@ -1631,15 +1623,15 @@ type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: Me
member x.ParameterTypes = typesOfILParams x.Parameters

member md.Code =
match md.Body.Contents with
| MethodBody.IL il-> Some il.Code
match md.Body with
| MethodBody.IL il-> Some il.Value.Code
| _ -> None

member x.IsIL = match x.Body.Contents with | MethodBody.IL _ -> true | _ -> false
member x.IsIL = match x.Body with | MethodBody.IL _ -> true | _ -> false

member x.Locals = match x.Body.Contents with | MethodBody.IL il -> il.Locals | _ -> []
member x.Locals = match x.Body with | MethodBody.IL il -> il.Value.Locals | _ -> []

member x.MethodBody = match x.Body.Contents with MethodBody.IL il -> il | _ -> failwith "not IL"
member x.MethodBody = match x.Body with MethodBody.IL il -> il.Value | _ -> failwith "not IL"

member x.SourceMarker = x.MethodBody.SourceMarker

Expand Down Expand Up @@ -2890,19 +2882,21 @@ let mkILMethodBody (zeroinit, locals, maxstack, code, tag) : ILMethodBody =
Code= code
SourceMarker=tag }

let mkMethodBody (zeroinit, locals, maxstack, code, tag) = MethodBody.IL (mkILMethodBody (zeroinit, locals, maxstack, code, tag))
let mkMethodBody (zeroinit, locals, maxstack, code, tag) =
let ilCode = mkILMethodBody (zeroinit, locals, maxstack, code, tag)
MethodBody.IL (lazy ilCode)

// --------------------------------------------------------------------
// Make a constructor
// --------------------------------------------------------------------

let mkILVoidReturn = mkILReturn ILType.Void

let methBodyNotAvailable = mkMethBodyAux MethodBody.NotAvailable
let methBodyNotAvailable = notlazy MethodBody.NotAvailable

let methBodyAbstract = mkMethBodyAux MethodBody.Abstract
let methBodyAbstract = notlazy MethodBody.Abstract

let methBodyNative = mkMethBodyAux MethodBody.Native
let methBodyNative = notlazy MethodBody.Native

let mkILCtor (access, args, impl) =
ILMethodDef(name=".ctor",
Expand All @@ -2911,7 +2905,7 @@ let mkILCtor (access, args, impl) =
callingConv=ILCallingConv.Instance,
parameters = args,
ret= mkILVoidReturn,
body= mkMethBodyAux impl,
body= notlazy impl,
securityDecls=emptyILSecurityDecls,
isEntryPoint=false,
genericParams=mkILEmptyGenericParams,
Expand Down Expand Up @@ -2960,7 +2954,7 @@ let mkILStaticMethod (genparams, nm, access, args, ret, impl) =
securityDecls=emptyILSecurityDecls,
isEntryPoint=false,
customAttrs = emptyILCustomAttrs,
body= mkMethBodyAux impl)
body= notlazy impl)

let mkILNonGenericStaticMethod (nm, access, args, ret, impl) =
mkILStaticMethod (mkILEmptyGenericParams, nm, access, args, ret, impl)
Expand All @@ -2976,7 +2970,7 @@ let mkILClassCtor impl =
isEntryPoint=false,
securityDecls=emptyILSecurityDecls,
customAttrs=emptyILCustomAttrs,
body= mkMethBodyAux impl)
body= notlazy impl)

// --------------------------------------------------------------------
// Make a virtual method, where the overriding is simply the default
Expand All @@ -3000,7 +2994,7 @@ let mkILGenericVirtualMethod (nm, access, genparams, actual_args, actual_ret, im
isEntryPoint=false,
securityDecls=emptyILSecurityDecls,
customAttrs = emptyILCustomAttrs,
body= mkMethBodyAux impl)
body= notlazy impl)

let mkILNonGenericVirtualMethod (nm, access, args, ret, impl) =
mkILGenericVirtualMethod (nm, access, mkILEmptyGenericParams, args, ret, impl)
Expand All @@ -3016,7 +3010,7 @@ let mkILGenericNonVirtualMethod (nm, access, genparams, actual_args, actual_ret,
isEntryPoint=false,
securityDecls=emptyILSecurityDecls,
customAttrs = emptyILCustomAttrs,
body= mkMethBodyAux impl)
body= notlazy impl)

let mkILNonGenericInstanceMethod (nm, access, args, ret, impl) =
mkILGenericNonVirtualMethod (nm, access, mkILEmptyGenericParams, args, ret, impl)
Expand All @@ -3032,11 +3026,12 @@ let ilmbody_code2code f (il: ILMethodBody) =

let mdef_code2code f (md: ILMethodDef) =
let il =
match md.Body.Contents with
match md.Body with
| MethodBody.IL il-> il
| _ -> failwith "mdef_code2code - method not IL"
let b = MethodBody.IL (ilmbody_code2code f il)
md.With(body = mkMethBodyAux b)
let ilCode = ilmbody_code2code f il.Value
let b = MethodBody.IL (notlazy ilCode)
md.With(body = notlazy b)

let prependInstrsToCode (instrs: ILInstr list) (c2: ILCode) =
let instrs = Array.ofList instrs
Expand Down Expand Up @@ -4122,14 +4117,14 @@ and refs_of_local s loc = refs_of_typ s loc.Type

and refs_of_mbody s x =
match x with
| MethodBody.IL il -> refs_of_ilmbody s il
| MethodBody.PInvoke (attr) -> refs_of_modref s attr.Where
| MethodBody.IL il -> refs_of_ilmbody s il.Value
| MethodBody.PInvoke (attr) -> refs_of_modref s attr.Value.Where
| _ -> ()

and refs_of_mdef s (md: ILMethodDef) =
List.iter (refs_of_param s) md.Parameters
refs_of_return s md.Return
refs_of_mbody s md.Body.Contents
refs_of_mbody s md.Body
refs_of_custom_attrs s md.CustomAttrs
refs_of_genparams s md.GenericParams

Expand Down
Loading

0 comments on commit fd12a2e

Please sign in to comment.