Skip to content

Commit

Permalink
Use AssetRipper.CIL for method filling (#248)
Browse files Browse the repository at this point in the history
  • Loading branch information
ds5678 authored Dec 31, 2023
1 parent c42ece9 commit 9581010
Show file tree
Hide file tree
Showing 4 changed files with 5 additions and 219 deletions.
5 changes: 3 additions & 2 deletions Cpp2IL.Core/Cpp2IL.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@

<ItemGroup>
<!--Needed for DLL output-->
<PackageReference Include="AsmResolver.DotNet" Version="5.1.0" />
<PackageReference Include="AsmResolver.DotNet" Version="5.5.0" />
<PackageReference Include="AssetRipper.CIL" Version="1.0.0" />

<!--For ARM64 dissassembly-->
<PackageReference Include="Disarm" Version="2022.1.0-master.26" />
Expand All @@ -51,7 +52,7 @@
<PackageReference Include="PolySharp" Version="1.14.1" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'net6.0'">
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<!--Supplementary packages to provide modern runtime features on netstandard2-->
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
Expand Down
94 changes: 2 additions & 92 deletions Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Collections;
using AsmResolver.DotNet.Signatures.Types;
using AsmResolver.PE.DotNet.Cil;
using AssetRipper.CIL;
using Cpp2IL.Core.Model.Contexts;

namespace Cpp2IL.Core.Utils.AsmResolver;
Expand All @@ -25,8 +21,7 @@ public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext)
{
var managedMethod = methodCtx.GetExtraData<MethodDefinition>("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {typeContext.Definition?.FullName}.{methodCtx.Definition?.Name}");

if (managedMethod.IsManagedMethodWithBody())
FillMethodBodyWithStub(managedMethod);
managedMethod.FillMethodBodyWithStub();
}
}
#if !DEBUG
Expand All @@ -38,89 +33,4 @@ public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext)
#endif
}
}

private static void FillMethodBodyWithStub(MethodDefinition methodDefinition)
{
methodDefinition.CilMethodBody = new(methodDefinition);
var methodInstructions = methodDefinition.CilMethodBody.Instructions;

if (methodDefinition.IsConstructor && !methodDefinition.IsStatic && !methodDefinition.DeclaringType!.IsValueType)
{
var baseConstructor = TryGetBaseConstructor(methodDefinition);
if (baseConstructor is not null)
{
methodInstructions.Add(CilOpCodes.Ldarg_0);
foreach (var baseParameter in baseConstructor.Parameters)
{
var importedBaseParameterType = methodDefinition.DeclaringType.Module!.DefaultImporter.ImportTypeSignature(baseParameter.ParameterType);
methodInstructions.AddDefaultValueForType(importedBaseParameterType);
}
methodInstructions.Add(CilOpCodes.Call, methodDefinition.DeclaringType.Module!.DefaultImporter.ImportMethod(baseConstructor));
}
}

foreach (var parameter in methodDefinition.Parameters)
{
//Although Roslyn-compiled code will only emit the out flag on ByReferenceTypeSignatures,
//Some Unity libraries have it on a handful (less than 100) of parameters with incompatible type signatures.
//One example on 2021.3.6 is int System.IO.CStreamReader.Read([In][Out] char[] dest, int index, int count)
//All the instances I investigated were clearly not meant to be out parameters.
//The [In][Out] attributes are not a decompilation issue and compile fine on .NET 7.
if (parameter.IsOutParameter(out var parameterType))
{
if (parameterType.IsValueTypeOrGenericParameter())
{
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
methodInstructions.Add(CilOpCodes.Initobj, parameterType.ToTypeDefOrRef());
}
else
{
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
methodInstructions.Add(CilOpCodes.Ldnull);
methodInstructions.Add(CilOpCodes.Stind_Ref);
}
}
}
methodInstructions.AddDefaultValueForType(methodDefinition.Signature!.ReturnType);
methodInstructions.Add(CilOpCodes.Ret);
methodInstructions.OptimizeMacros();
}

/// <summary>
/// Is this <see cref="Parameter"/> an out parameter?
/// </summary>
/// <param name="parameter"></param>
/// <param name="parameterType">The base type of the <see cref="ByReferenceTypeSignature"/></param>
/// <returns></returns>
private static bool IsOutParameter(this Parameter parameter, [NotNullWhen(true)] out TypeSignature? parameterType)
{
if ((parameter.Definition?.IsOut ?? false) && parameter.ParameterType is ByReferenceTypeSignature byReferenceTypeSignature)
{
parameterType = byReferenceTypeSignature.BaseType;
return true;
}
else
{
parameterType = default;
return false;
}
}

private static MethodDefinition? TryGetBaseConstructor(MethodDefinition methodDefinition)
{
var declaringType = methodDefinition.DeclaringType!;
var baseType = declaringType.BaseType?.Resolve();
if (baseType is null)
{
return null;
}
else if (declaringType.Module == baseType.Module)
{
return baseType.Methods.FirstOrDefault(m => m.IsConstructor && !m.IsStatic && !m.IsPrivate);
}
else
{
return baseType.Methods.FirstOrDefault(m => m.IsConstructor && !m.IsStatic && (m.IsFamily || m.IsPublic));
}
}
}
114 changes: 0 additions & 114 deletions Cpp2IL.Core/Utils/AsmResolver/CilInstructionCollectionExtensions.cs

This file was deleted.

11 changes: 0 additions & 11 deletions Cpp2IL.Core/Utils/AsmResolver/TypeSignatureExtensions.cs

This file was deleted.

0 comments on commit 9581010

Please sign in to comment.