internal FieldSymbol DefineCallSiteStorageSymbol(NamedTypeSymbol containerDefinition, NamedTypeSymbol delegateTypeOverMethodTypeParameters, TypeMap methodToContainerTypeParametersMap) { var fieldName = GeneratedNames.MakeDynamicCallSiteFieldName(_callSiteIdDispenser++); var delegateTypeOverContainerTypeParameters = methodToContainerTypeParametersMap.SubstituteNamedType(delegateTypeOverMethodTypeParameters); var callSiteType = _factory.Compilation.GetWellKnownType(WellKnownType.core_runtime_compiler_CallSite_T).Construct(new[] { delegateTypeOverContainerTypeParameters }); var field = new SynthesizedFieldSymbol(containerDefinition, callSiteType, fieldName, isPublic: true, isStatic: true); _factory.AddField(containerDefinition, field); return(_currentDynamicCallSiteContainer.IsGenericType ? field.AsMember(_currentDynamicCallSiteContainer) : field); }
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); }