Skip to content

Commit 53ed393

Browse files
authored
Call base constructors in Dummy Dll output (#163)
Resolves #102
1 parent b503474 commit 53ed393

6 files changed

+301
-133
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ SharpTreeView/obj/
4242
.vs
4343

4444
*.user
45+
46+
launchsettings.json

Diff for: Cpp2IL.Core/CorePlugin/AsmResolverDummyDllOutputFormat.cs

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public List<AssemblyDefinition> BuildAssemblies(ApplicationAnalysisContext conte
9696
#endif
9797

9898
MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.CopyDataFromIl2CppToManaged);
99+
MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverMethodFiller.FillManagedMethodBodies);
99100

100101
Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput");
101102

Diff for: Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs

+3-50
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,11 @@ public static void CopyDataFromIl2CppToManaged(AssemblyAnalysisContext asmContex
265265

266266
#if !DEBUG
267267
try
268-
{
269268
#endif
270-
CopyIl2CppDataToManagedType(typeContext, managedType);
271-
#if !DEBUG
269+
{
270+
CopyIl2CppDataToManagedType(typeContext, managedType);
272271
}
272+
#if !DEBUG
273273
catch (Exception e)
274274
{
275275
throw new Exception($"Failed to process type {managedType.FullName} (module {managedType.Module?.Name}, declaring type {managedType.DeclaringType?.FullName}) in {asmContext.Definition.AssemblyName.Name}", e);
@@ -368,9 +368,6 @@ private static void CopyMethodsInType(ReferenceImporter importer, TypeAnalysisCo
368368
managedMethod.ParameterDefinitions.Add(parameterDefinition);
369369
}
370370

371-
if (managedMethod.IsManagedMethodWithBody())
372-
FillMethodBodyWithStub(managedMethod);
373-
374371
//Handle generic parameters.
375372
methodDef?.GenericContainer?.GenericParameters.ToList()
376373
.ForEach(p =>
@@ -456,48 +453,4 @@ private static void CopyEventsInType(ReferenceImporter importer, TypeAnalysisCon
456453
ilTypeDefinition.Events.Add(managedEvent);
457454
}
458455
}
459-
460-
private static void FillMethodBodyWithStub(MethodDefinition methodDefinition)
461-
{
462-
methodDefinition.CilMethodBody = new(methodDefinition);
463-
464-
var methodInstructions = methodDefinition.CilMethodBody.Instructions;
465-
foreach (var parameter in methodDefinition.Parameters)
466-
{
467-
if(parameter.Definition?.IsOut ?? false)
468-
{
469-
if (parameter.ParameterType.IsValueType)
470-
{
471-
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
472-
methodInstructions.Add(CilOpCodes.Initobj, parameter.ParameterType.ToTypeDefOrRef());
473-
}
474-
else
475-
{
476-
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
477-
methodInstructions.Add(CilOpCodes.Ldnull);
478-
methodInstructions.Add(CilOpCodes.Stind_Ref);
479-
}
480-
}
481-
}
482-
if (methodDefinition.Signature!.ReturnType.FullName == "System.Void")
483-
{
484-
methodInstructions.Add(CilOpCodes.Ret);
485-
}
486-
else if (methodDefinition.Signature!.ReturnType.IsValueType)
487-
{
488-
var variable = new CilLocalVariable(methodDefinition.Signature!.ReturnType);
489-
methodDefinition.CilMethodBody.LocalVariables.Add(variable);
490-
methodDefinition.CilMethodBody.InitializeLocals = true;
491-
// methodInstructions.Add(CilOpCodes.Ldloca_S, variable);
492-
// methodInstructions.Add(CilOpCodes.Initobj, methodDefinition.Signature.ReturnType.ToTypeDefOrRef());
493-
methodInstructions.Add(CilOpCodes.Ldloc_0);
494-
methodInstructions.Add(CilOpCodes.Ret);
495-
}
496-
else
497-
{
498-
methodInstructions.Add(CilOpCodes.Ldnull);
499-
methodInstructions.Add(CilOpCodes.Ret);
500-
}
501-
methodInstructions.OptimizeMacros();
502-
}
503456
}
+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
using System.Linq;
3+
using AsmResolver.DotNet;
4+
using AsmResolver.DotNet.Code.Cil;
5+
using AsmResolver.DotNet.Signatures;
6+
using AsmResolver.DotNet.Signatures.Types;
7+
using AsmResolver.PE.DotNet.Cil;
8+
using AsmResolver.PE.DotNet.Metadata.Tables.Rows;
9+
using Cpp2IL.Core.Model.Contexts;
10+
11+
namespace Cpp2IL.Core.Utils.AsmResolver;
12+
13+
internal static class AsmResolverMethodFiller
14+
{
15+
public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext)
16+
{
17+
var managedAssembly = asmContext.GetExtraData<AssemblyDefinition>("AsmResolverAssembly") ?? throw new("AsmResolver assembly not found in assembly analysis context for " + asmContext);
18+
19+
var injectedRefHelperMethod = MakeRefHelper(managedAssembly.ManifestModule!);
20+
21+
foreach (var typeContext in asmContext.Types)
22+
{
23+
if (typeContext.Name == "<Module>")
24+
continue;
25+
26+
var managedType = typeContext.GetExtraData<TypeDefinition>("AsmResolverType") ?? throw new($"AsmResolver type not found in type analysis context for {typeContext.Definition?.FullName}");
27+
28+
#if !DEBUG
29+
try
30+
#endif
31+
{
32+
foreach (var methodCtx in typeContext.Methods)
33+
{
34+
var managedMethod = methodCtx.GetExtraData<MethodDefinition>("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {typeContext.Definition?.FullName}.{methodCtx.Definition?.Name}");
35+
36+
if (managedMethod.IsManagedMethodWithBody())
37+
FillMethodBodyWithStub(managedMethod, injectedRefHelperMethod);
38+
}
39+
}
40+
#if !DEBUG
41+
catch (Exception e)
42+
{
43+
throw new Exception($"Failed to process type {managedType.FullName} (module {managedType.Module?.Name}, declaring type {managedType.DeclaringType?.FullName}) in {asmContext.Definition.AssemblyName.Name}", e);
44+
}
45+
#endif
46+
}
47+
}
48+
49+
private static void AddDefaultValueForType(CilInstructionCollection instructions, TypeSignature type)
50+
{
51+
if (type is CorLibTypeSignature { ElementType: ElementType.Void })
52+
{
53+
}
54+
else if (type.IsValueType)
55+
{
56+
var variable = instructions.AddLocalVariable(type);
57+
instructions.Add(CilOpCodes.Ldloca, variable);
58+
instructions.Add(CilOpCodes.Initobj, type.ToTypeDefOrRef());
59+
instructions.Add(CilOpCodes.Ldloc, variable);
60+
}
61+
else
62+
{
63+
instructions.Add(CilOpCodes.Ldnull);
64+
}
65+
}
66+
67+
private static void FillMethodBodyWithStub(MethodDefinition methodDefinition, MethodDefinition injectedRefHelperMethod)
68+
{
69+
methodDefinition.CilMethodBody = new(methodDefinition);
70+
var methodInstructions = methodDefinition.CilMethodBody.Instructions;
71+
72+
if (methodDefinition.IsConstructor && !methodDefinition.IsStatic && !methodDefinition.DeclaringType!.IsValueType)
73+
{
74+
var baseConstructor = TryGetBaseConstructor(methodDefinition);
75+
if (baseConstructor is not null)
76+
{
77+
methodInstructions.Add(CilOpCodes.Ldarg_0);
78+
foreach (var baseParameter in baseConstructor.Parameters)
79+
{
80+
var importedBaseParameterType = methodDefinition.DeclaringType.Module!.DefaultImporter.ImportTypeSignatureIfNeeded(baseParameter.ParameterType);
81+
if (baseParameter.Definition is { IsOut: true })
82+
{
83+
var variable = methodInstructions.AddLocalVariable(importedBaseParameterType);
84+
methodInstructions.Add(CilOpCodes.Ldloca, variable);
85+
}
86+
else if (baseParameter.Definition is { IsIn: true })
87+
{
88+
var variable = methodInstructions.AddLocalVariable(importedBaseParameterType);
89+
if (importedBaseParameterType.IsValueType)
90+
{
91+
methodInstructions.Add(CilOpCodes.Ldloca, variable);
92+
methodInstructions.Add(CilOpCodes.Initobj, importedBaseParameterType.ToTypeDefOrRef());
93+
}
94+
else
95+
{
96+
methodInstructions.Add(CilOpCodes.Ldnull);
97+
methodInstructions.Add(CilOpCodes.Stloc, variable);
98+
}
99+
methodInstructions.Add(CilOpCodes.Ldloca, variable);
100+
}
101+
else if (importedBaseParameterType is ByReferenceTypeSignature byReferenceTypeSignature)
102+
{
103+
var referencedType = byReferenceTypeSignature.BaseType;
104+
var genericRefHelperInstance = injectedRefHelperMethod.DeclaringType!.MakeGenericInstanceType(referencedType);
105+
var memberReference = new MemberReference(genericRefHelperInstance.ToTypeDefOrRef(), injectedRefHelperMethod.Name, injectedRefHelperMethod.Signature);
106+
methodInstructions.Add(CilOpCodes.Call, memberReference);
107+
}
108+
else
109+
{
110+
AddDefaultValueForType(methodInstructions, importedBaseParameterType);
111+
}
112+
}
113+
methodInstructions.Add(CilOpCodes.Call, methodDefinition.DeclaringType.Module!.DefaultImporter.ImportMethod(baseConstructor));
114+
}
115+
}
116+
117+
foreach (var parameter in methodDefinition.Parameters)
118+
{
119+
if (parameter.Definition?.IsOut ?? false)
120+
{
121+
if (parameter.ParameterType.IsValueType)
122+
{
123+
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
124+
methodInstructions.Add(CilOpCodes.Initobj, parameter.ParameterType.ToTypeDefOrRef());
125+
}
126+
else
127+
{
128+
methodInstructions.Add(CilOpCodes.Ldarg, parameter);
129+
methodInstructions.Add(CilOpCodes.Ldnull);
130+
methodInstructions.Add(CilOpCodes.Stind_Ref);
131+
}
132+
}
133+
}
134+
AddDefaultValueForType(methodInstructions, methodDefinition.Signature!.ReturnType);
135+
methodInstructions.Add(CilOpCodes.Ret);
136+
methodInstructions.OptimizeMacros();
137+
}
138+
139+
private static MethodDefinition? TryGetBaseConstructor(MethodDefinition methodDefinition)
140+
{
141+
var declaringType = methodDefinition.DeclaringType!;
142+
var baseType = declaringType.BaseType?.Resolve();
143+
if (baseType is null)
144+
{
145+
return null;
146+
}
147+
else if (declaringType.Module == baseType.Module)
148+
{
149+
return baseType.Methods.FirstOrDefault(m => m.IsConstructor && !m.IsStatic && !m.IsPrivate);
150+
}
151+
else
152+
{
153+
return baseType.Methods.FirstOrDefault(m => m.IsConstructor && !m.IsStatic && (m.IsFamily || m.IsPublic));
154+
}
155+
}
156+
157+
private static MethodDefinition MakeRefHelper(ModuleDefinition module)
158+
{
159+
var staticClass = new TypeDefinition("Cpp2ILInjected", "RefHelper", TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
160+
module.TopLevelTypes.Add(staticClass);
161+
staticClass.GenericParameters.Add(new GenericParameter("T"));
162+
163+
var fieldType = new GenericParameterSignature(GenericParameterType.Type, 0);
164+
var fieldSignature = new FieldSignature(fieldType);
165+
var field = new FieldDefinition("backingField", FieldAttributes.Private | FieldAttributes.Static, fieldSignature);
166+
staticClass.Fields.Add(field);
167+
168+
var staticConstructorSignature = MethodSignature.CreateStatic(module.CorLibTypeFactory.Void);
169+
var staticConstructor = new MethodDefinition("..ctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RuntimeSpecialName, staticConstructorSignature);
170+
staticConstructor.CilMethodBody = new CilMethodBody(staticConstructor);
171+
var staticConstructorInstructions = staticConstructor.CilMethodBody.Instructions;
172+
staticConstructorInstructions.Add(CilOpCodes.Ldsflda, field);
173+
staticConstructorInstructions.Add(CilOpCodes.Initobj, fieldType.ToTypeDefOrRef());
174+
staticConstructorInstructions.Add(CilOpCodes.Ret);
175+
176+
var genericInstance = staticClass.MakeGenericInstanceType(fieldType);
177+
var memberReference = new MemberReference(genericInstance.ToTypeDefOrRef(), field.Name, field.Signature);
178+
179+
var methodSignature = MethodSignature.CreateStatic(new ByReferenceTypeSignature(fieldType));
180+
var method = new MethodDefinition("GetSharedReference", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, methodSignature);
181+
staticClass.Methods.Add(method);
182+
method.CilMethodBody = new CilMethodBody(method);
183+
var methodInstructions = method.CilMethodBody.Instructions;
184+
methodInstructions.Add(CilOpCodes.Ldsflda, memberReference);
185+
methodInstructions.Add(CilOpCodes.Ret);
186+
187+
return method;
188+
}
189+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using AsmResolver.DotNet.Code.Cil;
2+
using AsmResolver.DotNet.Signatures.Types;
3+
4+
namespace Cpp2IL.Core.Utils.AsmResolver;
5+
6+
internal static class CilInstructionCollectionExtensions
7+
{
8+
public static CilLocalVariable AddLocalVariable(this CilInstructionCollection instructions, TypeSignature variableType)
9+
{
10+
var variable = new CilLocalVariable(variableType);
11+
instructions.Owner.LocalVariables.Add(variable);
12+
return variable;
13+
}
14+
}

0 commit comments

Comments
 (0)