@@ -245,6 +245,12 @@ type cenv =
245245
246246 /// Used to apply forced inlining optimizations to witnesses generated late during codegen
247247 mutable optimizeDuringCodeGen: ( Expr -> Expr )
248+
249+ /// What depth are we at when generating an expression?
250+ mutable exprRecursionDepth: int
251+
252+ /// Delayed Method Generation - prevents stack overflows when we need to generate methods that are split into many methods by the optimizer.
253+ delayedGenMethods: Queue < cenv -> unit >
248254 }
249255
250256
@@ -2130,20 +2136,53 @@ let DoesGenExprStartWithSequencePoint g sp expr =
21302136 FirstEmittedCodeWillBeSequencePoint g sp expr ||
21312137 EmitSequencePointForWholeExpr g sp expr
21322138
2139+ let ProcessSequencePointForExpr ( cenv : cenv ) ( cgbuf : CodeGenBuffer ) sp expr =
2140+ let g = cenv.g
2141+ if not ( FirstEmittedCodeWillBeSequencePoint g sp expr) then
2142+ if EmitSequencePointForWholeExpr g sp expr then
2143+ CG.EmitSeqPoint cgbuf ( RangeOfSequencePointForWholeExpr g expr)
2144+ elif EmitHiddenCodeMarkerForWholeExpr g sp expr then
2145+ cgbuf.EmitStartOfHiddenCode()
2146+
21332147//-------------------------------------------------------------------------
21342148// Generate expressions
21352149//-------------------------------------------------------------------------
21362150
2137- let rec GenExpr ( cenv : cenv ) ( cgbuf : CodeGenBuffer ) eenv sp expr sequel =
2151+ let rec GenExpr cenv cgbuf eenv sp ( expr : Expr ) sequel =
2152+ cenv.exprRecursionDepth <- cenv.exprRecursionDepth + 1
2153+
2154+ if cenv.exprRecursionDepth > 1 then
2155+ StackGuard.EnsureSufficientExecutionStack cenv.exprRecursionDepth
2156+ GenExprAux cenv cgbuf eenv sp expr sequel
2157+ else
2158+ GenExprWithStackGuard cenv cgbuf eenv sp expr sequel
2159+
2160+ cenv.exprRecursionDepth <- cenv.exprRecursionDepth - 1
2161+
2162+ if cenv.exprRecursionDepth = 0 then
2163+ ProcessDelayedGenMethods cenv
2164+
2165+ and ProcessDelayedGenMethods cenv =
2166+ while cenv.delayedGenMethods.Count > 0 do
2167+ let gen = cenv.delayedGenMethods.Dequeue ()
2168+ gen cenv
2169+
2170+ and GenExprWithStackGuard cenv cgbuf eenv sp expr sequel =
2171+ assert ( cenv.exprRecursionDepth = 1 )
2172+ try
2173+ GenExprAux cenv cgbuf eenv sp expr sequel
2174+ assert ( cenv.exprRecursionDepth = 1 )
2175+ with
2176+ | :? System.InsufficientExecutionStackException ->
2177+ error( InternalError( " Expression is too large and/or complex to emit." , expr.Range))
2178+
2179+ and GenExprAux ( cenv : cenv ) ( cgbuf : CodeGenBuffer ) eenv sp expr sequel =
21382180 let g = cenv.g
21392181 let expr = stripExpr expr
21402182
2141- if not ( FirstEmittedCodeWillBeSequencePoint g sp expr) then
2142- if EmitSequencePointForWholeExpr g sp expr then
2143- CG.EmitSeqPoint cgbuf ( RangeOfSequencePointForWholeExpr g expr)
2144- elif EmitHiddenCodeMarkerForWholeExpr g sp expr then
2145- cgbuf.EmitStartOfHiddenCode()
2183+ ProcessSequencePointForExpr cenv cgbuf sp expr
21462184
2185+ // A sequence expression will always match Expr.App.
21472186 match ( if compileSequenceExpressions then LowerCallsAndSeqs.LowerSeqExpr g cenv.amap expr else None) with
21482187 | Some info ->
21492188 GenSequenceExpr cenv cgbuf eenv info sequel
@@ -2154,32 +2193,8 @@ let rec GenExpr (cenv: cenv) (cgbuf: CodeGenBuffer) eenv sp expr sequel =
21542193 GenConstant cenv cgbuf eenv ( c, m, ty) sequel
21552194 | Expr.Match ( spBind, exprm, tree, targets, m, ty) ->
21562195 GenMatch cenv cgbuf eenv ( spBind, exprm, tree, targets, m, ty) sequel
2157- | Expr.Sequential ( e1, e2, dir, spSeq, m) ->
2158- GenSequential cenv cgbuf eenv sp ( e1, e2, dir, spSeq, m) sequel
21592196 | Expr.LetRec ( binds, body, m, _) ->
21602197 GenLetRec cenv cgbuf eenv ( binds, body, m) sequel
2161- | Expr.Let ( bind, body, _, _) ->
2162- // This case implemented here to get a guaranteed tailcall
2163- // Make sure we generate the sequence point outside the scope of the variable
2164- let startScope , endScope as scopeMarks = StartDelayedLocalScope " let" cgbuf
2165- let eenv = AllocStorageForBind cenv cgbuf scopeMarks eenv bind
2166- let spBind = GenSequencePointForBind cenv cgbuf bind
2167- GenBindingAfterSequencePoint cenv cgbuf eenv spBind bind ( Some startScope)
2168-
2169- // Work out if we need a sequence point for the body. For any "user" binding then the body gets SPAlways.
2170- // For invisible compiler-generated bindings we just use "sp", unless its body is another invisible binding
2171- // For sticky bindings arising from inlining we suppress any immediate sequence point in the body
2172- let spBody =
2173- match bind.SequencePointInfo with
2174- | SequencePointAtBinding _
2175- | NoSequencePointAtLetBinding
2176- | NoSequencePointAtDoBinding -> SPAlways
2177- | NoSequencePointAtInvisibleBinding -> sp
2178- | NoSequencePointAtStickyBinding -> SPSuppress
2179-
2180- // Generate the body
2181- GenExpr cenv cgbuf eenv spBody body ( EndLocalScope( sequel, endScope))
2182-
21832198 | Expr.Lambda _ | Expr.TyLambda _ ->
21842199 GenLambda cenv cgbuf eenv false None expr sequel
21852200 | Expr.App ( Expr.Val ( vref, _, m) as v, _, tyargs, [], _) when
@@ -2200,8 +2215,10 @@ let rec GenExpr (cenv: cenv) (cgbuf: CodeGenBuffer) eenv sp expr sequel =
22002215 // Most generation of linear expressions is implemented routinely using tailcalls and the correct sequels.
22012216 // This is because the element of expansion happens to be the final thing generated in most cases. However
22022217 // for large lists we have to process the linearity separately
2218+ | Expr.Sequential _
2219+ | Expr.Let _
22032220 | LinearOpExpr _ ->
2204- GenLinearExpr cenv cgbuf eenv expr sequel id |> ignore< FakeUnit>
2221+ GenLinearExpr cenv cgbuf eenv sp expr sequel (* canProcessSequencePoint *) false id |> ignore< FakeUnit>
22052222
22062223 | Expr.Op ( op, tyargs, args, m) ->
22072224 match op, args, tyargs with
@@ -2515,16 +2532,63 @@ and GenAllocUnionCase cenv cgbuf eenv (c,tyargs,args,m) sequel =
25152532 GenAllocUnionCaseCore cenv cgbuf eenv ( c, tyargs, args.Length, m)
25162533 GenSequel cenv eenv.cloc cgbuf sequel
25172534
2518- and GenLinearExpr cenv cgbuf eenv expr sequel ( contf : FakeUnit -> FakeUnit ) =
2519- match expr with
2520- | LinearOpExpr ( TOp.UnionCase c, tyargs, argsFront, argLast, m) ->
2535+ and GenLinearExpr cenv cgbuf eenv sp expr sequel canProcessSequencePoint ( contf : FakeUnit -> FakeUnit ) =
2536+ match stripExpr expr with
2537+ | LinearOpExpr ( TOp.UnionCase c, tyargs, argsFront, argLast, m) ->
25212538 GenExprs cenv cgbuf eenv argsFront
2522- GenLinearExpr cenv cgbuf eenv argLast Continue ( contf << ( fun Fake ->
2539+ GenLinearExpr cenv cgbuf eenv SPSuppress argLast Continue (* canProcessSequencePoint *) true ( contf << ( fun Fake ->
25232540 GenAllocUnionCaseCore cenv cgbuf eenv ( c, tyargs, argsFront.Length + 1 , m)
25242541 GenSequel cenv eenv.cloc cgbuf sequel
25252542 Fake))
2543+
2544+ | Expr.Sequential ( e1, e2, specialSeqFlag, spSeq, _) ->
2545+ if canProcessSequencePoint then
2546+ ProcessSequencePointForExpr cenv cgbuf sp expr
2547+
2548+ // Compiler generated sequential executions result in suppressions of sequence points on both
2549+ // left and right of the sequence
2550+ let spAction , spExpr =
2551+ ( match spSeq with
2552+ | SequencePointsAtSeq -> SPAlways, SPAlways
2553+ | SuppressSequencePointOnExprOfSequential -> SPSuppress, sp
2554+ | SuppressSequencePointOnStmtOfSequential -> sp, SPSuppress)
2555+ match specialSeqFlag with
2556+ | NormalSeq ->
2557+ GenExpr cenv cgbuf eenv spAction e1 discard
2558+ GenLinearExpr cenv cgbuf eenv spExpr e2 sequel (* canProcessSequencePoint *) true contf
2559+ | ThenDoSeq ->
2560+ GenExpr cenv cgbuf eenv spExpr e1 Continue
2561+ GenExpr cenv cgbuf eenv spAction e2 discard
2562+ GenSequel cenv eenv.cloc cgbuf sequel
2563+ contf Fake
2564+
2565+ | Expr.Let ( bind, body, _, _) ->
2566+ if canProcessSequencePoint then
2567+ ProcessSequencePointForExpr cenv cgbuf sp expr
2568+
2569+ // This case implemented here to get a guaranteed tailcall
2570+ // Make sure we generate the sequence point outside the scope of the variable
2571+ let startScope , endScope as scopeMarks = StartDelayedLocalScope " let" cgbuf
2572+ let eenv = AllocStorageForBind cenv cgbuf scopeMarks eenv bind
2573+ let spBind = GenSequencePointForBind cenv cgbuf bind
2574+ GenBindingAfterSequencePoint cenv cgbuf eenv spBind bind ( Some startScope)
2575+
2576+ // Work out if we need a sequence point for the body. For any "user" binding then the body gets SPAlways.
2577+ // For invisible compiler-generated bindings we just use "sp", unless its body is another invisible binding
2578+ // For sticky bindings arising from inlining we suppress any immediate sequence point in the body
2579+ let spBody =
2580+ match bind.SequencePointInfo with
2581+ | SequencePointAtBinding _
2582+ | NoSequencePointAtLetBinding
2583+ | NoSequencePointAtDoBinding -> SPAlways
2584+ | NoSequencePointAtInvisibleBinding -> sp
2585+ | NoSequencePointAtStickyBinding -> SPSuppress
2586+
2587+ // Generate the body
2588+ GenLinearExpr cenv cgbuf eenv spBody body ( EndLocalScope( sequel, endScope)) (* canProcessSequencePoint *) true contf
2589+
25262590 | _ ->
2527- GenExpr cenv cgbuf eenv SPSuppress expr sequel
2591+ GenExpr cenv cgbuf eenv sp expr sequel
25282592 contf Fake
25292593
25302594and GenAllocRecd cenv cgbuf eenv ctorInfo ( tcref , argtys , args , m ) sequel =
@@ -3475,28 +3539,6 @@ and GenWhileLoop cenv cgbuf eenv (spWhile, e1, e2, m) sequel =
34753539 // SEQUENCE POINTS: Emit a sequence point to cover 'done' if present
34763540 GenUnitThenSequel cenv eenv m eenv.cloc cgbuf sequel
34773541
3478- //--------------------------------------------------------------------------
3479- // Generate seq
3480- //--------------------------------------------------------------------------
3481-
3482- and GenSequential cenv cgbuf eenv spIn ( e1 , e2 , specialSeqFlag , spSeq , _m ) sequel =
3483-
3484- // Compiler generated sequential executions result in suppressions of sequence points on both
3485- // left and right of the sequence
3486- let spAction , spExpr =
3487- ( match spSeq with
3488- | SequencePointsAtSeq -> SPAlways, SPAlways
3489- | SuppressSequencePointOnExprOfSequential -> SPSuppress, spIn
3490- | SuppressSequencePointOnStmtOfSequential -> spIn, SPSuppress)
3491- match specialSeqFlag with
3492- | NormalSeq ->
3493- GenExpr cenv cgbuf eenv spAction e1 discard
3494- GenExpr cenv cgbuf eenv spExpr e2 sequel
3495- | ThenDoSeq ->
3496- GenExpr cenv cgbuf eenv spExpr e1 Continue
3497- GenExpr cenv cgbuf eenv spAction e2 discard
3498- GenSequel cenv eenv.cloc cgbuf sequel
3499-
35003542//--------------------------------------------------------------------------
35013543// Generate IL assembly code.
35023544// Polymorphic IL/ILX instructions may be instantiated when polymorphic code is inlined.
@@ -5210,7 +5252,14 @@ and GenBindingAfterSequencePoint cenv cgbuf eenv sp (TBind(vspec, rhsExpr, _)) s
52105252 let tps , ctorThisValOpt , baseValOpt , vsl , body' , bodyty = IteratedAdjustArityOfLambda g cenv.amap topValInfo rhsExpr
52115253 let methodVars = List.concat vsl
52125254 CommitStartScope cgbuf startScopeMarkOpt
5213- GenMethodForBinding cenv cgbuf eenv ( vspec, mspec, access, paramInfos, retInfo) ( topValInfo, ctorThisValOpt, baseValOpt, tps, methodVars, methodArgTys, body', bodyty)
5255+
5256+ let ilxMethInfoArgs =
5257+ ( vspec, mspec, access, paramInfos, retInfo, topValInfo, ctorThisValOpt, baseValOpt, tps, methodVars, methodArgTys, body', bodyty)
5258+ // if we have any expression recursion depth, we should delay the generation of a method to prevent stack overflows
5259+ if cenv.exprRecursionDepth > 0 then
5260+ DelayGenMethodForBinding cenv cgbuf.mgbuf eenv ilxMethInfoArgs
5261+ else
5262+ GenMethodForBinding cenv cgbuf.mgbuf eenv ilxMethInfoArgs
52145263
52155264 | StaticProperty ( ilGetterMethSpec, optShadowLocal) ->
52165265
@@ -5649,11 +5698,10 @@ and ComputeMethodImplAttribs cenv (_v: Val) attrs =
56495698 let hasAggressiveInliningImplFlag = ( implflags &&& 0x0100 ) <> 0x0
56505699 hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningImplFlag, hasAggressiveInliningImplFlag, attrs
56515700
5652- and GenMethodForBinding
5653- cenv cgbuf eenv
5654- ( v : Val , mspec , access , paramInfos , retInfo )
5655- ( topValInfo , ctorThisValOpt , baseValOpt , tps , methodVars , methodArgTys , body , returnTy ) =
5701+ and DelayGenMethodForBinding cenv mgbuf eenv ilxMethInfoArgs =
5702+ cenv.delayedGenMethods.Enqueue ( fun cenv -> GenMethodForBinding cenv mgbuf eenv ilxMethInfoArgs)
56565703
5704+ and GenMethodForBinding cenv mgbuf eenv ( v , mspec , access , paramInfos , retInfo , topValInfo , ctorThisValOpt , baseValOpt , tps , methodVars , methodArgTys , body , returnTy ) =
56575705 let g = cenv.g
56585706 let m = v.Range
56595707 let selfMethodVars , nonSelfMethodVars , compileAsInstance =
@@ -5714,7 +5762,7 @@ and GenMethodForBinding
57145762 else
57155763 body
57165764
5717- let ilCode = CodeGenMethodForExpr cenv cgbuf. mgbuf ( SPAlways, tailCallInfo, mspec.Name, eenvForMeth, 0 , bodyExpr, sequel)
5765+ let ilCode = CodeGenMethodForExpr cenv mgbuf ( SPAlways, tailCallInfo, mspec.Name, eenvForMeth, 0 , bodyExpr, sequel)
57185766
57195767 // This is the main code generation for most methods
57205768 false , MethodBody.IL ilCode, false
@@ -5780,7 +5828,7 @@ and GenMethodForBinding
57805828 else
57815829 mdef
57825830 CountMethodDef()
5783- cgbuf. mgbuf.AddMethodDef( tref, mdef)
5831+ mgbuf.AddMethodDef( tref, mdef)
57845832
57855833
57865834 match v.MemberInfo with
@@ -5817,7 +5865,7 @@ and GenMethodForBinding
58175865 let mdef = List.fold ( fun mdef f -> f mdef) mdef flagFixups
58185866
58195867 // fixup can potentially change name of reflected definition that was already recorded - patch it if necessary
5820- cgbuf. mgbuf.ReplaceNameOfReflectedDefinition( v, mdef.Name)
5868+ mgbuf.ReplaceNameOfReflectedDefinition( v, mdef.Name)
58215869 mdef
58225870 else
58235871 mkILGenericNonVirtualMethod ( v.CompiledName g.CompilerGlobalState, access, ilMethTypars, ilParams, ilReturn, ilMethodBody)
@@ -5844,7 +5892,7 @@ and GenMethodForBinding
58445892 // Emit the pseudo-property as an event, but not if its a private method impl
58455893 if mdef.Access <> ILMemberAccess.Private then
58465894 let edef = GenEventForProperty cenv eenvForMeth mspec v ilAttrsThatGoOnPrimaryItem m returnTy
5847- cgbuf. mgbuf.AddEventDef( tref, edef)
5895+ mgbuf.AddEventDef( tref, edef)
58485896 // The method def is dropped on the floor here
58495897
58505898 else
@@ -5854,7 +5902,7 @@ and GenMethodForBinding
58545902 let ilPropTy = GenType cenv.amap m eenvUnderMethTypeTypars.tyenv vtyp
58555903 let ilArgTys = v |> ArgInfosOfPropertyVal g |> List.map fst |> GenTypes cenv.amap m eenvUnderMethTypeTypars.tyenv
58565904 let ilPropDef = GenPropertyForMethodDef compileAsInstance tref mdef v memberInfo ilArgTys ilPropTy ( mkILCustomAttrs ilAttrsThatGoOnPrimaryItem) compiledName
5857- cgbuf. mgbuf.AddOrMergePropertyDef( tref, ilPropDef, m)
5905+ mgbuf.AddOrMergePropertyDef( tref, ilPropDef, m)
58585906
58595907 // Add the special name flag for all properties
58605908 let mdef = mdef.WithSpecialName.With( customAttrs= mkILCustomAttrs (( GenAttrs cenv eenv attrsAppliedToGetterOrSetter) @ sourceNameAttribs @ ilAttrsCompilerGenerated))
@@ -7668,7 +7716,9 @@ type IlxAssemblyGenerator(amap: ImportMap, tcGlobals: TcGlobals, tcVal: Constrai
76687716 casApplied = casApplied
76697717 intraAssemblyInfo = intraAssemblyInfo
76707718 opts = codeGenOpts
7671- optimizeDuringCodeGen = ( fun x -> x) }
7719+ optimizeDuringCodeGen = ( fun x -> x)
7720+ exprRecursionDepth = 0
7721+ delayedGenMethods = Queue () }
76727722 GenerateCode ( cenv, anonTypeTable, ilxGenEnv, typedAssembly, assemAttribs, moduleAttribs)
76737723
76747724 /// Invert the compilation of the given value and clear the storage of the value
0 commit comments