PageRenderTime 127ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

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