internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = this.GetNonNullSyntaxNode(); SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this, syntax, compilationState, diagnostics); factory.CurrentMethod = this; ArrayBuilder<BoundStatement> body = ArrayBuilder<BoundStatement>.GetInstance(); // Initialize the payload root for each kind of dynamic analysis instrumentation. // A payload root is an array of arrays of per-method instrumentation payloads. // For each kind of instrumentation: // // payloadRoot = new T[MaximumMethodDefIndex + 1][]; // // where T is the type of the payload at each instrumentation point, and MaximumMethodDefIndex is the // index portion of the greatest method definition token in the compilation. This guarantees that any // method can use the index portion of its own method definition token as an index into the payload array. try { foreach (KeyValuePair<int, InstrumentationPayloadRootField> payloadRoot in ContainingPrivateImplementationDetailsType.GetInstrumentationPayloadRoots()) { int analysisKind = payloadRoot.Key; ArrayTypeSymbol payloadArrayType = (ArrayTypeSymbol)payloadRoot.Value.Type; BoundStatement payloadInitialization = factory.Assignment( factory.InstrumentationPayloadRoot(analysisKind, payloadArrayType), factory.Array(payloadArrayType.ElementType, factory.Binary(BinaryOperatorKind.Addition, factory.SpecialType(SpecialType.System_Int32), factory.MaximumMethodDefIndex(), factory.Literal(1)))); body.Add(payloadInitialization); } // Initialize the module version ID (MVID) field. Dynamic instrumentation requires the MVID of the executing module, and this field makes that accessible. // MVID = Guid.Parse(ModuleVersionIdString); body.Add( factory.Assignment( factory.ModuleVersionId(), factory.StaticCall( WellKnownMember.System_Guid__Parse, factory.ModuleVersionIdString()))); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember missing) { diagnostics.Add(missing.Diagnostic); } BoundStatement returnStatement = factory.Return(); body.Add(returnStatement); factory.CloseMethod(factory.Block(body.ToImmutableAndFree())); }
/// <summary> /// Given a SynthesizedExplicitImplementationMethod (effectively a tuple (interface method, implementing method, implementing type)), /// construct a BoundBlock body. Consider the tuple (Interface.Foo, Base.Foo, Derived). The generated method will look like: /// /// R Interface.Foo<T1, T2, ...>(A1 a1, A2 a2, ...) /// { /// //don't return the output if the return type is void /// return this.Foo<T1, T2, ...>(a1, a2, ...); /// } /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = (MethodSymbol)this.OriginalDefinition; try { MethodSymbol methodToInvoke = this.IsGenericMethod ? this.ImplementingMethod.Construct(this.TypeParameters.Cast<TypeParameterSymbol, TypeSymbol>()) : this.ImplementingMethod; F.CloseMethod(MethodBodySynthesizer.ConstructSingleInvocationMethodBody(F, methodToInvoke, useBaseReference: false)); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
protected override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory factory, ArrayBuilder <BoundStatement> statements, DiagnosticBag diagnostics) => _getConstructorBody(factory, statements, _parameters);
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { BoundExpression originalLeft = node.Left; if (originalLeft.Kind != BoundKind.Local) { return(base.VisitAssignmentOperator(node)); } var leftLocal = (BoundLocal)originalLeft; BoundExpression originalRight = node.Right; if (leftLocal.LocalSymbol.RefKind != RefKind.None && node.IsRef && NeedsProxy(leftLocal.LocalSymbol)) { Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol)); Debug.Assert(originalRight.Kind != BoundKind.ConvertedStackAllocExpression); //spilling ref local variables throw ExceptionUtilities.Unreachable; } if (NeedsProxy(leftLocal.LocalSymbol) && !proxies.ContainsKey(leftLocal.LocalSymbol)) { Debug.Assert(leftLocal.LocalSymbol.DeclarationKind == LocalDeclarationKind.None); // spilling temp variables throw ExceptionUtilities.Unreachable; } BoundExpression rewrittenLeft = (BoundExpression)this.Visit(leftLocal); BoundExpression rewrittenRight = (BoundExpression)this.Visit(originalRight); TypeSymbol rewrittenType = VisitType(node.Type); // Check if we're assigning the result of stackalloc to a hoisted local. // If we are, we need to store the result in a temp local and then assign // the value of the local to the field corresponding to the hoisted local. // If the receiver of the field is on the stack when the stackalloc happens, // popping it will free the memory (?) or otherwise cause verification issues. // DevDiv Bugs 59454 if (rewrittenLeft.Kind != BoundKind.Local && originalRight.Kind == BoundKind.ConvertedStackAllocExpression) { // From ILGENREC::genAssign: // DevDiv Bugs 59454: Handle hoisted local initialized with a stackalloc // NOTE: Need to check for cast of stackalloc on RHS. // If LHS isLocal, then genAddr is a noop so regular case works fine. SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this.CurrentMethod, rewrittenLeft.Syntax, this.CompilationState, this.Diagnostics); BoundAssignmentOperator tempAssignment; BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment); Debug.Assert(!node.IsRef); BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.IsRef, rewrittenType); return(new BoundSequence( node.Syntax, ImmutableArray.Create <LocalSymbol>(tempLocal.LocalSymbol), ImmutableArray.Create <BoundExpression>(tempAssignment), rewrittenAssignment, rewrittenType)); } return(node.Update(rewrittenLeft, rewrittenRight, node.IsRef, rewrittenType)); }
static BoundStatement makeAppendString(SyntheticBoundNodeFactory F, BoundLocal builder, string value) { return(F.ExpressionStatement(F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendString), F.StringLiteral(value)))); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { BoundExpression originalLeft = node.Left; if (originalLeft.Kind != BoundKind.Local) { return base.VisitAssignmentOperator(node); } var leftLocal = (BoundLocal)originalLeft; BoundExpression originalRight = node.Right; if (leftLocal.LocalSymbol.RefKind != RefKind.None && node.RefKind != RefKind.None && NeedsProxy(leftLocal.LocalSymbol)) { Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol)); Debug.Assert(!IsStackAlloc(originalRight)); //spilling ref local variables throw ExceptionUtilities.Unreachable; } if (NeedsProxy(leftLocal.LocalSymbol) && !proxies.ContainsKey(leftLocal.LocalSymbol)) { Debug.Assert(leftLocal.LocalSymbol.DeclarationKind == LocalDeclarationKind.None); // spilling temp variables throw ExceptionUtilities.Unreachable; } BoundExpression rewrittenLeft = (BoundExpression)this.Visit(leftLocal); BoundExpression rewrittenRight = (BoundExpression)this.Visit(originalRight); TypeSymbol rewrittenType = VisitType(node.Type); // Check if we're assigning the result of stackalloc to a hoisted local. // If we are, we need to store the result in a temp local and then assign // the value of the local to the field corresponding to the hoisted local. // If the receiver of the field is on the stack when the stackalloc happens, // popping it will free the memory (?) or otherwise cause verification issues. // DevDiv Bugs 59454 if (rewrittenLeft.Kind != BoundKind.Local && IsStackAlloc(originalRight)) { // From ILGENREC::genAssign: // DevDiv Bugs 59454: Handle hoisted local initialized with a stackalloc // NOTE: Need to check for cast of stackalloc on RHS. // If LHS isLocal, then genAddr is a noop so regular case works fine. SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this.CurrentMethod, rewrittenLeft.Syntax, this.CompilationState, this.Diagnostics); BoundAssignmentOperator tempAssignment; BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment); Debug.Assert(node.RefKind == RefKind.None); BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.RefKind, rewrittenType); return new BoundSequence( node.Syntax, ImmutableArray.Create<LocalSymbol>(tempLocal.LocalSymbol), ImmutableArray.Create<BoundExpression>(tempAssignment), rewrittenAssignment, rewrittenType); } return node.Update(rewrittenLeft, rewrittenRight, node.RefKind, rewrittenType); }
/// <summary> /// Construct a body for a method containing a call to a single other method with the same signature (modulo name). /// </summary> /// <param name="F">Bound node factory.</param> /// <param name="methodToInvoke">Method to invoke in constructed body.</param> /// <param name="useBaseReference">True for "base.", false for "this.".</param> /// <returns>Body for implementedMethod.</returns> internal static BoundBlock ConstructSingleInvocationMethodBody(SyntheticBoundNodeFactory F, MethodSymbol methodToInvoke, bool useBaseReference) { var argBuilder = ArrayBuilder<BoundExpression>.GetInstance(); //var refKindBuilder = ArrayBuilder<RefKind>.GetInstance(); foreach (var param in F.CurrentMethod.Parameters) { argBuilder.Add(F.Parameter(param)); //refKindBuilder.Add(param.RefKind); } BoundExpression invocation = F.Call(useBaseReference ? (BoundExpression)F.Base() : F.This(), methodToInvoke, argBuilder.ToImmutableAndFree()); return F.CurrentMethod.ReturnsVoid ? F.Block(F.ExpressionStatement(invocation), F.Return()) : F.Block(F.Return(invocation)); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // $anonymous$ local = value as $anonymous$; // return local != null // && System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, local.backingFld_1) // ... // && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, local.backingFld_N); // } // Type and type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // local BoundAssignmentOperator assignmentToTemp; BoundLocal boundLocal = F.StoreToTemp(F.As(F.Parameter(_parameters[0]), anonymousType), out assignmentToTemp); // Generate: statement <= 'local = value as $anonymous$' BoundStatement assignment = F.ExpressionStatement(assignmentToTemp); // Generate expression for return statement // retExpression <= 'local != null' BoundExpression retExpression = F.Binary(BinaryOperatorKind.ObjectNotEqual, manager.System_Boolean, F.Convert(manager.System_Object, boundLocal), F.Null(manager.System_Object)); // prepare symbols MethodSymbol equalityComparer_Equals = manager.System_Collections_Generic_EqualityComparer_T__Equals; MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default; NamedTypeSymbol equalityComparerType = equalityComparer_Equals.ContainingType; // Compare fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; FieldSymbol fieldSymbol = anonymousType.Properties[index].BackingField; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' = 'retExpression && System.Collections.Generic.EqualityComparer<T_index>. // Default.Equals(this.backingFld_index, local.backingFld_index)' retExpression = F.LogicalAnd(retExpression, F.Call(F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_Equals.AsMember(constructedEqualityComparer), F.Field(F.This(), fieldSymbol), F.Field(boundLocal, fieldSymbol))); } // Final return statement BoundStatement retStatement = F.Return(retExpression); // Create a bound block F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement)); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; try { LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); ParameterSymbol text = this.Parameters[0]; // This method should be kept consistent with ComputeStringHash //uint hashCode = 0; //if (text != null) //{ // hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; //} //return hashCode; var body = F.Block( ImmutableArray.Create <LocalSymbol>(hashCode, i), F.If( F.Binary(BinaryOperatorKind.ObjectNotEqual, F.SpecialType(SpecialType.System_Boolean), F.Parameter(text), F.Null(text.Type)), F.Block( F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Chars), F.Local(i)), Conversion.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call(F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Length))), F.Goto(again)))), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // HASH_FACTOR = 0xa5555529; // INIT_HASH = (...((0 * HASH_FACTOR) + GetFNVHashCode(backingFld_1.Name)) * HASH_FACTOR // + GetFNVHashCode(backingFld_2.Name)) * HASH_FACTOR // + ... // + GetFNVHashCode(backingFld_N.Name) // // { // return (...((INITIAL_HASH * HASH_FACTOR) + EqualityComparer<T_1>.Default.GetHashCode(this.backingFld_1)) * HASH_FACTOR // + EqualityComparer<T_2>.Default.GetHashCode(this.backingFld_2)) * HASH_FACTOR // ... // + EqualityComparer<T_N>.Default.GetHashCode(this.backingFld_N) // } // // Where GetFNVHashCode is the FNV-1a hash code. const int HASH_FACTOR = -1521134295; // (int)0xa5555529 // Type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // INIT_HASH int initHash = 0; foreach (var property in anonymousType.Properties) { initHash = unchecked (initHash * HASH_FACTOR + Hash.GetFNVHashCode(property.BackingField.Name)); } // Generate expression for return statement // retExpression <= 'INITIAL_HASH' BoundExpression retExpression = F.Literal(initHash); // prepare symbols MethodSymbol equalityComparer_GetHashCode = manager.System_Collections_Generic_EqualityComparer_T__GetHashCode; MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default; NamedTypeSymbol equalityComparerType = equalityComparer_GetHashCode.ContainingType; // bound HASH_FACTOR BoundLiteral boundHashFactor = F.Literal(HASH_FACTOR); // Process fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' <= 'retExpression * HASH_FACTOR retExpression = F.Binary(BinaryOperatorKind.IntMultiplication, manager.System_Int32, retExpression, boundHashFactor); // Generate 'retExpression' <= 'retExpression + EqualityComparer<T_index>.Default.GetHashCode(this.backingFld_index)' retExpression = F.Binary(BinaryOperatorKind.IntAddition, manager.System_Int32, retExpression, F.Call( F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_GetHashCode.AsMember(constructedEqualityComparer), F.Field(F.This(), anonymousType.Properties[index].BackingField))); } // Create a bound block F.CloseMethod(F.Block(F.Return(retExpression))); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // return String.Format( // "{ <name1> = {0}", <name2> = {1}", ... <nameN> = {N-1}", // this.backingFld_1, // this.backingFld_2, // ... // this.backingFld_N // } // Type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // build arguments int fieldCount = anonymousType.Properties.Length; BoundExpression retExpression = null; if (fieldCount > 0) { // we do have fields, so have to use String.Format(...) BoundExpression[] arguments = new BoundExpression[fieldCount]; // process properties PooledStringBuilder formatString = PooledStringBuilder.GetInstance(); for (int i = 0; i < fieldCount; i++) { AnonymousTypePropertySymbol property = anonymousType.Properties[i]; // build format string formatString.Builder.AppendFormat(i == 0 ? "{{{{ {0} = {{{1}}}" : ", {0} = {{{1}}}", property.Name, i); // build argument arguments[i] = F.Convert(manager.System_Object, new BoundLoweredConditionalAccess(F.Syntax, F.Field(F.This(), property.BackingField), null, F.Call(new BoundConditionalReceiver( F.Syntax, id: i, type: property.BackingField.Type), manager.System_Object__ToString), null, id: i, type: manager.System_String), Conversion.ImplicitReference); } formatString.Builder.Append(" }}"); // add format string argument BoundExpression format = F.Literal(formatString.ToStringAndFree()); // Generate expression for return statement // retExpression <= System.String.Format(args) var formatMethod = manager.System_String__Format_IFormatProvider; retExpression = F.StaticCall(manager.System_String, formatMethod, F.Null(formatMethod.Parameters[0].Type), format, F.ArrayOrEmpty(manager.System_Object, arguments)); } else { // this is an empty anonymous type, just return "{ }" retExpression = F.Literal("{ }"); } F.CloseMethod(F.Block(F.Return(retExpression))); }
protected virtual void GenerateMethodBodyStatements(SyntheticBoundNodeFactory factory, ArrayBuilder <BoundStatement> statements, DiagnosticBag diagnostics) { // overridden in a derived class to add extra statements to the body of the generated constructor }
private static BoundExpression AddConditionSequencePoint(BoundExpression condition, SyntaxNode synthesizedVariableSyntax, SyntheticBoundNodeFactory factory) { if (!factory.Compilation.Options.EnableEditAndContinue) { return(condition); } // The local has to be associated with a syntax that is tracked by EnC source mapping. // At most one ConditionalBranchDiscriminator variable shall be associated with any given EnC tracked syntax node. var local = factory.SynthesizedLocal(condition.Type, synthesizedVariableSyntax, kind: SynthesizedLocalKind.ConditionalBranchDiscriminator); // Add hidden sequence point unless the condition is a constant expression. // Constant expression must stay a const to not invalidate results of control flow analysis. var valueExpression = (condition.ConstantValue == null) ? new BoundSequencePointExpression(syntax: null, expression: factory.Local(local), type: condition.Type) : condition; return(new BoundSequence( condition.Syntax, ImmutableArray.Create(local), ImmutableArray.Create <BoundExpression>(factory.AssignmentExpression(factory.Local(local), condition)), valueExpression, condition.Type)); }
/// <remarks> /// This method should be kept consistent with <see cref="SynthesizedStringSwitchHashMethod.ComputeStringHash"/> /// </remarks> internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentFunction = this; try { ParameterSymbol text = this.Parameters[0]; NamedTypeSymbol spanChar = F.WellKnownType(_isReadOnlySpan ? WellKnownType.System_ReadOnlySpan_T : WellKnownType.System_Span_T) .Construct(F.SpecialType(SpecialType.System_Char)); LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); // uint hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; // return hashCode; var body = F.Block( ImmutableArray.Create <LocalSymbol>(hashCode, i), F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.WellKnownMethod(_isReadOnlySpan ? WellKnownMember.System_ReadOnlySpan_T__get_Item : WellKnownMember.System_Span_T__get_Item).AsMember(spanChar), F.Local(i)), Conversion.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call( F.Parameter(text), F.WellKnownMethod(_isReadOnlySpan ? WellKnownMember.System_ReadOnlySpan_T__get_Length : WellKnownMember.System_Span_T__get_Length).AsMember(spanChar))), F.Goto(again)), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
/// <summary> /// Given a SynthesizedSealedPropertyAccessor (an accessor with a reference to the accessor it overrides), /// construct a BoundBlock body. /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = (MethodSymbol)this.OriginalDefinition; try { F.CloseMethod(MethodBodySynthesizer.ConstructSingleInvocationMethodBody(F, this.OverriddenAccessor, useBaseReference: true)); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
internal override void GenerateMethodBody( TypeCompilationState compilationState, BindingDiagnosticBag diagnostics ) { var F = new SyntheticBoundNodeFactory( this, this.SyntaxNode, compilationState, diagnostics ); try { MethodSymbol? equalityComparer_GetHashCode = null; MethodSymbol? equalityComparer_get_Default = null; BoundExpression currentHashValue; if (ContainingType.BaseTypeNoUseSiteDiagnostics.IsObjectType()) { if (_equalityContract.GetMethod is null) { // The equality contract isn't usable, an error was reported elsewhere F.CloseMethod(F.ThrowNull()); return; } if (_equalityContract.IsStatic) { F.CloseMethod(F.ThrowNull()); return; } // There are no base record types. // Get hash code of the equality contract and combine it with hash codes for field values. ensureEqualityComparerHelpers( F, ref equalityComparer_GetHashCode, ref equalityComparer_get_Default ); currentHashValue = MethodBodySynthesizer.GenerateGetHashCode( equalityComparer_GetHashCode !, equalityComparer_get_Default !, F.Property(F.This(), _equalityContract), F ); } else { // There are base record types. // Get base.GetHashCode() and combine it with hash codes for field values. var overridden = OverriddenMethod; if ( overridden is null || overridden.ReturnType.SpecialType != SpecialType.System_Int32 ) { // There was a problem with overriding, an error was reported elsewhere F.CloseMethod(F.ThrowNull()); return; } currentHashValue = F.Call(F.Base(overridden.ContainingType), overridden); } // bound HASH_FACTOR BoundLiteral?boundHashFactor = null; foreach (var f in ContainingType.GetFieldsToEmit()) { if (!f.IsStatic) { ensureEqualityComparerHelpers( F, ref equalityComparer_GetHashCode, ref equalityComparer_get_Default ); currentHashValue = MethodBodySynthesizer.GenerateHashCombine( currentHashValue, equalityComparer_GetHashCode !, equalityComparer_get_Default !, ref boundHashFactor, F.Field(F.This(), f), F ); } } F.CloseMethod(F.Block(F.Return(currentHashValue))); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); }
/// <summary> /// Given a SynthesizedSealedPropertyAccessor (an accessor with a reference to the accessor it overrides), /// construct a BoundBlock body. /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this.OriginalDefinition; try { MethodSymbol methodBeingWrapped = this.BaseMethod; if (this.Arity > 0) { Debug.Assert(this.Arity == methodBeingWrapped.Arity); methodBeingWrapped = methodBeingWrapped.ConstructedFrom.Construct(StaticCast<TypeSymbol>.From(this.TypeParameters)); } BoundBlock body = MethodBodySynthesizer.ConstructSingleInvocationMethodBody(F, methodBeingWrapped, useBaseReference: true); if (body.Kind != BoundKind.Block) body = F.Block(body); F.CompilationState.AddMethodWrapper(methodBeingWrapped, this, body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); } }
protected override ImmutableArray <LocalSymbol> GenerateLocals(SyntheticBoundNodeFactory f, BoundExpression receiver) { return(ImmutableArray <LocalSymbol> .Empty); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; try { LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); ParameterSymbol text = this.Parameters[0]; // This method should be kept consistent with ComputeStringHash //uint hashCode = 0; //if (text != null) //{ // hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; //} //return hashCode; var body = F.Block( ImmutableArray.Create<LocalSymbol>(hashCode, i), F.If( F.Binary(BinaryOperatorKind.ObjectNotEqual, F.SpecialType(SpecialType.System_Boolean), F.Parameter(text), F.Null(text.Type)), F.Block( F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Chars), F.Local(i)), ConversionKind.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call(F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Length))), F.Goto(again)))), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
protected override (ImmutableArray <BoundExpression> args, ImmutableArray <RefKind> refs) GenerateArguments(SyntheticBoundNodeFactory f) { var argsB = ArrayBuilder <BoundExpression> .GetInstance(); var refsB = ArrayBuilder <RefKind> .GetInstance(); foreach (var p in ImplementingMethod.Parameters) { argsB.Add(f.Parameter(p)); refsB.Add(p.RefKind); } return(argsB.ToImmutableAndFree(), refsB.ToImmutableAndFree()); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var factory = new SyntheticBoundNodeFactory(this, _syntax, compilationState, diagnostics); factory.CurrentMethod = this; // The method body is "throw null;" although the body // is arbitrary since the method will not be invoked. var body = factory.Block(factory.ThrowNull()); factory.CloseMethod(body); }
protected override BoundExpression GenerateCall(SyntheticBoundNodeFactory f, BoundExpression receiver, ImmutableArray <BoundExpression> arguments, ImmutableArray <RefKind> refKinds, DiagnosticBag diagnostics) { // For user-defined operators, the normal shim call approach works // fine. However, we also want to permit shim calls into types // with builtin operators, for which we need to do an actual // lookup as to which operator we're defining, and a quick // jump into part of the operator overload resolution code to see // if we're actually in one of those types. // // This may be incomplete, but is probably(??) sound. // TODO(@MattWindsor91): consider refkinds? if (ImplementingMethod.OriginalDefinition is SourceUserDefinedOperatorSymbol op) { Debug.Assert(receiver.Kind == BoundKind.TypeExpression, "receiver of an operator should always be a type"); var rectype = (BoundTypeExpression)receiver; var opdecl = op.GetSyntax(); Debug.Assert(opdecl != null, "should have operator syntax here"); var opsyn = opdecl.OperatorToken; var opkind = opsyn.Kind(); var binder = DeclaringCompilation.GetBinder(ImplementingMethod.GetNonNullSyntaxNode()).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.InShim, this); var ovr = new OverloadResolution(binder); var ignore = new HashSet <DiagnosticInfo>(); if (arguments.Length == 1) { (var usuccess, var ukind) = TryGetUnaryOperatorKind(opsyn.Kind()); if (usuccess) { var result = UnaryOperatorOverloadResolutionResult.GetInstance(); ovr.UnaryOperatorOverloadResolution(ukind, arguments[0], result, ref ignore); if (result.SingleValid()) { var bsig = result.Best.Signature; if (bsig.Method == null) { return(f.Unary(bsig.Kind, bsig.ReturnType, arguments[0])); } } } } else if (arguments.Length == 2) { (var bsuccess, var bkind) = TryGetBinaryOperatorKind(opsyn.Kind()); if (bsuccess) { var result = BinaryOperatorOverloadResolutionResult.GetInstance(); ovr.BinaryOperatorOverloadResolution(bkind, arguments[0], arguments[1], result, ref ignore); if (result.SingleValid()) { var bsig = result.Best.Signature; if (bsig.Method == null) { return(f.Binary(bsig.Kind, bsig.ReturnType, arguments[0], arguments[1])); } } } } } return(base.GenerateCall(f, receiver, arguments, refKinds, diagnostics)); }
protected SyntheticBoundNodeFactory CreateBoundNodeFactory(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; return F; }
internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, TypeMap typeMap, out AsyncMethodBuilderMemberCollection collection) { if (method.IsIterator) { var builderType = F.WellKnownType(WellKnownType.core_runtime_compiler_AsyncIteratorMethodBuilder); Debug.Assert((object)builderType != null); TryGetBuilderMember <MethodSymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Create, builderType, customBuilder: false, out MethodSymbol createBuilderMethod); if (createBuilderMethod is null) { collection = default; return(false); } return(TryCreate( F, customBuilder: false, builderType: builderType, resultType: F.SpecialType(SpecialType.System_Void), createBuilderMethod: createBuilderMethod, taskProperty: null, setException: null, // unused setResult: WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Complete, awaitOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__AwaitOnCompleted, awaitUnsafeOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__AwaitUnsafeOnCompleted, start: WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__MoveNext_T, setStateMachine: null, // unused collection: out collection)); } if (method.IsVoidReturningAsync()) { var builderType = F.WellKnownType(WellKnownType.core_runtime_compiler_AsyncVoidMethodBuilder); Debug.Assert((object)builderType != null); MethodSymbol createBuilderMethod; bool customBuilder = false; TryGetBuilderMember <MethodSymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__Create, builderType, customBuilder, out createBuilderMethod); if ((object)createBuilderMethod == null) { collection = default(AsyncMethodBuilderMemberCollection); return(false); } return(TryCreate( F, customBuilder: customBuilder, builderType: builderType, resultType: F.SpecialType(SpecialType.System_Void), createBuilderMethod: createBuilderMethod, taskProperty: null, setException: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__SetException, setResult: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__SetResult, awaitOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitOnCompleted, awaitUnsafeOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted, start: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__Start_T, setStateMachine: WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__SetStateMachine, collection: out collection)); } if (method.IsTaskReturningAsync(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType.TypeSymbol; NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; object builderArgument; bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: false); if ((object)builderType != null) { taskProperty = GetCustomTaskProperty(F, builderType, returnType); createBuilderMethod = GetCustomCreateMethod(F, builderType); } } else { builderType = F.WellKnownType(WellKnownType.core_runtime_compiler_AsyncTaskMethodBuilder); Debug.Assert((object)builderType != null); TryGetBuilderMember <MethodSymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, builderType, customBuilder, out createBuilderMethod); TryGetBuilderMember <PropertySymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Task, builderType, customBuilder, out taskProperty); } if ((object)builderType == null || (object)createBuilderMethod == null || (object)taskProperty == null) { collection = default(AsyncMethodBuilderMemberCollection); return(false); } return(TryCreate( F, customBuilder: customBuilder, builderType: builderType, resultType: F.SpecialType(SpecialType.System_Void), createBuilderMethod: createBuilderMethod, taskProperty: taskProperty, setException: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetException, setResult: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetResult, awaitOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitOnCompleted, awaitUnsafeOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__AwaitUnsafeOnCompleted, start: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Start_T, setStateMachine: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__SetStateMachine, collection: out collection)); } if (method.IsGenericTaskReturningAsync(F.Compilation)) { var returnType = (NamedTypeSymbol)method.ReturnType.TypeSymbol; var resultType = returnType.TypeArgumentsNoUseSiteDiagnostics.Single().TypeSymbol; if (typeMap != null) { resultType = typeMap.SubstituteType(resultType).TypeSymbol; } returnType = returnType.ConstructedFrom.Construct(resultType); NamedTypeSymbol builderType; MethodSymbol createBuilderMethod = null; PropertySymbol taskProperty = null; object builderArgument; bool customBuilder = returnType.IsCustomTaskType(out builderArgument); if (customBuilder) { builderType = ValidateBuilderType(F, builderArgument, returnType.DeclaredAccessibility, isGeneric: true); if ((object)builderType != null) { builderType = builderType.ConstructedFrom.Construct(resultType); taskProperty = GetCustomTaskProperty(F, builderType, returnType); createBuilderMethod = GetCustomCreateMethod(F, builderType); } } else { builderType = F.WellKnownType(WellKnownType.core_runtime_compiler_AsyncTaskMethodBuilder_T); Debug.Assert((object)builderType != null); builderType = builderType.Construct(resultType); TryGetBuilderMember <MethodSymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Create, builderType, customBuilder, out createBuilderMethod); TryGetBuilderMember <PropertySymbol>( F, WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Task, builderType, customBuilder, out taskProperty); } if ((object)builderType == null || (object)taskProperty == null || (object)createBuilderMethod == null) { collection = default(AsyncMethodBuilderMemberCollection); return(false); } return(TryCreate( F, customBuilder: customBuilder, builderType: builderType, resultType: resultType, createBuilderMethod: createBuilderMethod, taskProperty: taskProperty, setException: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetException, setResult: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetResult, awaitOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitOnCompleted, awaitUnsafeOnCompleted: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__AwaitUnsafeOnCompleted, start: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__Start_T, setStateMachine: WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T__SetStateMachine, collection: out collection)); } throw ExceptionUtilities.UnexpectedValue(method); }