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

Reduce closures allocated during invocation of CapturedSymbolReplacement.Replacement #74258

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,14 @@ protected override BoundExpression FramePointer(SyntaxNode syntax, NamedTypeSymb
// However, frame pointer local variables themselves can be "captured". In that case
// the inner frames contain pointers to the enclosing frames. That is, nested
// frame pointers are organized in a linked list.
return proxyField.Replacement(syntax, frameType => FramePointer(syntax, frameType));
return proxyField.Replacement(
syntax,
static (frameType, arg) =>
{
var (syntax, @this) = arg;
return @this.FramePointer(syntax, frameType);
},
(syntax, this));
ToddGrun marked this conversation as resolved.
Show resolved Hide resolved
}

var localFrame = (LocalSymbol)framePointer;
Expand Down Expand Up @@ -777,7 +784,15 @@ private void InitVariableProxy(SyntaxNode syntax, Symbol symbol, LocalSymbol fra
throw ExceptionUtilities.UnexpectedValue(symbol.Kind);
}

var left = proxy.Replacement(syntax, frameType1 => new BoundLocal(syntax, framePointer, null, framePointer.Type));
var left = proxy.Replacement(
syntax,
static (frameType1, arg) =>
{
var (syntax, framePointer) = arg;
return new BoundLocal(syntax, framePointer, null, framePointer.Type);
},
(syntax, framePointer));

