Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack-overflow fix #10868

Merged
merged 6 commits into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1547,28 +1547,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 @@ -1624,13 +1614,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 @@ -1644,7 +1636,7 @@ type ILMethodDef (name: string, attributes: MethodAttributes, implAttributes: Me

member _.Return = ret

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

member _.SecurityDeclsStored = securityDeclsStored

Expand All @@ -1658,7 +1650,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 @@ -1667,7 +1659,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 @@ -1680,15 +1672,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 @@ -2938,19 +2930,21 @@ let mkILMethodBody (initlocals, 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 @@ -2959,7 +2953,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 @@ -3008,7 +3002,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 @@ -3024,7 +3018,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 @@ -3048,7 +3042,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 @@ -3064,7 +3058,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 @@ -3080,11 +3074,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 @@ -4170,14 +4165,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