public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node) { BoundSpillSequenceBuilder builder = null; BoundExpression count = VisitExpression(ref builder, node.Count); var initializerOpt = (BoundArrayInitialization)VisitExpression(ref builder, node.InitializerOpt); return(UpdateExpression(builder, node.Update(node.ElementType, count, initializerOpt, node.Type))); }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } var elementType = stackAllocNode.ElementType; if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type)); } else if (type.OriginalDefinition == _compilation.GetWellKnownType(WellKnownType.System_Span_T)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var sideEffects = ArrayBuilder <BoundExpression> .GetInstance(); var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var countTemp = CaptureExpressionInTempIfNeeded(rewrittenCount, sideEffects, locals); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, spanType); BoundExpression constructorCall; if (TryGetWellKnownTypeMember(stackAllocNode.Syntax, WellKnownMember.System_Span_T__ctor, out MethodSymbol spanConstructor)) { constructorCall = _factory.New((MethodSymbol)spanConstructor.SymbolAsMember(spanType), stackAllocNode, countTemp); } else { constructorCall = new BoundBadExpression( syntax: stackAllocNode.Syntax, resultKind: LookupResultKind.NotInvocable, symbols: ImmutableArray <Symbol> .Empty, childBoundNodes: ImmutableArray <BoundExpression> .Empty, type: ErrorTypeSymbol.UnknownResultType); } return(new BoundSequence( syntax: stackAllocNode.Syntax, locals: locals.ToImmutableAndFree(), sideEffects: sideEffects.ToImmutableAndFree(), value: constructorCall, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } var elementType = stackAllocNode.ElementType; if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, stackAllocNode.Type)); } else if (type.IsSpanType()) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var countTemp = _factory.StoreToTemp(rewrittenCount, out BoundAssignmentOperator countTempAssignment); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, spanType); var spanCtor = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor).SymbolAsMember(spanType); var ctorCall = _factory.New(spanCtor, stackAllocNode, countTemp); return(new BoundSequence( syntax: stackAllocNode.Syntax, locals: ImmutableArray.Create(countTemp.LocalSymbol), sideEffects: ImmutableArray.Create <BoundExpression>(countTempAssignment), value: ctorCall, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }
public override BoundNode VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression stackAllocNode) { return(VisitStackAllocArrayCreation(stackAllocNode)); }
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode) { var rewrittenCount = VisitExpression(stackAllocNode.Count); var type = stackAllocNode.Type; if (rewrittenCount.ConstantValue?.Int32Value == 0) { // either default(span) or nullptr return(_factory.Default(type)); } var elementType = stackAllocNode.ElementType; var initializerOpt = stackAllocNode.InitializerOpt; if (initializerOpt != null) { initializerOpt = initializerOpt.Update(VisitList(initializerOpt.Initializers)); } if (type.IsPointerType()) { var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType); return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, stackAllocNode.Type)); } else if (TypeSymbol.Equals(type.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.ConsiderEverything2)) { var spanType = (NamedTypeSymbol)stackAllocNode.Type; var sideEffects = ArrayBuilder <BoundExpression> .GetInstance(); var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var countTemp = CaptureExpressionInTempIfNeeded(rewrittenCount, sideEffects, locals, SynthesizedLocalKind.Spill); var stackSize = RewriteStackAllocCountToSize(countTemp, elementType); stackAllocNode = new BoundConvertedStackAllocExpression( stackAllocNode.Syntax, elementType, stackSize, initializerOpt, _compilation.CreatePointerTypeSymbol(elementType)); BoundExpression constructorCall; if (TryGetWellKnownTypeMember(stackAllocNode.Syntax, WellKnownMember.System_Span_T__ctor, out MethodSymbol spanConstructor)) { constructorCall = _factory.New((MethodSymbol)spanConstructor.SymbolAsMember(spanType), stackAllocNode, countTemp); } else { constructorCall = new BoundBadExpression( syntax: stackAllocNode.Syntax, resultKind: LookupResultKind.NotInvocable, symbols: ImmutableArray <Symbol> .Empty, childBoundNodes: ImmutableArray <BoundExpression> .Empty, type: ErrorTypeSymbol.UnknownResultType); } // The stackalloc instruction requires that the evaluation stack contains only its parameter when executed. // We arrange to clear the stack by wrapping it in a SpillSequence, which will cause pending computations // to be spilled, and also by storing the result in a temporary local, so that the result does not get // hoisted/spilled into some state machine. If that temp local needs to be spilled that will result in an // error. _needsSpilling = true; var tempAccess = _factory.StoreToTemp(constructorCall, out BoundAssignmentOperator tempAssignment, syntaxOpt: stackAllocNode.Syntax); sideEffects.Add(tempAssignment); locals.Add(tempAccess.LocalSymbol); return(new BoundSpillSequence( syntax: stackAllocNode.Syntax, locals: locals.ToImmutableAndFree(), sideEffects: sideEffects.ToImmutableAndFree(), value: tempAccess, type: spanType)); } else { throw ExceptionUtilities.UnexpectedValue(type); } }