Skip to content

Commit

Permalink
BUGFIX: instantiate callee declaring types with current generic context.
Browse files Browse the repository at this point in the history
  • Loading branch information
Washi1337 committed Mar 23, 2024
1 parent ab38780 commit 7d2705f
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
</PackageReference>
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
Expand All @@ -8,7 +9,7 @@ namespace Echo.Platforms.AsmResolver.Emulation.Dispatch
/// Provides information about the result of an instruction dispatch.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay}")]
public readonly struct CilDispatchResult
public readonly struct CilDispatchResult : IEquatable<CilDispatchResult>
{
private CilDispatchResult(ObjectHandle exceptionObject)
{
Expand Down Expand Up @@ -111,5 +112,26 @@ public static CilDispatchResult InvalidCast(CilExecutionContext context, TypeSig

return Exception(context.Machine, context.Machine.ValueFactory.InvalidCastExceptionType);
}

/// <inheritdoc />
public bool Equals(CilDispatchResult other)
{
return ExceptionObject.Equals(other.ExceptionObject);
}

/// <inheritdoc />
public override bool Equals(object? obj)
{
return obj is CilDispatchResult other && Equals(other);
}

/// <inheritdoc />
public override int GetHashCode()
{
return ExceptionObject.GetHashCode();
}

/// <inheritdoc />
public override string ToString() => DebuggerDisplay.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ namespace Echo.Platforms.AsmResolver.Emulation.Dispatch.ObjectModel
public class CallHandler : CallHandlerBase
{
/// <inheritdoc />
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(
CilExecutionContext context,
CilInstruction instruction,
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,
IList<BitVector> arguments)
{
return MethodDevirtualizationResult.Success((IMethodDescriptor) instruction.Operand!);
return MethodDevirtualizationResult.Success(method);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.DotNet.Signatures.Types;
using AsmResolver.PE.DotNet.Cil;
using Echo.Memory;
using Echo.Platforms.AsmResolver.Emulation.Invocation;
Expand All @@ -17,12 +18,12 @@ public abstract class CallHandlerBase : ICilOpCodeHandler
/// <inheritdoc />
public virtual CilDispatchResult Dispatch(CilExecutionContext context, CilInstruction instruction)
{
var method = (IMethodDescriptor) instruction.Operand!;
var method = InstantiateDeclaringType(context.CurrentFrame.Method, (IMethodDescriptor)instruction.Operand!);
var arguments = GetArguments(context, method);

try
{
return HandleCall(context, instruction, arguments);
return HandleCall(context, instruction, method, arguments);
}
finally
{
Expand Down Expand Up @@ -51,12 +52,13 @@ protected virtual bool ShouldPopInstanceObject(IMethodDescriptor method)
protected CilDispatchResult HandleCall(
CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,

Check warning on line 55 in src/Platforms/Echo.Platforms.AsmResolver/Emulation/Dispatch/ObjectModel/CallHandlerBase.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'method' has no matching param tag in the XML comment for 'CallHandlerBase.HandleCall(CilExecutionContext, CilInstruction, IMethodDescriptor, IList<BitVector>)' (but other parameters do)

Check warning on line 55 in src/Platforms/Echo.Platforms.AsmResolver/Emulation/Dispatch/ObjectModel/CallHandlerBase.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'method' has no matching param tag in the XML comment for 'CallHandlerBase.HandleCall(CilExecutionContext, CilInstruction, IMethodDescriptor, IList<BitVector>)' (but other parameters do)

Check warning on line 55 in src/Platforms/Echo.Platforms.AsmResolver/Emulation/Dispatch/ObjectModel/CallHandlerBase.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'method' has no matching param tag in the XML comment for 'CallHandlerBase.HandleCall(CilExecutionContext, CilInstruction, IMethodDescriptor, IList<BitVector>)' (but other parameters do)
IList<BitVector> arguments)
{
var callerFrame = context.CurrentFrame;

// Devirtualize the method in the operand.
var devirtualization = DevirtualizeMethod(context, instruction, arguments);
var devirtualization = DevirtualizeMethod(context, instruction, method, arguments);
if (devirtualization.IsUnknown)
throw new CilEmulatorException($"Devirtualization of method call {instruction} was inconclusive.");

Expand Down Expand Up @@ -113,20 +115,20 @@ private static BitVector GetInstancePointer(CilExecutionContext context, IMethod
return stack.Pop(declaringType);
}

private MethodDevirtualizationResult DevirtualizeMethod(
CilExecutionContext context,
CilInstruction instruction,
private MethodDevirtualizationResult DevirtualizeMethod(CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,
IList<BitVector> arguments)
{
var result = DevirtualizeMethodInternal(context, instruction, arguments);
var result = DevirtualizeMethodInternal(context, instruction, method, arguments);
if (!result.IsUnknown)
return result;

var method = context.Machine.UnknownResolver.ResolveMethod(context, instruction, arguments)
var resolved = context.Machine.UnknownResolver.ResolveMethod(context, instruction, arguments)
?? instruction.Operand as IMethodDescriptor;

if (method is not null)
result = MethodDevirtualizationResult.Success(method);
if (resolved is not null)
result = MethodDevirtualizationResult.Success(resolved);

return result;
}
Expand All @@ -136,13 +138,28 @@ private static BitVector GetInstancePointer(CilExecutionContext context, IMethod
/// </summary>
/// <param name="context">The execution context the instruction is evaluated in.</param>
/// <param name="instruction">The instruction that is being evaluated.</param>
/// <param name="method"></param>
/// <param name="arguments">The arguments pushed onto the stack.</param>
/// <returns>The result of the devirtualization.</returns>
protected abstract MethodDevirtualizationResult DevirtualizeMethodInternal(
CilExecutionContext context,
protected abstract MethodDevirtualizationResult DevirtualizeMethodInternal(CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,
IList<BitVector> arguments);

private static IMethodDescriptor InstantiateDeclaringType(IMethodDescriptor caller, IMethodDescriptor callee)
{
// The caller may pass along generic type arguments to the callee.
var context = GenericContext.FromMethod(caller);
if (callee.DeclaringType?.ToTypeDefOrRef() is TypeSpecification { Signature: {} typeSignature })
{
var newType = typeSignature.InstantiateGenericTypes(context);
if (newType != typeSignature)
return newType.ToTypeDefOrRef().CreateMemberReference(callee.Name!, callee.Signature!);
}

return callee;
}

private static CilDispatchResult Invoke(CilExecutionContext context, IMethodDescriptor method, IList<BitVector> arguments)
{
var result = context.Machine.Invoker.Invoke(context, method, arguments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public class CallVirtHandler : CallHandlerBase
private static readonly SignatureComparer Comparer = new();

/// <inheritdoc />
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(
CilExecutionContext context,
CilInstruction instruction,
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,
IList<BitVector> arguments)
{
switch (arguments[0].AsSpan())
Expand All @@ -34,7 +34,6 @@ public class CallVirtHandler : CallHandlerBase
.AsObjectHandle(context.Machine));

case var objectPointer:
var method = (IMethodDescriptor) instruction.Operand!;
var objectType = objectPointer.AsObjectHandle(context.Machine).GetObjectType();
var implementation = FindMethodImplementationInType(objectType.Resolve(), method.Resolve());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public override CilDispatchResult Dispatch(CilExecutionContext context, CilInstr
case AllocationResultType.Allocated:
// Insert the allocated "this" pointer into the arguments and call constructor.
arguments.Insert(0, allocation.Address!);
var result = HandleCall(context, instruction, arguments);
var result = HandleCall(context, instruction, constructor, arguments);

// If successful, push the resulting object onto the stack.
if (result.IsSuccess)
Expand Down Expand Up @@ -66,12 +66,12 @@ public override CilDispatchResult Dispatch(CilExecutionContext context, CilInstr
protected override bool ShouldPopInstanceObject(IMethodDescriptor method) => false;

/// <inheritdoc />
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(
CilExecutionContext context,
protected override MethodDevirtualizationResult DevirtualizeMethodInternal(CilExecutionContext context,
CilInstruction instruction,
IMethodDescriptor method,
IList<BitVector> arguments)
{
return MethodDevirtualizationResult.Success((IMethodDescriptor) instruction.Operand!);
return MethodDevirtualizationResult.Success(method);
}
}
}
Loading

0 comments on commit 7d2705f

Please sign in to comment.