var assignToProxy = new BoundAssignmentOperator(syntax, left, value, value.Type);
if (_currentMethod.MethodKind == MethodKind.Constructor &&
symbol == _currentMethod.ThisParameter &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,15 @@ private bool TryReplaceWithProxy(Symbol parameterOrLocal, SyntaxNode syntax, [No
{
if (proxies.TryGetValue(parameterOrLocal, out CapturedSymbolReplacement? proxy))
{
replacement = proxy.Replacement(syntax, frameType => FramePointer(syntax, frameType));
replacement = proxy.Replacement(
syntax,
static (frameType, arg) =>
{
var (syntax, @this) = arg;
return @this.FramePointer(syntax, frameType);
},
(syntax, this));

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public CapturedSymbolReplacement(bool isReusable)
/// Rewrite the replacement expression for the hoisted local so all synthesized field are accessed as members
/// of the appropriate frame.
/// </summary>
public abstract BoundExpression Replacement(SyntaxNode node, Func<NamedTypeSymbol, BoundExpression> makeFrame);
public abstract BoundExpression Replacement<TArg>(SyntaxNode node, Func<NamedTypeSymbol, TArg, BoundExpression> makeFrame, TArg arg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would really prefer if these put arg before makeFrame.

}

internal sealed class CapturedToFrameSymbolReplacement : CapturedSymbolReplacement
Expand All @@ -36,9 +36,9 @@ public CapturedToFrameSymbolReplacement(LambdaCapturedVariable hoistedField, boo
this.HoistedField = hoistedField;
}

public override BoundExpression Replacement(SyntaxNode node, Func<NamedTypeSymbol, BoundExpression> makeFrame)
public override BoundExpression Replacement<TArg>(SyntaxNode node, Func<NamedTypeSymbol, TArg, BoundExpression> makeFrame, TArg arg)
{
var frame = makeFrame(this.HoistedField.ContainingType);
var frame = makeFrame(this.HoistedField.ContainingType, arg);
var field = this.HoistedField.AsMember((NamedTypeSymbol)frame.Type);
return new BoundFieldAccess(node, frame, field, constantValueOpt: null);
}
Expand All @@ -54,9 +54,9 @@ public CapturedToStateMachineFieldReplacement(StateMachineFieldSymbol hoistedFie
this.HoistedField = hoistedField;
}

public override BoundExpression Replacement(SyntaxNode node, Func<NamedTypeSymbol, BoundExpression> makeFrame)
public override BoundExpression Replacement<TArg>(SyntaxNode node, Func<NamedTypeSymbol, TArg, BoundExpression> makeFrame, TArg arg)
{
var frame = makeFrame(this.HoistedField.ContainingType);
var frame = makeFrame(this.HoistedField.ContainingType, arg);
var field = this.HoistedField.AsMember((NamedTypeSymbol)frame.Type);
return new BoundFieldAccess(node, frame, field, constantValueOpt: null);
}
Expand All @@ -74,7 +74,7 @@ public CapturedToExpressionSymbolReplacement(BoundExpression replacement, Immuta
this.HoistedFields = hoistedFields;
}

public override BoundExpression Replacement(SyntaxNode node, Func<NamedTypeSymbol, BoundExpression> makeFrame)
public override BoundExpression Replacement<TArg>(SyntaxNode node, Func<NamedTypeSymbol, TArg, BoundExpression> makeFrame, TArg arg)
{
// By returning the same replacement each time, it is possible we
// are constructing a DAG instead of a tree for the translation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public MethodToStateMachineRewriter(
proxies.TryGetValue(thisParameter, out thisProxy) &&
F.Compilation.Options.OptimizationLevel == OptimizationLevel.Release)
{
BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, frameType => F.This());
BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, static (frameType, F) => F.This(), F);
Debug.Assert(thisProxyReplacement.Type is not null);
this.cachedThis = F.SynthesizedLocal(thisProxyReplacement.Type, syntax: F.Syntax, kind: SynthesizedLocalKind.FrameCache);
}
Expand Down Expand Up @@ -925,7 +925,7 @@ protected BoundStatement CacheThisIfNeeded()
if ((object)this.cachedThis != null)
{
CapturedSymbolReplacement proxy = proxies[this.OriginalMethod.ThisParameter];
var fetchThis = proxy.Replacement(F.Syntax, frameType => F.This());
var fetchThis = proxy.Replacement(F.Syntax, static (frameType, F) => F.This(), F);
return F.Assignment(F.Local(this.cachedThis), fetchThis);
}

Expand Down Expand Up @@ -961,7 +961,7 @@ public sealed override BoundNode VisitThisReference(BoundThisReference node)
else
{
Debug.Assert(proxy != null);
return proxy.Replacement(F.Syntax, frameType => F.This());
return proxy.Replacement(F.Syntax, static (frameType, F) => F.This(), F);
}
}

Expand All @@ -977,7 +977,7 @@ public override BoundNode VisitBaseReference(BoundBaseReference node)

CapturedSymbolReplacement proxy = proxies[this.OriginalMethod.ThisParameter];
Debug.Assert(proxy != null);
return proxy.Replacement(F.Syntax, frameType => F.This());
return proxy.Replacement(F.Syntax, static (frameType, F) => F.This(), F);
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,16 @@ protected BoundStatement GenerateParameterStorage(LocalSymbol stateMachineVariab
CapturedSymbolReplacement proxy;
if (proxies.TryGetValue(method.ThisParameter, out proxy))
{
bodyBuilder.Add(F.Assignment(proxy.Replacement(F.Syntax, frameType1 => F.Local(stateMachineVariable)), F.This()));
var leftExpression = proxy.Replacement(
F.Syntax,
static (frameType1, arg) =>
{
var (F, stateMachineVariable) = arg;
return F.Local(stateMachineVariable);
},
(F, stateMachineVariable));

bodyBuilder.Add(F.Assignment(leftExpression, F.This()));
}
}

Expand All @@ -320,8 +329,16 @@ protected BoundStatement GenerateParameterStorage(LocalSymbol stateMachineVariab
CapturedSymbolReplacement proxy;
if (proxies.TryGetValue(parameter, out proxy))
{
bodyBuilder.Add(F.Assignment(proxy.Replacement(F.Syntax, frameType1 => F.Local(stateMachineVariable)),
F.Parameter(parameter)));
var leftExpression = proxy.Replacement(
F.Syntax,
static (frameType1, arg) =>
{
var (F, stateMachineVariable) = arg;
return F.Local(stateMachineVariable);
},
(F, stateMachineVariable));

bodyBuilder.Add(F.Assignment(leftExpression, F.Parameter(parameter)));
}
}

Expand Down Expand Up @@ -456,10 +473,18 @@ protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSy
CapturedSymbolReplacement proxy;
if (copyDest.TryGetValue(method.ThisParameter, out proxy))
{
bodyBuilder.Add(
F.Assignment(
proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable)),
copySrc[method.ThisParameter].Replacement(F.Syntax, stateMachineType => F.This())));
var leftExpression = proxy.Replacement(
F.Syntax,
static (stateMachineType, arg) =>
{
var (F, resultVariable) = arg;
return F.Local(resultVariable);
},
(F, resultVariable));

var rightExpression = copySrc[method.ThisParameter].Replacement(F.Syntax, static (stateMachineType, F) => F.This(), F);

bodyBuilder.Add(F.Assignment(leftExpression, rightExpression));
}
}

Expand All @@ -471,9 +496,17 @@ protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSy
if (copyDest.TryGetValue(parameter, out proxy))
{
// result.parameter
BoundExpression resultParameter = proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable));
BoundExpression resultParameter = proxy.Replacement(
F.Syntax,
static (stateMachineType, arg) =>
{
var (F, resultVariable) = arg;
return F.Local(resultVariable);
},
(F, resultVariable));

// this.parameterProxy
BoundExpression parameterProxy = copySrc[parameter].Replacement(F.Syntax, stateMachineType => F.This());
BoundExpression parameterProxy = copySrc[parameter].Replacement(F.Syntax, static (stateMachineType, F) => F.This(), F);
BoundStatement copy = InitializeParameterField(getEnumeratorMethod, parameter, resultParameter, parameterProxy);

bodyBuilder.Add(copy);
Expand Down
Loading