diff --git a/Cpp2IL.Core/Cpp2IL.Core.csproj b/Cpp2IL.Core/Cpp2IL.Core.csproj index 1f34073f..20b01911 100644 --- a/Cpp2IL.Core/Cpp2IL.Core.csproj +++ b/Cpp2IL.Core/Cpp2IL.Core.csproj @@ -34,7 +34,8 @@ - + + @@ -51,7 +52,7 @@ - + diff --git a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs b/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs index 208438cf..0f832abc 100644 --- a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs +++ b/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs @@ -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; @@ -25,8 +21,7 @@ public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext) { var managedMethod = methodCtx.GetExtraData("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 @@ -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(); - } - - /// - /// Is this an out parameter? - /// - /// - /// The base type of the - /// - 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)); - } - } } diff --git a/Cpp2IL.Core/Utils/AsmResolver/CilInstructionCollectionExtensions.cs b/Cpp2IL.Core/Utils/AsmResolver/CilInstructionCollectionExtensions.cs deleted file mode 100644 index d4f0b3df..00000000 --- a/Cpp2IL.Core/Utils/AsmResolver/CilInstructionCollectionExtensions.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using AsmResolver.DotNet.Code.Cil; -using AsmResolver.DotNet.Signatures.Types; -using AsmResolver.PE.DotNet.Cil; -using AsmResolver.PE.DotNet.Metadata.Tables.Rows; - -namespace Cpp2IL.Core.Utils.AsmResolver; - -internal static class CilInstructionCollectionExtensions -{ - public static CilLocalVariable AddLocalVariable(this CilInstructionCollection instructions, TypeSignature variableType) - { - var variable = new CilLocalVariable(variableType); - instructions.Owner.LocalVariables.Add(variable); - return variable; - } - - public static void AddDefaultValueForType(this CilInstructionCollection instructions, TypeSignature type) - { - if (type is CorLibTypeSignature { IsValueType: true } corLibTypeSignature) - { - instructions.AddDefaultPrimitiveValue(corLibTypeSignature); - } - else if (type is ByReferenceTypeSignature) - { - instructions.AddNullRef(); - } - else if (type.IsValueTypeOrGenericParameter()) - { - instructions.AddDefaultValueForUnknownType(type); - } - else - { - instructions.Add(CilOpCodes.Ldnull); - } - } - - /// - /// Load a null reference onto the stack. - /// - /// - /// The specified instructions come from the documentation for .
- /// They decompile as: ref *(T*)null - /// The decompilation is valid C# and is the most optimized implementation. - /// However, it does produce a compiler warning. - ///
- /// - private static void AddNullRef(this CilInstructionCollection instructions) - { - instructions.Add(CilOpCodes.Ldc_I4_0); - instructions.Add(CilOpCodes.Conv_U); - } - - /// - /// Load the default value onto the stack for an unknown type. - /// - /// - /// This is a silver bullet. It handles any type except void and by ref. - /// - /// - /// - private static void AddDefaultValueForUnknownType(this CilInstructionCollection instructions, TypeSignature type) - { - Debug.Assert(type is not CorLibTypeSignature { ElementType: ElementType.Void } and not ByReferenceTypeSignature); - var variable = instructions.AddLocalVariable(type); - instructions.Add(CilOpCodes.Ldloca, variable); - instructions.Add(CilOpCodes.Initobj, type.ToTypeDefOrRef()); - instructions.Add(CilOpCodes.Ldloc, variable); - } - - private static void AddDefaultPrimitiveValue(this CilInstructionCollection instructions, CorLibTypeSignature type) - { - switch (type.ElementType) - { - case ElementType.Void: - break; - case ElementType.U1 or ElementType.U2 or ElementType.U4 or ElementType.I1 or ElementType.I2 or ElementType.I4 or ElementType.Boolean or ElementType.Char: - instructions.Add(CilOpCodes.Ldc_I4_0); - break; - case ElementType.I8: - instructions.Add(CilOpCodes.Ldc_I4_0); - instructions.Add(CilOpCodes.Conv_I8); - break; - case ElementType.U8: - instructions.Add(CilOpCodes.Ldc_I4_0); - instructions.Add(CilOpCodes.Conv_U8); - break; - case ElementType.I: - instructions.Add(CilOpCodes.Ldc_I4_0); - instructions.Add(CilOpCodes.Conv_I); - break; - case ElementType.U: - instructions.Add(CilOpCodes.Ldc_I4_0); - instructions.Add(CilOpCodes.Conv_U); - break; - case ElementType.R4: - instructions.Add(CilOpCodes.Ldc_R4, 0f); - break; - case ElementType.R8: - instructions.Add(CilOpCodes.Ldc_R8, 0d); - break; - case ElementType.Object or ElementType.String: - instructions.Add(CilOpCodes.Ldnull); - break; - case ElementType.TypedByRef: - instructions.AddDefaultValueForUnknownType(type); - break; - default: - throw new ArgumentOutOfRangeException(null); - } - } -} diff --git a/Cpp2IL.Core/Utils/AsmResolver/TypeSignatureExtensions.cs b/Cpp2IL.Core/Utils/AsmResolver/TypeSignatureExtensions.cs deleted file mode 100644 index 40545076..00000000 --- a/Cpp2IL.Core/Utils/AsmResolver/TypeSignatureExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using AsmResolver.DotNet.Signatures.Types; - -namespace Cpp2IL.Core.Utils.AsmResolver; - -internal static class TypeSignatureExtensions -{ - public static bool IsValueTypeOrGenericParameter(this TypeSignature type) - { - return type is { IsValueType: true } or GenericParameterSignature; - } -}