Skip to content

Commit d89f9ec

Browse files
committed
Add awaiter implementation
1 parent 45e22c2 commit d89f9ec

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
4+
using System.Text;
5+
using Il2CppInterop.Generator.Contexts;
6+
using Il2CppInterop.Generator.Utils;
7+
using Mono.Cecil;
8+
using Mono.Cecil.Cil;
9+
10+
namespace Il2CppInterop.Generator.Passes;
11+
12+
internal class Pass61ImplementAwaiters
13+
{
14+
public static void DoPass(RewriteGlobalContext context)
15+
{
16+
var corlib = context.GetAssemblyByName("mscorlib");
17+
var actionUntyped = corlib.GetTypeByName("System.Action");
18+
19+
var actionConversionUntyped = actionUntyped.NewType.Methods.FirstOrDefault(m => m.Name == "op_Implicit") ?? throw new MissingMethodException("Untyped action conversion");
20+
21+
foreach (var assemblyContext in context.Assemblies)
22+
{
23+
// dont actually import the references until they're needed
24+
Lazy<TypeReference> actionUntypedRef = new(() => assemblyContext.NewAssembly.MainModule.ImportReference(actionUntyped.OriginalType));
25+
Lazy<MethodReference> actionConversionUntypedRef = new(() => assemblyContext.NewAssembly.MainModule.ImportReference(actionConversionUntyped));
26+
Lazy<TypeReference> notifyCompletionRef = new(() => assemblyContext.NewAssembly.MainModule.ImportReference(typeof(INotifyCompletion)));
27+
var voidRef = assemblyContext.Imports.Module.Void();
28+
foreach (var typeContext in assemblyContext.Types)
29+
{
30+
var interfaceImplementation = typeContext.OriginalType.Interfaces.FirstOrDefault(InterfaceImplementation => InterfaceImplementation.InterfaceType.Name == nameof(INotifyCompletion));
31+
if (interfaceImplementation is null)
32+
continue;
33+
34+
var isGeneric = typeContext.OriginalType.ContainsGenericParameter;
35+
36+
var awaiterType = typeContext.OriginalType;
37+
38+
var originalOnComplete = typeContext.TryGetMethodByName(nameof(INotifyCompletion.OnCompleted)) ?? throw new MissingMethodException("Original OnComplete");
39+
40+
var onCompletedAttr = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot;
41+
var onComplete = new MethodDefinition(nameof(INotifyCompletion.OnCompleted), onCompletedAttr, voidRef);
42+
typeContext.NewType.Interfaces.Add(new(notifyCompletionRef.Value));
43+
typeContext.NewType.Methods.Add(onComplete);
44+
45+
onComplete.Parameters.Add(new ParameterDefinition("continuation", ParameterAttributes.None, actionUntypedRef.Value));
46+
47+
var onCompleteIl = onComplete.Body.GetILProcessor();
48+
49+
onCompleteIl.Emit(OpCodes.Nop);
50+
onCompleteIl.Emit(OpCodes.Ldarg_0);
51+
onCompleteIl.Emit(OpCodes.Ldarg_1); // ldarg1 bc not static, so ldarg0 is this & ldarg1 is the parameter
52+
onCompleteIl.Emit(OpCodes.Call, actionConversionUntypedRef.Value);
53+
onCompleteIl.Emit(OpCodes.Call, originalOnComplete.NewMethod);
54+
onCompleteIl.Emit(OpCodes.Nop);
55+
onCompleteIl.Emit(OpCodes.Ret);
56+
}
57+
}
58+
}
59+
}

Il2CppInterop.Generator/Runners/InteropAssemblyGenerator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ public void Run(GeneratorOptions options)
151151
Pass60AddImplicitConversions.DoPass(rewriteContext);
152152
}
153153

154+
using (new TimingCookie("Implementing awaiters"))
155+
{
156+
Pass61ImplementAwaiters.DoPass(rewriteContext);
157+
}
158+
154159
using (new TimingCookie("Creating properties"))
155160
{
156161
Pass70GenerateProperties.DoPass(rewriteContext);

0 commit comments

Comments
 (0)