PageRenderTime 37ms CodeModel.GetById 12ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/Runtime/Microsoft.Dynamic/Debugging/DebuggableLambdaBuilder.cs

http://github.com/IronLanguages/main
C# | 740 lines | 553 code | 116 blank | 71 comment | 71 complexity | 605688a6accb64e0bbbfc5417554603c MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if FEATURE_CORE_DLR
 17using MSAst = System.Linq.Expressions;
 18#else
 19using MSAst = Microsoft.Scripting.Ast;
 20#endif
 21
 22using System;
 23using System.Collections.Generic;
 24using System.Diagnostics;
 25using System.Reflection;
 26using Microsoft.Scripting.Ast;
 27using Microsoft.Scripting.Debugging.CompilerServices;
 28using Microsoft.Scripting.Utils;
 29using AstUtils = Microsoft.Scripting.Ast.Utils;
 30
 31namespace Microsoft.Scripting.Debugging {
 32    using Ast = MSAst.Expression;
 33
 34    /// <summary>
 35    /// DebuggableLambdaBuilder is used to transform a DLR expression tree into a debuggable lambda expression.
 36    /// </summary>
 37    internal class DebuggableLambdaBuilder {
 38        private readonly DebugContext _debugContext;                                    // DebugContext
 39        private Dictionary<DebugSourceFile, MSAst.ParameterExpression> _sourceFilesMap; // Map of source file instances to their variable nodes
 40        private readonly DebugLambdaInfo _lambdaInfo;                                   // Labmda info that's passed to us by the compiler
 41        private string _alias;                                                          // Lambda alias
 42        private readonly MSAst.Expression _debugContextExpression;                      // DebugContext Expression
 43        private readonly MSAst.Expression _globalDebugMode;                             // Global DebugMode expression
 44        private MSAst.LabelTarget _generatorLabelTarget;                                // Generator label target
 45        private DebugSourceSpan[] _debugMarkerLocationMap;                              // Map of debug markers to source locations
 46        private IList<VariableInfo>[] _variableScopeMap;                                // Map of debug markers to source locations
 47        private List<MSAst.ParameterExpression> _lambdaVars;                            // List of locals for transformed lambda
 48        private List<MSAst.ParameterExpression> _lambdaParams;                          // List of params for transformed lambda
 49        private List<MSAst.ParameterExpression> _generatorVars;                         // List of locals for generator lambda
 50        private List<MSAst.ParameterExpression> _generatorParams;                       // List of params for generator lambda
 51        private MSAst.ParameterExpression _retVal;                                      // Temp variable used to store the labmda's return value.
 52        private MSAst.Expression _pushFrame;                                            // Push-frame expression
 53        private MSAst.Expression _conditionalPushFrame;                                 // Conditional Push-frame expression
 54        private bool _noPushFrameOptimization;                                          // Flag that specifies whether we're performing the push-frame optimization for this lambda
 55        private readonly List<MSAst.ParameterExpression> _pendingLocals;                // List of original locals
 56        private readonly List<MSAst.ParameterExpression> _verifiedLocals;               // List of post-transform locals
 57        private readonly Dictionary<string, object> _verifiedLocalNames;                // Unique names for locals
 58        private readonly List<VariableInfo> _variableInfos;                             // List of variables that'll be available at runtime
 59        private readonly Dictionary<MSAst.ParameterExpression, VariableInfo> _pendingToVariableInfosMap;               // Map of original locals to their VariableInfo
 60        private readonly Dictionary<MSAst.ParameterExpression, MSAst.ParameterExpression> _pendingToVerifiedLocalsMap; // Map of original locals to post-transform locals
 61        private MSAst.Expression _functionInfo;                                         // Expression that's used to initialize $funcInfo local
 62        private int _lambdaId;
 63
 64        // Static variable/parameter expressions
 65        private static readonly MSAst.ParameterExpression _frame = Ast.Variable(typeof(DebugFrame), "$frame");
 66        private static readonly MSAst.ParameterExpression _thread = Ast.Variable(typeof(DebugThread), "$thread");
 67        private static readonly MSAst.ParameterExpression _debugMarker = Ast.Variable(typeof(int), "$debugMarker");
 68        private static readonly MSAst.ParameterExpression _framePushed = Ast.Variable(typeof(bool), "$framePushed");
 69        private static readonly MSAst.ParameterExpression _funcInfo = Ast.Parameter(typeof(FunctionInfo), "$funcInfo");
 70        private static readonly MSAst.ParameterExpression _traceLocations = Ast.Parameter(typeof(bool[]), "$traceLocations");
 71        private static readonly MSAst.ParameterExpression _retValAsObject = Ast.Variable(typeof(object), "$retVal");
 72        private static readonly MSAst.ParameterExpression _retValFromGeneratorLoop = Ast.Variable(typeof(object), "$retValFromGen");
 73        private static readonly MSAst.ParameterExpression _frameExitException = Ast.Parameter(typeof(bool), "$frameExitException");
 74
 75        internal DebuggableLambdaBuilder(DebugContext debugContext, DebugLambdaInfo lambdaInfo) {
 76            _debugContext = debugContext;
 77            _lambdaInfo = lambdaInfo;
 78
 79            _alias = _lambdaInfo.LambdaAlias;
 80            _debugContextExpression = AstUtils.Constant(debugContext);
 81
 82            // Variables
 83            _verifiedLocals = new List<MSAst.ParameterExpression>();
 84            _verifiedLocalNames = new Dictionary<string, object>();
 85            _pendingLocals = new List<MSAst.ParameterExpression>();
 86            _variableInfos = new List<VariableInfo>();
 87            _pendingToVariableInfosMap = new Dictionary<MSAst.ParameterExpression, VariableInfo>();
 88            _pendingToVerifiedLocalsMap = new Dictionary<MSAst.ParameterExpression, MSAst.ParameterExpression>();
 89
 90            // DebugMode expression that's used by the transformed code to see what the current debug mode is
 91            _globalDebugMode = Ast.Property(_debugContextExpression, "Mode");
 92        }
 93
 94        internal MSAst.LambdaExpression Transform(MSAst.LambdaExpression lambda) {
 95            if (_alias == null) {
 96                _alias = lambda.Name;
 97
 98                if (_alias == null) {
 99                    _alias = "$lambda" + ++_lambdaId;
100                }
101            }
102
103            // Create lambda builders
104            _lambdaVars = new List<MSAst.ParameterExpression>();
105            _lambdaParams = new List<MSAst.ParameterExpression>();
106            _generatorVars = new List<MSAst.ParameterExpression>();
107            _generatorParams = new List<MSAst.ParameterExpression>();
108
109            if (lambda.Body is GeneratorExpression) {
110                return TransformGenerator(lambda);
111            } else {
112                return TransformLambda(lambda);
113            }
114        }
115
116        private MSAst.LambdaExpression TransformLambda(MSAst.LambdaExpression lambda) {
117            MSAst.Expression body = lambda.Body;
118
119            _lambdaVars.AddRange(new[] { _thread, _framePushed, _funcInfo, _traceLocations, _debugMarker, _frameExitException });
120
121            _generatorParams.Add(_frame);
122
123            Type returnType = lambda.Type.GetMethod("Invoke").ReturnType;
124
125            // Create $retVal variable only if the return type isn't void
126            if (returnType == typeof(object))
127                _retVal = _retValAsObject;
128            else if (returnType != typeof(void))
129                _retVal = Ast.Variable(returnType, "$retVal");
130
131            if (_retVal != null) {
132                _lambdaVars.Add(_retVal);
133                _generatorVars.Add(_retVal);
134            }
135
136            _lambdaVars.Add(_retValFromGeneratorLoop);
137
138            Dictionary<MSAst.ParameterExpression, object> parameters = new Dictionary<MSAst.ParameterExpression, object>();
139            foreach (MSAst.ParameterExpression parameter in lambda.Parameters) {
140                parameters.Add(parameter, null);
141            }
142
143            // Add parameters to the pending list
144            _pendingLocals.AddRange(lambda.Parameters);
145
146            // Run 1st tree walk to identify all locals
147            LambdaWalker lambdaWalker = new LambdaWalker();
148            body = lambdaWalker.Visit(body);
149
150            // Add all locals to pending list
151            _pendingLocals.AddRange(lambdaWalker.Locals);
152
153            // Process the variables
154            LayOutVariables(lambdaWalker.StrongBoxedLocals, parameters);
155
156            // Rewrite for generator
157            MSAst.Expression generatorBody = TransformToGeneratorBody(body);
158
159            // Add source file variables
160            _lambdaVars.AddRange(_sourceFilesMap.Values);
161
162            // Create the expression for pushing the frame
163            CreatePushFrameExpression();
164
165            // Rewrite for debuggable body
166            MSAst.Expression debuggableBody = TransformToDebuggableBody(body);
167
168            // Get the generator factory lambda
169            MSAst.LambdaExpression generatorFactoryLambda = CreateGeneratorFactoryLambda(generatorBody);
170
171            // Create FunctionInfo object
172            CreateFunctionInfo(generatorFactoryLambda);
173
174
175            // Create the outer lambda
176            return CreateOuterLambda(lambda.Type, debuggableBody);
177        }
178
179        private MSAst.LambdaExpression TransformGenerator(MSAst.LambdaExpression lambda) {
180            GeneratorExpression generator = (GeneratorExpression)lambda.Body;
181            MSAst.Expression body = generator.Body;
182
183            _generatorLabelTarget = generator.Target;
184
185            // $TODO: Detect if the label's type is not typeof(object), and create a new label
186            Debug.Assert(_generatorLabelTarget.Type == typeof(object));
187
188            _generatorParams.Add(_frame);
189
190            Dictionary<MSAst.ParameterExpression, object> parameters = new Dictionary<MSAst.ParameterExpression, object>();
191            foreach (MSAst.ParameterExpression parameter in lambda.Parameters) {
192                parameters.Add(parameter, null);
193            }
194
195            // Add parameters to the pending list
196            _pendingLocals.AddRange(lambda.Parameters);
197
198            // Run 1st tree walk to identify all locals
199            LambdaWalker lambdaWalker = new LambdaWalker();
200            lambdaWalker.Visit(body);
201
202            // Add all locals to pending list
203            _pendingLocals.AddRange(lambdaWalker.Locals);
204
205            // Prepare variables
206            LayoutVariablesForGenerator(parameters);
207
208            // Rewrite for generator
209            MSAst.Expression generatorBody = TransformToGeneratorBody(body);
210
211            // Get the generator factory lambda
212            MSAst.LambdaExpression generatorFactoryLambda = CreateGeneratorFactoryLambda(generatorBody);
213
214            // Create FunctionInfo object
215            CreateFunctionInfo(generatorFactoryLambda);
216
217            // Create our own outer generator lambda
218            return CreateOuterGeneratorFactory(lambda.Type);
219        }
220
221        // Lays out variables exactly in the order they'll be lifted.  Any variables with conflicting names
222        // are replaced with new variables.  Strongbox'ed variables are not lifted here.
223        private void LayOutVariables(Dictionary<MSAst.ParameterExpression, object> strongBoxedLocals, Dictionary<MSAst.ParameterExpression, object> parameters) {
224
225            IList<MSAst.ParameterExpression> hiddenVariables = _lambdaInfo.HiddenVariables;
226
227            int byrefIndex = 0;
228            int strongBoxIndex = 0;
229
230            for (int i = 0; i < _pendingLocals.Count; i++) {
231                MSAst.ParameterExpression pendingLocal = _pendingLocals[i];
232                MSAst.ParameterExpression verifiedLocal = pendingLocal;
233
234                if (_pendingToVariableInfosMap.ContainsKey(pendingLocal)) {
235                    continue;
236                }
237
238                string alias;
239
240                // See if there's an alias for the local
241                if (_lambdaInfo.VariableAliases == null || !_lambdaInfo.VariableAliases.TryGetValue(pendingLocal, out alias)) {
242                    alias = pendingLocal.Name;
243                }
244
245                bool isParameter = parameters.ContainsKey(pendingLocal);
246                bool isHidden = hiddenVariables != null && hiddenVariables.Contains(pendingLocal);
247                bool isStrongBoxed = strongBoxedLocals.ContainsKey(pendingLocal);
248
249                if (alias == null) {
250                    alias = "local";
251                    isHidden = true;
252                }
253
254                bool isDuplicate = _verifiedLocalNames.ContainsKey(alias);
255
256                // Check if we need to replace the local because of name collisions
257                if (isDuplicate) {
258                    // Get a unique name
259                    int count = 1;
260                    while (isDuplicate) {
261                        alias = alias + count++;
262                        isDuplicate = _verifiedLocalNames.ContainsKey(alias);
263                    }
264
265                    verifiedLocal = Ast.Parameter(verifiedLocal.Type, alias);
266                }
267
268                _verifiedLocals.Add(verifiedLocal);
269                _verifiedLocalNames.Add(alias, null);
270
271                if (pendingLocal != verifiedLocal) {
272                    _pendingToVerifiedLocalsMap.Add(pendingLocal, verifiedLocal);
273                }
274
275                int localIndex = isStrongBoxed ? strongBoxIndex++ : byrefIndex++;
276                VariableInfo varInfo = new VariableInfo(alias, pendingLocal.Type, isParameter, isHidden, isStrongBoxed, localIndex, _variableInfos.Count);
277
278                _variableInfos.Add(varInfo);
279                _pendingToVariableInfosMap.Add(pendingLocal, varInfo);
280
281                // Add the variable to builders
282                if (isParameter) {
283                    _lambdaParams.Add(pendingLocal);
284                    _generatorParams.Add(pendingLocal);
285                } else {
286                    _lambdaVars.Add(verifiedLocal);
287                    _generatorVars.Add(pendingLocal);
288                }
289            }
290        }
291
292        private void LayoutVariablesForGenerator(Dictionary<MSAst.ParameterExpression, object> parameters) {
293            IList<MSAst.ParameterExpression> hiddenVariables = _lambdaInfo.HiddenVariables;
294            int strongBoxIndex = 0;
295
296            for (int i = 0; i < _pendingLocals.Count; i++) {
297                MSAst.ParameterExpression pendingLocal = _pendingLocals[i];
298                MSAst.ParameterExpression verifiedLocal = pendingLocal;
299
300                string alias;
301
302                // See if there's an alias for the local
303                if (_lambdaInfo.VariableAliases == null || !_lambdaInfo.VariableAliases.TryGetValue(pendingLocal, out alias)) {
304                    alias = pendingLocal.Name;
305                }
306
307                bool isParameter = parameters.ContainsKey(pendingLocal);
308                bool isHidden = hiddenVariables != null && hiddenVariables.Contains(pendingLocal);
309
310                if (alias == null) {
311                    alias = "local";
312                    isHidden = true;
313                }
314
315                bool isDuplicate = _verifiedLocalNames.ContainsKey(alias);
316
317                // Check if we need to replace the local because of name collisions
318                if (isDuplicate) {
319                    // Get a unique name
320                    int count = 1;
321                    while (isDuplicate) {
322                        alias = alias + count++;
323                        isDuplicate = _verifiedLocalNames.ContainsKey(alias);
324                    }
325
326                    verifiedLocal = Ast.Parameter(verifiedLocal.Type, alias);
327                }
328
329                _verifiedLocals.Add(verifiedLocal);
330                _verifiedLocalNames.Add(alias, null);
331
332                if (pendingLocal != verifiedLocal) {
333                    _pendingToVerifiedLocalsMap.Add(pendingLocal, verifiedLocal);
334                }
335
336                VariableInfo varInfo = new VariableInfo(alias, pendingLocal.Type, isParameter, isHidden, true, strongBoxIndex++, _variableInfos.Count);
337
338                _variableInfos.Add(varInfo);
339                _pendingToVariableInfosMap.Add(pendingLocal, varInfo);
340
341                // Add the variable to builders
342                if (isParameter) {
343                    _lambdaParams.Add(pendingLocal);
344                    _generatorParams.Add(pendingLocal);
345                } else {
346                    _generatorVars.Add(pendingLocal);
347                }
348            }
349        }
350
351        private void CreatePushFrameExpression() {
352            _pushFrame = Ast.Block(
353                Ast.Assign(_framePushed, Ast.Constant(true)),
354
355                // Get thread
356                Ast.Assign(
357                    _thread,
358                    AstUtils.SimpleCallHelper(
359                        typeof(RuntimeOps).GetMethod("GetCurrentThread"),
360                        _debugContextExpression
361                    )
362                ),
363
364                _debugContext.ThreadFactory.CreatePushFrameExpression(_funcInfo, _debugMarker, _verifiedLocals, _variableInfos, _thread)
365            );
366
367            _conditionalPushFrame = AstUtils.If(
368                Ast.Equal(_framePushed, Ast.Constant(false)),
369                _pushFrame
370            );
371        }
372
373        private void CreateFunctionInfo(MSAst.LambdaExpression generatorFactoryLambda) {
374            if (_lambdaInfo.CompilerSupport != null && _lambdaInfo.CompilerSupport.DoesExpressionNeedReduction(generatorFactoryLambda)) {
375                _functionInfo = _lambdaInfo.CompilerSupport.QueueExpressionForReduction(
376                    Ast.Call(
377                        typeof(RuntimeOps).GetMethod("CreateFunctionInfo"),
378                        generatorFactoryLambda,
379                        AstUtils.Constant(_alias),
380                        AstUtils.Constant(_debugMarkerLocationMap, typeof(object)),
381                        AstUtils.Constant(_variableScopeMap, typeof(object)),
382                        AstUtils.Constant(_variableInfos, typeof(object)),
383                        Ast.Constant(_lambdaInfo.CustomPayload, typeof(object))
384                    )
385                );
386            } else {
387                _functionInfo = Ast.Constant(
388                    DebugContext.CreateFunctionInfo(
389                        generatorFactoryLambda.Compile(),
390                        _alias,
391                        _debugMarkerLocationMap,
392                        _variableScopeMap,
393                        _variableInfos,
394                        _lambdaInfo.CustomPayload), 
395                    typeof(FunctionInfo));
396            }
397        }
398
399        private MSAst.Expression TransformToDebuggableBody(MSAst.Expression body) {
400            return new DebugInfoRewriter(
401                _debugContext,
402                false,
403                _traceLocations,
404                _thread,
405                _frame,
406                _noPushFrameOptimization ? null : _conditionalPushFrame,
407                _debugMarker,
408                _globalDebugMode,
409                _sourceFilesMap,
410                null,
411                _pendingToVerifiedLocalsMap,
412                null,
413                _lambdaInfo).Visit(body);
414        }
415
416        private MSAst.Expression TransformToGeneratorBody(MSAst.Expression body) {
417            if (_generatorLabelTarget == null)
418                _generatorLabelTarget = Ast.Label(typeof(object));
419
420            DebugInfoRewriter debugInfoToYieldRewriter = new DebugInfoRewriter(
421                _debugContext,
422                true,
423                _traceLocations,
424                _thread,
425                _frame,
426                null,
427                null,
428                _globalDebugMode,
429                null,
430                _generatorLabelTarget,
431                null,
432                _pendingToVariableInfosMap,
433                _lambdaInfo);
434
435            MSAst.Expression transformedBody = debugInfoToYieldRewriter.Visit(body);
436            _debugMarkerLocationMap = debugInfoToYieldRewriter.DebugMarkerLocationMap;
437            _variableScopeMap = debugInfoToYieldRewriter.VariableScopeMap;
438
439            // Populate sourceFileMap-to-variables map
440            _sourceFilesMap = new Dictionary<DebugSourceFile, MSAst.ParameterExpression>();
441            foreach (DebugSourceSpan sourceSpan in _debugMarkerLocationMap) {
442                if (!_sourceFilesMap.ContainsKey(sourceSpan.SourceFile)) {
443                    _sourceFilesMap.Add(sourceSpan.SourceFile, Ast.Parameter(typeof(DebugSourceFile)));
444                }
445            }
446
447            // Don't perform leaf-frame optimization if the compiler didn't ask for it or 
448            // if we found unconditional calls to other debuggable labmdas.
449            _noPushFrameOptimization = !_lambdaInfo.OptimizeForLeafFrames || debugInfoToYieldRewriter.HasUnconditionalFunctionCalls;
450            return transformedBody;
451        }
452
453        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody) {
454            List<MSAst.Expression> bodyExpressions = new List<MSAst.Expression>();
455            List<MSAst.Expression> tryExpressions = new List<MSAst.Expression>();
456            List<MSAst.Expression> finallyExpressions = new List<MSAst.Expression>();
457
458            Type returnType = lambdaType.GetMethod("Invoke").ReturnType;
459            MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType);
460
461            // Init $funcInfo
462            tryExpressions.Add(
463                Ast.Assign(
464                    _funcInfo,
465                    Ast.Convert(_functionInfo, typeof(FunctionInfo))
466                )
467            );
468
469            // Init $traceLocations
470            // $TODO: only do this if we're in TracePoints mode
471            tryExpressions.Add(
472                Ast.Assign(
473                    _traceLocations,
474                    Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo)
475                )
476            );
477
478            // Init sourceFile locals
479            foreach (var entry in _sourceFilesMap) {
480                tryExpressions.Add(
481                    Ast.Assign(
482                        entry.Value,
483                        Ast.Constant(entry.Key, typeof(DebugSourceFile))
484                    )
485                );
486            }
487
488            if (_noPushFrameOptimization) {
489                tryExpressions.Add(_pushFrame);
490            }
491            
492            tryExpressions.Add(Ast.Call(
493                typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"),
494                _thread
495            ));
496            
497            var frameExit = AstUtils.If(
498                Ast.Equal(
499                    _debugMarkerLocationMap.Length > 0 ?
500                        Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") :
501                        _globalDebugMode,
502                    AstUtils.Constant((int)DebugMode.FullyEnabled)
503                ),
504                Ast.Call(
505                    typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"),
506                    _thread,
507                    _debugMarker,
508                    _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null)
509                )
510            );
511
512            // normal exit
513            tryExpressions.Add(
514                Ast.Block(
515                    _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody, 
516                    Ast.Assign(_frameExitException, Ast.Constant(true)),
517                    frameExit) 
518            );
519
520            tryExpressions.Add(
521                _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty()
522            );
523
524            MSAst.Expression[] popFrame = new MSAst.Expression[] {
525                AstUtils.If(
526                    // Fire thead-exit event if PopFrame returns true
527                    Ast.AndAlso(
528                        Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)),
529                        Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled))
530                    ),
531                    Ast.Call(
532                        typeof(RuntimeOps).GetMethod("OnThreadExitEvent"),
533                        _thread
534                    )
535                )
536            };
537
538            if (_noPushFrameOptimization) {
539                finallyExpressions.AddRange(popFrame);
540            } else {
541                finallyExpressions.Add(
542                     AstUtils.If(
543                         Ast.Equal(_framePushed, Ast.Constant(true)),
544                         popFrame
545                    )
546                );
547            }
548
549            MSAst.ParameterExpression caughtException;
550
551            // Run the function body
552            bodyExpressions.Add(Ast.TryCatchFinally(
553                Ast.TryCatch(
554                    Ast.Block(
555                        ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType))
556                    ),
557                    Ast.Catch(
558                        caughtException = Ast.Variable(typeof(Exception), "$caughtException"), 
559                        Ast.Block(
560                            // The expressions below will always throw.
561                            // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException.
562                            // If the exception is not being cancelled then we'll just rethrow at the end of the catch block.
563                            AstUtils.If(
564                                Ast.Not(
565                                    Ast.TypeIs(
566                                        caughtException,
567                                        typeof(ForceToGeneratorLoopException)
568                                    )
569                                ),
570                                AstUtils.If(
571                                    Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)),
572                                    _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame,
573                                    Ast.Call(
574                                        typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"),
575                                        _thread,
576                                        _debugMarker,
577                                        caughtException
578                                    )
579                                ),
580                                // exception exit
581                                AstUtils.If(
582                                    Ast.Not(_frameExitException),
583                                    frameExit
584                                )                                
585                            ),
586
587                            Ast.Rethrow(),
588
589                            // Ensuring that the catch block is of the same type as the try block
590                            Ast.Default(returnType)
591                        )
592                    )
593                ),
594                Ast.Block(finallyExpressions),
595                Ast.Catch(
596                    typeof(ForceToGeneratorLoopException),
597                    Ast.TryFinally(
598                        // Handle ForceToGeneratorLoopException
599                        Ast.Block(
600                            returnType != typeof(void) ? Ast.Block(
601                                Ast.Assign(
602                                    _retValFromGeneratorLoop, 
603                                    Ast.Call(
604                                        typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
605                                        _thread
606                                    )
607                                ),
608                                AstUtils.If(
609                                    Ast.NotEqual(
610                                        _retValFromGeneratorLoop,
611                                        Ast.Constant(null)
612                                    ),
613                                    Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)),
614                                    Ast.Return(
615                                        returnLabelTarget,
616                                        Ast.Convert(_retValFromGeneratorLoop, returnType)
617                                    )
618                                ).Else(
619                                    Ast.Assign(_retVal, Ast.Default(returnType)),
620                                    Ast.Return(
621                                        returnLabelTarget,
622                                        Ast.Default(returnType)
623                                    )
624                                )
625                            ) :
626                            Ast.Block(
627                                Ast.Call(
628                                    typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
629                                    _thread
630                                ),
631                                Ast.Return(returnLabelTarget)
632                            )
633                            ,
634                            // Ensuring that the catch block is of the same type as the try block
635                            Ast.Default(returnType)
636                        ),
637                        // Make sure that the debugMarker is up-to-date after the generator loop
638                        Ast.Assign(
639                            _debugMarker, 
640                            Ast.Call(
641                                typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"),
642                                _thread
643                            )
644                        )
645                    )
646                )
647            ));
648
649            MSAst.Expression body = Ast.Block(bodyExpressions);
650
651            if (body.Type == typeof(void) && returnType != typeof(void)) {
652                body = Ast.Block(body, Ast.Default(returnType));
653            }
654
655            return Ast.Lambda(
656                lambdaType,
657                Ast.Block(
658                    _lambdaVars,
659                    Ast.Label(returnLabelTarget, body)
660                ),
661                _alias,
662                _lambdaParams);
663        }
664
665        private MSAst.LambdaExpression CreateGeneratorFactoryLambda(MSAst.Expression generatorBody) {
666            MSAst.Expression body = Ast.Block(
667                Ast.Call(
668                    typeof(RuntimeOps).GetMethod("ReplaceLiftedLocals"),
669                    _frame,
670                    Ast.RuntimeVariables(_pendingLocals)
671                ),
672                generatorBody
673            );
674
675            if (_retVal != null) {
676                body = Ast.Block(
677                    Ast.Assign(_retVal, body),
678                    AstUtils.YieldReturn(
679                        _generatorLabelTarget, Ast.Convert(_retVal, typeof(object))
680                    )
681                );
682            }
683
684            List<Type> argTypes = new List<Type>();
685            for (int i = 0; i < _variableInfos.Count; i++) {
686                VariableInfo varInfo = _variableInfos[i];
687                if (varInfo.IsParameter)
688                    argTypes.Add(varInfo.VariableType);
689            }
690
691            if (body.Type != typeof(void)) {
692                body = AstUtils.Void(body);
693            }
694
695            return AstUtils.GeneratorLambda(
696                InvokeTargets.GetGeneratorFactoryTarget(argTypes.ToArray()),
697                _generatorLabelTarget,
698                Ast.Block(
699                    _generatorVars,
700                    body
701                ),
702                _alias,
703                _generatorParams);
704        }
705
706        private MSAst.LambdaExpression CreateOuterGeneratorFactory(Type lambdaType) {
707            MSAst.LabelTarget returnLabelTarget = Ast.Label(lambdaType.GetMethod("Invoke").ReturnType);
708
709            MSAst.Expression body = Ast.Return(
710                returnLabelTarget,
711                Ast.Call(
712                    typeof(RuntimeOps),
713                    "CreateDebugGenerator",
714                    new[] { _generatorLabelTarget.Type },
715                     Ast.Call(
716                        typeof(RuntimeOps).GetMethod("CreateFrameForGenerator"),
717                        _debugContextExpression,
718                        _functionInfo
719                    )
720                )
721            );
722
723            MSAst.LabelExpression returnLabel = null;
724            if (returnLabelTarget.Type == typeof(void)) {
725                returnLabel = Ast.Label(returnLabelTarget, AstUtils.Void(body));
726            } else {
727                returnLabel = Ast.Label(returnLabelTarget, AstUtils.Convert(body, returnLabelTarget.Type));
728            }
729
730            return Ast.Lambda(
731                lambdaType,
732                Ast.Block(
733                    _lambdaVars,
734                    returnLabel
735                ),
736                _alias,
737                _lambdaParams);
738        }
739    }
740}