[static registrar] Implement support for calling the generated UnmanagedCallersOnly method from the managed static registrar

This commit is contained in:
Git History Editor 2023-05-05 19:16:11 +02:00 коммит произвёл Rolf Bjarne Kvinge
Родитель 382ebae8d5
Коммит 9bcc96e171
1 изменённых файлов: 109 добавлений и 0 удалений

Просмотреть файл

@ -4031,6 +4031,14 @@ namespace Registrar {
nslog_start.AppendLine (");");
}
#if NET
// Generate the native trampoline to call the generated UnmanagedCallersOnly method if we're using the managed static registrar.
if (LinkContext.App.Registrar == RegistrarMode.ManagedStatic) {
GenerateCallToUnmanagedCallersOnlyMethod (sb, method, isCtor, isVoid, num_arg, descriptiveMethodName, exceptions);
return;
}
#endif
if (!TryCreateTokenReference (method.Method, TokenType.Method, out var token_ref, exceptions))
return;
@ -4261,6 +4269,107 @@ namespace Registrar {
}
}
#if NET
void GenerateCallToUnmanagedCallersOnlyMethod (AutoIndentStringBuilder sb, ObjCMethod method, bool isCtor, bool isVoid, int num_arg, string descriptiveMethodName, List<Exception> exceptions)
{
// Generate the native trampoline to call the generated UnmanagedCallersOnly method.
// We try to do as little as possible in here, and instead do the work in managed code.
// If we're AOT-compiled, we don't need to look for the UnmanagedCallersOnly method,
// we can just call the corresponding entry point directly. Otherwise we'll have to
// call into managed code to find the function pointer for the UnmanagedCallersOnly
// method (we store the result in a static variable, so that we only do this once
// per method, the first time it's called).
var staticCall = App.IsAOTCompiled (method.DeclaringType.Type.Module.Assembly.Name.Name);
if (!App.Configuration.AssemblyTrampolineInfos.TryFindInfo (method.Method, out var pinvokeMethodInfo)) {
exceptions.Add (ErrorHelper.CreateError (99, "Could not find the managed callback for {0}", descriptiveMethodName));
return;
}
var ucoEntryPoint = pinvokeMethodInfo.UnmanagedCallersOnlyEntryPoint;
sb.AppendLine ();
if (!staticCall)
sb.Append ("typedef ");
var callbackReturnType = string.Empty;
var hasReturnType = true;
if (isCtor) {
callbackReturnType = "id";
} else if (isVoid) {
callbackReturnType = "void";
hasReturnType = false;
} else {
callbackReturnType = ToObjCParameterType (method.NativeReturnType, descriptiveMethodName, exceptions, method.Method);
}
sb.Append (callbackReturnType);
sb.Append (" ");
if (staticCall) {
sb.Append (ucoEntryPoint);
} else {
sb.Append ("(*");
sb.Append (ucoEntryPoint);
sb.Append ("_function)");
}
sb.Append (" (id self, SEL sel");
var indexOffset = method.IsCategoryInstance ? 1 : 0;
for (var i = indexOffset; i < num_arg; i++) {
sb.Append (", ");
var parameterType = ToObjCParameterType (method.NativeParameters [i], method.DescriptiveMethodName, exceptions, method.Method, delegateToBlockType: true, cSyntaxForBlocks: true);
var containsBlock = parameterType.Contains ("%PARAMETERNAME%");
parameterType = parameterType.Replace ("%PARAMETERNAME%", $"p{i - indexOffset}");
sb.Append (parameterType);
if (!containsBlock) {
sb.Append (" ");
sb.AppendFormat ("p{0}", i - indexOffset);
}
}
if (isCtor)
sb.Append (", bool* call_super");
sb.Append (", GCHandle* exception_gchandle");
if (method.IsVariadic)
sb.Append (", ...");
sb.Append (");");
sb.WriteLine ();
sb.WriteLine (GetObjCSignature (method, exceptions));
sb.WriteLine ("{");
sb.WriteLine ("GCHandle exception_gchandle = INVALID_GCHANDLE;");
if (isCtor)
sb.WriteLine ($"bool call_super = false;");
if (hasReturnType)
sb.WriteLine ($"{callbackReturnType} rv = {{ 0 }};");
if (!staticCall) {
sb.WriteLine ($"static {ucoEntryPoint}_function {ucoEntryPoint};");
sb.WriteLine ($"xamarin_registrar_dlsym ((void **) &{ucoEntryPoint}, \"{method.Method.Module.Assembly.Name.Name}\", \"{ucoEntryPoint}\", {pinvokeMethodInfo.Id});");
}
if (hasReturnType)
sb.Write ("rv = ");
sb.Write (ucoEntryPoint);
sb.Write (" (self, _cmd");
for (var i = indexOffset; i < num_arg; i++) {
sb.AppendFormat (", p{0}", i - indexOffset);
}
if (isCtor)
sb.Write (", &call_super");
sb.Write (", &exception_gchandle");
sb.WriteLine (");");
sb.WriteLine ("xamarin_process_managed_exception_gchandle (exception_gchandle);");
if (isCtor) {
GenerateCallToSuperForConstructor (sb, method, exceptions);
}
if (hasReturnType)
sb.WriteLine ("return rv;");
sb.WriteLine ("}");
}
#endif
void SpecializePrepareReturnValue (AutoIndentStringBuilder sb, ObjCMethod method, string descriptiveMethodName, string rettype, List<Exception> exceptions)
{
var returntype = method.ReturnType;