Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add array initialization optimization #62392

Merged
merged 8 commits into from
Jul 15, 2022
56 changes: 39 additions & 17 deletions src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1534,37 +1534,36 @@ private void EmitDefaultValueTypeConstructorCallExpression(BoundCall call)
FreeOptTemp(tempOpt);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void EmitStaticCallExpression(BoundCall call, UseKind useKind)
private void EmitStaticCall(MethodSymbol method, BoundExpression receiverOpt, ImmutableArray<BoundExpression> arguments, UseKind useKind, SyntaxNode syntax, ImmutableArray<RefKind> refKindsOpt)
{
var method = call.Method;
var receiver = call.ReceiverOpt;
var arguments = call.Arguments;

Debug.Assert(method.IsStatic);

EmitArguments(arguments, method.Parameters, call.ArgumentRefKindsOpt);
EmitArguments(arguments, method.Parameters, refKindsOpt);
int stackBehavior = GetCallStackBehavior(method, arguments);

if (method.IsAbstract || method.IsVirtual)
{
if (receiver is not BoundTypeExpression { Type: { TypeKind: TypeKind.TypeParameter } })
if (receiverOpt is not BoundTypeExpression { Type.TypeKind: TypeKind.TypeParameter })
{
throw ExceptionUtilities.Unreachable;
}

_builder.EmitOpCode(ILOpCode.Constrained);
EmitSymbolToken(receiver.Type, receiver.Syntax);
EmitSymbolToken(receiverOpt.Type, receiverOpt.Syntax);
}

_builder.EmitOpCode(ILOpCode.Call, stackBehavior);

EmitSymbolToken(method, call.Syntax,
method.IsVararg ? (BoundArgListOperator)arguments[arguments.Length - 1] : null);
EmitSymbolToken(method, syntax,
method.IsVararg ? (BoundArgListOperator)arguments[^1] : null);

EmitCallCleanup(call.Syntax, useKind, method);
EmitCallCleanup(syntax, useKind, method);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void EmitStaticCallExpression(BoundCall call, UseKind useKind)
=> EmitStaticCall(call.Method, call.ReceiverOpt, call.Arguments, useKind, call.Syntax, call.ArgumentRefKindsOpt);

[MethodImpl(MethodImplOptions.NoInlining)]
private void EmitInstanceCallExpression(BoundCall call, UseKind useKind)
{
Expand Down Expand Up @@ -1917,19 +1916,42 @@ private void EmitArrayLength(BoundArrayLength expression, bool used)
EmitPopIfUnused(used);
}

private void EmitArrayCreationExpression(BoundArrayCreation expression, bool used)
private void EmitUninitializedArrayCreation(int initializerLength, SyntaxNode syntax, MethodSymbol allocUninitialized)
{
var arrayType = (ArrayTypeSymbol)expression.Type;
BoundExpression receiverOpt = null;

var arrLen = ConstantValue.Create(initializerLength);
var pinned = ConstantValue.Create(false);

var arg1 = new BoundLiteral(syntax, arrLen, _module.Compilation.GetSpecialType(SpecialType.System_Int32));
var arg2 = new BoundLiteral(syntax, pinned, _module.Compilation.GetSpecialType(SpecialType.System_Boolean));
var arguments = ImmutableArray.Create<BoundExpression>(arg1, arg2);

EmitArrayIndices(expression.Bounds);
EmitStaticCall(allocUninitialized, receiverOpt, arguments, UseKind.UsedAsValue, syntax,
ImmutableArray.Create(RefKind.None, RefKind.None));
}

private void EmitArrayCreationExpression(BoundArrayCreation expression, bool used)
{
var arrayType = (ArrayTypeSymbol)expression.Type;
if (arrayType.IsSZArray)
{
_builder.EmitOpCode(ILOpCode.Newarr);
EmitSymbolToken(arrayType.ElementType, expression.Syntax);
var allocUninitialized = _module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_GC__AllocateUninitializedArray_T);
if (expression.InitializerOpt != null && allocUninitialized is MethodSymbol { } alloc)
adamperlin marked this conversation as resolved.
Show resolved Hide resolved
{
var constructed = alloc.Construct(ImmutableArray.Create(arrayType.ElementType));
EmitUninitializedArrayCreation(expression.InitializerOpt.Initializers.Length, expression.Syntax, constructed);
}
else
{
EmitArrayIndices(expression.Bounds);
_builder.EmitOpCode(ILOpCode.Newarr);
EmitSymbolToken(arrayType.ElementType, expression.Syntax);
}
}
else
{
EmitArrayIndices(expression.Bounds);
_builder.EmitArrayCreation(_module.Translate(arrayType), expression.Syntax, _diagnostics);
}

Expand Down
Loading