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

Optimize multicast delegate thunk #104222

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 11 additions & 3 deletions src/coreclr/tools/Common/TypeSystem/IL/DelegateInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class DelegateInfo
private readonly TypeDesc _delegateType;
private readonly DelegateFeature _supportedFeatures;

private MethodSignature _signature;
private MethodDesc _invokeMethod;

private MethodDesc _getThunkMethod;
private DelegateThunkCollection _thunks;
Expand Down Expand Up @@ -71,8 +71,16 @@ public MethodSignature Signature
{
get
{
_signature ??= _delegateType.GetKnownMethod("Invoke", null).Signature;
return _signature;
return InvokeMethod.Signature;
}
}

public MethodDesc InvokeMethod
{
get
{
_invokeMethod ??= _delegateType.GetKnownMethod("Invoke", null);
return _invokeMethod;
}
}

Expand Down
43 changes: 7 additions & 36 deletions src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateThunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Internal.IL.Stubs
/// </summary>
public abstract partial class DelegateThunk : ILStubMethod
{
private DelegateInfo _delegateInfo;
protected readonly DelegateInfo _delegateInfo;

public DelegateThunk(DelegateInfo delegateInfo)
{
Expand Down Expand Up @@ -75,22 +75,6 @@ protected FieldDesc HelperObjectField
}
}

protected FieldDesc FirstParameterField
{
get
{
return SystemDelegateType.GetKnownField("_firstParameter");
}
}

protected FieldDesc FunctionPointerField
{
get
{
return SystemDelegateType.GetKnownField("_functionPointer");
}
}

public sealed override string DiagnosticName
{
get
Expand Down Expand Up @@ -310,7 +294,6 @@ public override MethodIL EmitIL()
ILLocalVariable delegateArrayLocal = emitter.NewLocal(invocationListArrayType);
ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
ILLocalVariable iteratorLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32));
ILLocalVariable delegateToCallLocal = emitter.NewLocal(SystemDelegateType);

ILLocalVariable returnValueLocal = 0;
if (!Signature.ReturnType.IsVoid)
Expand All @@ -323,11 +306,11 @@ public override MethodIL EmitIL()

// ldarg.0 (this pointer)
// ldfld Delegate._helperObject
// castclass Delegate.Wrapper[]
// castclass Delegate.Wrapper[] (omitted - generate unsafe cast assuming the delegate is well-formed)
// stloc delegateArrayLocal
codeStream.EmitLdArg(0);
codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField));
codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType));
// codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType));
codeStream.EmitStLoc(delegateArrayLocal);

// Fill in invocationCountLocal
Expand All @@ -354,43 +337,31 @@ public override MethodIL EmitIL()

// Implement as do/while loop. We only have this stub in play if we're in the multicast situation
// Find the delegate to call
// Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal].Value;
// delegateArrayLocal[iteratorLocal].Value

// ldloc delegateArrayLocal
// ldloc iteratorLocal
// ldelema Delegate.Wrapper
// ldfld Delegate.Wrapper.Value
// stloc delegateToCallLocal
codeStream.EmitLdLoc(delegateArrayLocal);
codeStream.EmitLdLoc(iteratorLocal);
codeStream.Emit(ILOpcode.ldelema, emitter.NewToken(delegateWrapperType));
codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(delegateWrapperType.GetKnownField("Value")));
codeStream.EmitStLoc(delegateToCallLocal);

// Call the delegate
// returnValueLocal = delegateToCallLocal(...);
// delegateArrayLocal[iteratorLocal].Value(...)

// ldloc delegateToCallLocal
// ldfld Delegate._firstParameter
// ldarg 1, n
// ldloc delegateToCallLocal
// ldfld Delegate._functionPointer
// calli returnValueType thiscall (all the params)
// callvirt DelegateType.Invoke(...)
// IF there is a return value
// stloc returnValueLocal

codeStream.EmitLdLoc(delegateToCallLocal);
codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField));

for (int i = 0; i < Signature.Length; i++)
{
codeStream.EmitLdArg(i + 1);
}

codeStream.EmitLdLoc(delegateToCallLocal);
codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField));

codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature));
codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(_delegateInfo.InvokeMethod.InstantiateAsOpen()));

if (returnValueLocal != 0)
codeStream.EmitStLoc(returnValueLocal);
Expand Down
Loading