LILAC
Language to language Interop LAyer Compiler
Loading...
Searching...
No Matches
MethodExporter.cs
Go to the documentation of this file.
1using System.CodeDom.Compiler;
2using System.Text;
3using System.Xml.Linq;
4using Microsoft.CodeAnalysis;
5
7
8public class MethodExporter(IMethodSymbol symbol) : IExporter
9{
10 private string GetMangling()
11 {
12 return $"__interop_{symbol.GetUnmanagedMethodName()}";
13 }
14
15 public void GenerateUnmanagedCode(IndentedTextWriter source, IndentedTextWriter header)
16 {
17 // Emit parameter pack definition
18 var argsPack = new ParameterPack(symbol);
19 argsPack.GenerateUnmanagedStub(header);
20 header.WriteLine();
21
22 // Emit method declaration
23 var sb = new StringBuilder();
24 sb.Append(symbol.ReturnType.GetNativeName()).Append(' ');
25 var namespaceOffset = sb.Length;
26
27 sb.Append(symbol.GetUnmanagedMethodName()).Append('(');
28 for (var i = 0; i < symbol.Parameters.Length; i++)
29 {
30 var parameter = symbol.Parameters[i];
31 if (i > 0)
32 sb.Append(", ");
33 sb.Append($"{parameter.Type.GetNativeName()} {parameter.Name}");
34 }
35
36 sb.Append(");");
37 header.WriteLine(sb.ToString());
38
39 // Emit method definition
40 sb.Insert(namespaceOffset, $"{symbol.ContainingType.GetNativeName()}::");
41 sb.Remove(sb.Length - 1, 1);
42 source.WriteLine(sb.ToString());
43
44 source.WriteLine("{");
45
46 source.Indent++;
47
48 // Pack arguments into parameter pack
49 sb.Clear();
50 sb.Append($"{argsPack.Name} __argpack(");
51 if (!symbol.IsStatic)
52 {
53 sb.Append("__this");
54 if (symbol.Parameters.Any())
55 sb.Append(", ");
56 }
57 for (var i = 0; i < symbol.Parameters.Length; i++)
58 {
59 var parameter = symbol.Parameters[i];
60 if (i > 0)
61 sb.Append(", ");
62 sb.Append($"{parameter.Name}");
63 }
64 sb.AppendLine(");");
65 source.WriteLine(sb.ToString());
66
67 // Inquire fp for mehtod
68 source.WriteLine("int (*fp)(void*, std::int32_t) = reinterpret_cast<decltype(fp)>(g_dhost->LoadMethod(");
69 source.Indent++;
70 source.WriteLine($"\"{symbol.ContainingType.GetAssemblyQualifiedName()}\",");
71 source.WriteLine($"\"{GetMangling()}\"));");
72 source.Indent--;
73
74 source.WriteLine();
75 source.WriteLine("fp(&__argpack, sizeof(__argpack));");
76 if (symbol.Name == ".ctor")
77 source.WriteLine("__this = __argpack.__this;");
78 if (!symbol.ReturnsVoid)
79 source.WriteLine("return __argpack.__return;");
80
81 source.Indent--;
82 source.WriteLine("}");
83 }
84
85 public void GenerateManagedCode(IndentedTextWriter builder)
86 {
87 var argsPack = new ParameterPack(symbol);
88 argsPack.GenerateManagedStub(builder);
89 builder.WriteLine();
90
91 builder.WriteLine("[System.Runtime.InteropServices.UnmanagedCallersOnly]");
92 builder.WriteLine($"public static unsafe int {GetMangling()}({argsPack.Name}* argpack, int size)");
93 builder.WriteLine("{");
94 builder.Indent++;
95
96 if (symbol.Name == ".ctor")
97 {
98 var args = string.Join(", ", symbol.Parameters.Select(parameter => $"argpack->{parameter.Name}"));
99 builder.WriteLine($"var obj = new {symbol.ContainingType.Name}({args})");
100 builder.WriteLine("var handle = System.Runtime.InteropServices.GCHandle.Alloc(obj, System.Runtime.InteropServices.GCHandleType.Pinned);");
101 builder.WriteLine("argpack->__this = handle.AddrOfPinnedObject();");
102 }
103 else
104 {
105 var args = string.Join(", ", symbol.Parameters.Select(parameter => $"argpack->{parameter.Name}"));
106 builder.WriteLine("var handle = System.Runtime.InteropServices.GCHandle.FromIntPtr(argpack->__this);");
107 builder.WriteLine($"argpack->__return = (({symbol.ContainingType.Name})handle.Target).{symbol.Name}({args});");
108 }
109
110 builder.WriteLine("return 0;");
111
112 builder.Indent--;
113 builder.WriteLine("}");
114 }
115}