Permalink
Switch branches/tags
version-2.9.0 version-2.8.2 version-2.8.0 version-2.7.0-beta3 version-2.6.0-beta3 version-2.4.0 version-2.3.5 version-2.3.4 version-2.3.2 version-2.3.2-beta1 version-2.3.0-beta3 version-2.3.0-beta2 version-2.3.0-beta1 version-2.2.0 version-2.1.0 version-2.0.0 version-2.0.0-rc4 version-2.0.0-rc3 version-2.0.0-rc2 version-2.0.0-rc version-2.0.0-beta5 version-2.0.0-beta4 version-2.0.0-beta3 version-2.0.0-beta1 version-1.3.2 version-1.3.1 version-1.3.0 version-1.3.0-beta1-20160429-01 version-1.2.2 version-1.2.1 version-1.2.0 version-1.2.0-beta1-20160108-01 version-1.2.0-beta version-1.2.0-beta-20151211-01 version-1.1.1 version-1.1.0 version-1.1.0-rc1-20151109-01 version-1.0.0 version-1.0.0-beta1-20141031-01 toolset_5 toolset_3 toolset_2 toolset_1_1 toolset_1 Visual.Studio.2015.Update.1.RC Visual.Studio.2015.Update.1.CTP Visual-Studio-2017 Visual-Studio-2017-Version-15.8 Visual-Studio-2017-Version-15.7.2 Visual-Studio-2017-Version-15.7 Visual-Studio-2017-Version-15.6 Visual-Studio-2017-Version-15.5 Visual-Studio-2017-Version-15.4 Visual-Studio-2017-Version-15.3.5 Visual-Studio-2017-Version-15.3.4 Visual-Studio-2017-Version-15.3.2 Visual-Studio-2017-Version-15.3 Visual-Studio-2017-Version-15.2 Visual-Studio-2017-Version-15.1 Visual-Studio-2017-RC4 Visual-Studio-2017-RC3 Visual-Studio-2017-RC2 Visual-Studio-2017-RC Visual-Studio-2017-Preview-Version-15.3 Visual-Studio-2017-Preview-6-Version-15.7 Visual-Studio-2017-Preview-3-Version-15.4 Visual-Studio-2017-Preview-3-Version-15.3 Visual-Studio-2017-Preview-2-Version-15.4 Visual-Studio-2017-Preview-2-Version-15.3 Visual-Studio-2017-Preview-1-Version-15.4 Visual-Studio-2015 Visual-Studio-2015-Update-3 Visual-Studio-2015-Update-3-Micro-Update-1 Visual-Studio-2015-Update-2 Visual-Studio-2015-Update-2-RC Visual-Studio-2015-Update-2-Micro-Update-3 Visual-Studio-2015-Update-2-Micro-Update-1 Visual-Studio-2015-Update-1 Visual-Studio-2015-Update-1-RC Visual-Studio-2015-Update-1-CTP Visual-Studio-2015-RC Visual-Studio-2015-Preview Visual-Studio-2015-CTP-6 Visual-Studio-2015-CTP-5 Visual-Studio-15-Preview Visual-Studio-15-Preview-5 Visual-Studio-15-Preview-4 Visual-Studio-15-Preview-3 VS.Toolset.Roslyn.1.1.0-beta1-20150727-01 VS.Tools.X86.Managed.V45.1.0.150513.2 Oss.Scan.2015.03.13 Oss.Scan.2013.03.13 NetFx.Toolset.150729
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
137 lines (115 sloc) 6.23 KB
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class LocalRewriter
{
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 (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, initializerOpt, 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);
}
}
private BoundExpression RewriteStackAllocCountToSize(BoundExpression countExpression, TypeSymbol elementType)
{
// From ILGENREC::genExpr:
// EDMAURER always perform a checked multiply regardless of the context.
// localloc takes an unsigned native int. When a user specifies a negative
// count of elements, per spec, the behavior is undefined. So convert element
// count to unsigned.
// NOTE: to match this special case logic, we're going to construct the multiplication
// ourselves, rather than calling MakeSizeOfMultiplication (which inserts various checks
// and conversions).
TypeSymbol uintType = _factory.SpecialType(SpecialType.System_UInt32);
TypeSymbol uintPtrType = _factory.SpecialType(SpecialType.System_UIntPtr);
// Why convert twice? Because dev10 actually uses an explicit conv_u instruction and the normal conversion
// from int32 to native uint is emitted as conv_i. The behavior we want to emulate is to re-interpret
// (i.e. unchecked) an int32 as unsigned (i.e. uint32) and then convert it to a native uint *without* sign
// extension.
BoundExpression sizeOfExpression = _factory.Sizeof(elementType);
var sizeConst = sizeOfExpression.ConstantValue;
if (sizeConst != null)
{
int size = sizeConst.Int32Value;
Debug.Assert(size > 0);
// common case: stackalloc int[123]
var countConst = countExpression.ConstantValue;
if (countConst != null)
{
var count = countConst.Int32Value;
long folded = unchecked((uint)count * size);
if (folded < uint.MaxValue)
{
return _factory.Convert(uintPtrType, _factory.Literal((uint)folded), Conversion.IntegerToPointer);
}
}
}
BoundExpression convertedCount = _factory.Convert(uintType, countExpression, Conversion.ExplicitNumeric);
convertedCount = _factory.Convert(uintPtrType, convertedCount, Conversion.IntegerToPointer);
// another common case: stackalloc byte[x]
if (sizeConst?.Int32Value == 1)
{
return convertedCount;
}
BinaryOperatorKind multiplicationKind = BinaryOperatorKind.Checked | BinaryOperatorKind.UIntMultiplication; //"UInt" just to make it unsigned
BoundExpression product = _factory.Binary(multiplicationKind, uintPtrType, convertedCount, sizeOfExpression);
return product;
}
}
}