public void CloseMethod(BoundStatement body) { Debug.Assert((object)CurrentMethod != null); if (body.Kind != BoundKind.Block) { body = Block(body); } CompilationState.AddSynthesizedMethod(CurrentMethod, body); CurrentMethod = null; }
private BoundNode RewriteLambdaConversion(BoundLambda node) { var wasInExpressionLambda = inExpressionLambda; inExpressionLambda = inExpressionLambda || node.Type.IsExpressionTree(); if (inExpressionLambda) { var newType = VisitType(node.Type); var newBody = (BoundBlock)Visit(node.Body); node = node.Update(node.Symbol, newBody, node.Diagnostics, node.Binder, newType); var result0 = wasInExpressionLambda ? node : ExpressionLambdaRewriter.RewriteLambda(node, CompilationState, Diagnostics); inExpressionLambda = wasInExpressionLambda; return(result0); } NamedTypeSymbol translatedLambdaContainer; BoundNode lambdaScope = null; if (analysis.lambdaScopes.TryGetValue(node.Symbol, out lambdaScope)) { translatedLambdaContainer = frames[lambdaScope]; } else { translatedLambdaContainer = topLevelMethod.ContainingType; } // Move the body of the lambda to a freshly generated synthetic method on its frame. bool lambdaIsStatic = analysis.captures[node.Symbol].IsEmpty(); var synthesizedMethod = new SynthesizedLambdaMethod(translatedLambdaContainer, topLevelMethod, node, lambdaIsStatic, CompilationState); if (CompilationState.Emitting) { CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(translatedLambdaContainer, synthesizedMethod); } for (int i = 0; i < node.Symbol.ParameterCount; i++) { parameterMap.Add(node.Symbol.Parameters[i], synthesizedMethod.Parameters[i]); } // rewrite the lambda body as the generated method's body var oldMethod = currentMethod; var oldFrameThis = currentFrameThis; var oldTypeParameters = currentTypeParameters; var oldInnermostFramePointer = innermostFramePointer; var oldTypeMap = currentLambdaBodyTypeMap; var oldAddedStatements = addedStatements; var oldAddedLocals = addedLocals; addedStatements = null; addedLocals = null; // switch to the generated method currentMethod = synthesizedMethod; if (lambdaIsStatic) { // no link from a static lambda to its container innermostFramePointer = currentFrameThis = null; } else { currentFrameThis = synthesizedMethod.ThisParameter; innermostFramePointer = null; framePointers.TryGetValue(translatedLambdaContainer, out innermostFramePointer); } if (translatedLambdaContainer.OriginalDefinition is LambdaFrame) { currentTypeParameters = translatedLambdaContainer.TypeParameters; currentLambdaBodyTypeMap = ((LambdaFrame)translatedLambdaContainer).TypeMap; } else { currentTypeParameters = synthesizedMethod.TypeParameters; currentLambdaBodyTypeMap = new TypeMap(topLevelMethod.TypeParameters, currentTypeParameters); } var body = AddStatementsIfNeeded((BoundStatement)VisitBlock(node.Body)); CheckLocalsDefined(body); CompilationState.AddSynthesizedMethod(synthesizedMethod, body); // return to the old method currentMethod = oldMethod; currentFrameThis = oldFrameThis; currentTypeParameters = oldTypeParameters; innermostFramePointer = oldInnermostFramePointer; currentLambdaBodyTypeMap = oldTypeMap; addedLocals = oldAddedLocals; addedStatements = oldAddedStatements; // Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression NamedTypeSymbol constructedFrame = (translatedLambdaContainer is LambdaFrame) ? translatedLambdaContainer.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)) : translatedLambdaContainer; BoundExpression receiver = lambdaIsStatic ? new BoundTypeExpression(node.Syntax, null, constructedFrame) : FrameOfType(node.Syntax, constructedFrame); MethodSymbol referencedMethod = synthesizedMethod.AsMember(constructedFrame); if (referencedMethod.IsGenericMethod) { referencedMethod = referencedMethod.Construct(StaticCast <TypeSymbol> .From(currentTypeParameters)); } TypeSymbol type = this.VisitType(node.Type); BoundExpression result = new BoundDelegateCreationExpression( node.Syntax, receiver, referencedMethod, isExtensionMethod: false, type: type); // if the block containing the lambda is not the innermost block, // or the lambda is static, then the lambda object should be cached in its frame. // NOTE: we are not caching static lambdas in static ctors - cannot reuse such cache. var shouldCacheForStaticMethod = lambdaIsStatic && currentMethod.MethodKind != MethodKind.StaticConstructor && !referencedMethod.IsGenericMethod; // NOTE: We require "lambdaScope != null". // We do not want to introduce a field into an actual user's class (not a synthetic frame). var shouldCacheInLoop = lambdaScope != null && lambdaScope != analysis.blockParent[node.Body] && InLoopOrLambda(node.Syntax, lambdaScope.Syntax); if (shouldCacheForStaticMethod || shouldCacheInLoop) { // replace the expression "new Delegate(frame.M)" with "(frame.cache == null) ? (frame.cache = new Delegate(frame.M)) : frame.cache" var F = new SyntheticBoundNodeFactory(currentMethod, node.Syntax, CompilationState, Diagnostics); try { var cacheVariableName = GeneratedNames.MakeLambdaCacheName(CompilationState.GenerateTempNumber()); BoundExpression cacheVariable; if (shouldCacheForStaticMethod || shouldCacheInLoop && translatedLambdaContainer is LambdaFrame) { var cacheVariableType = lambdaIsStatic ? type : (translatedLambdaContainer as LambdaFrame).TypeMap.SubstituteType(type); var cacheField = new SynthesizedFieldSymbol(translatedLambdaContainer, cacheVariableType, cacheVariableName, isPublic: !lambdaIsStatic, isStatic: lambdaIsStatic); CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(translatedLambdaContainer, cacheField); cacheVariable = F.Field(receiver, cacheField.AsMember(constructedFrame)); //NOTE: the field was added to the unconstructed frame type. } else { // the lambda captures at most the "this" of the enclosing method. We cache its delegate in a local variable. var cacheLocal = F.SynthesizedLocal(type, cacheVariableName); if (addedLocals == null) { addedLocals = ArrayBuilder <LocalSymbol> .GetInstance(); } addedLocals.Add(cacheLocal); if (addedStatements == null) { addedStatements = ArrayBuilder <BoundStatement> .GetInstance(); } cacheVariable = F.Local(cacheLocal); addedStatements.Add(F.Assignment(cacheVariable, F.Null(type))); } result = F.Coalesce(cacheVariable, F.AssignmentExpression(cacheVariable, result)); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { Diagnostics.Add(ex.Diagnostic); return(new BoundBadExpression(F.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(node), node.Type)); } } return(result); }
/// <summary> /// Introduce a frame around the translation of the given node. /// </summary> /// <param name="node">The node whose translation should be translated to contain a frame</param> /// <param name="frame">The frame for the translated node</param> /// <param name="F">A function that computes the translation of the node. It receives lists of added statements and added symbols</param> /// <returns>The translated statement, as returned from F</returns> private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F) { NamedTypeSymbol frameType = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)); LocalSymbol framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState); CSharpSyntaxNode syntax = node.Syntax; // assign new frame to the frame variable CompilationState.AddSynthesizedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), frame.Constructor)); var prologue = ArrayBuilder <BoundExpression> .GetInstance(); MethodSymbol constructor = frame.Constructor.AsMember(frameType); Debug.Assert(frameType == constructor.ContainingType); var newFrame = new BoundObjectCreationExpression( syntax: syntax, constructor: constructor); prologue.Add(new BoundAssignmentOperator(syntax, new BoundLocal(syntax, framePointer, null, frameType), newFrame, frameType)); CapturedSymbolReplacement oldInnermostFrameProxy = null; if ((object)innermostFramePointer != null) { proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy); if (analysis.needsParentFrame.Contains(node)) { var capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer); FieldSymbol frameParent = capturedFrame.AsMember(frameType); BoundExpression left = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null); BoundExpression right = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol); BoundExpression assignment = new BoundAssignmentOperator(syntax, left, right, left.Type); if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall) { // Containing method is a constructor // Initialization statement for the "this" proxy must be inserted // after the constructor initializer statement block // This insertion will be done by the delegate F Debug.Assert(thisProxyInitDeferred == null); thisProxyInitDeferred = assignment; } else { prologue.Add(assignment); } if (CompilationState.Emitting) { CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(frame, capturedFrame); } proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame); } } // Capture any parameters of this block. This would typically occur // at the top level of a method or lambda with captured parameters. // TODO: speed up the following by computing it in analysis. foreach (var v in analysis.variablesCaptured) { BoundNode varNode; if (!analysis.variableBlock.TryGetValue(v, out varNode) || varNode != node || analysis.declaredInsideExpressionLambda.Contains(v)) { continue; } InitVariableProxy(syntax, v, framePointer, prologue); } Symbol oldInnermostFramePointer = innermostFramePointer; innermostFramePointer = framePointer; var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance(); addedLocals.Add(framePointer); framePointers.Add(frame, framePointer); var result = F(prologue, addedLocals); framePointers.Remove(frame); innermostFramePointer = oldInnermostFramePointer; if ((object)innermostFramePointer != null) { if (oldInnermostFrameProxy != null) { proxies[innermostFramePointer] = oldInnermostFrameProxy; } else { proxies.Remove(innermostFramePointer); } } return(result); }