From f958c1b5b1c521cc5084221bcb8a3ce957e49d67 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 13 Jul 2022 11:47:55 +0200 Subject: [PATCH 1/3] [static registrar] Handle metadata token lookup failure gracefully. Change the static registrar to fail gracefully if it can't compute a metadata token for a given metadata item, and instead fall back to doing the lookup of whatever we need at runtime. This is a step towards making per-assembly static registrar working. Ref: https://github.com/xamarin/xamarin-macios/issues/12067. --- tools/common/StaticRegistrar.cs | 123 +++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 41 deletions(-) diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 9fa0fb221c35..6e0c264b88fb 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -213,6 +213,7 @@ public override string ToString () class StaticRegistrar : Registrar { static string NFloatTypeName { get => Driver.IsDotNet ? "System.Runtime.InteropServices.NFloat" : "System.nfloat"; } + const uint INVALID_TOKEN_REF = 0xFFFFFFFF; Dictionary protocol_member_method_map; @@ -2877,10 +2878,11 @@ void Specialize (AutoIndentStringBuilder sb, out string initialization_method) flags |= MTTypeFlags.UserType; CheckNamespace (@class, exceptions); - token_ref = CreateTokenReference (@class.Type, TokenType.TypeDef); + if (!TryCreateTokenReference (@class.Type, TokenType.TypeDef, out token_ref, exceptions)) + continue; map.AppendLine ("{{ NULL, 0x{1:X} /* #{3} '{0}' => '{2}' */, (MTTypeFlags) ({4}) /* {5} */ }},", @class.ExportedName, - CreateTokenReference (@class.Type, TokenType.TypeDef), + token_ref, GetAssemblyQualifiedName (@class.Type), map_entries, (int) flags, flags); map_dict [@class] = map_entries++; @@ -2919,9 +2921,11 @@ void Specialize (AutoIndentStringBuilder sb, out string initialization_method) if (@class.IsProtocol && @class.ProtocolWrapperType != null) { - if (token_ref == uint.MaxValue) - token_ref = CreateTokenReference (@class.Type, TokenType.TypeDef); - protocol_wrapper_map.Add (token_ref, new Tuple (@class, CreateTokenReference (@class.ProtocolWrapperType, TokenType.TypeDef))); + if (token_ref == INVALID_TOKEN_REF && !TryCreateTokenReference (@class.Type, TokenType.TypeDef, out token_ref, exceptions)) + continue; + if (!TryCreateTokenReference (@class.ProtocolWrapperType, TokenType.TypeDef, out var protocol_wrapper_type_ref, exceptions)) + continue; + protocol_wrapper_map.Add (token_ref, new Tuple (@class, protocol_wrapper_type_ref)); if (needs_protocol_map || TryGetAttribute (@class.Type, "Foundation", "XpcInterfaceAttribute", out var xpcAttr)) { protocols.Add (new ProtocolInfo { TokenReference = token_ref, Protocol = @class }); CheckNamespace (@class, exceptions); @@ -3148,8 +3152,12 @@ void Specialize (AutoIndentStringBuilder sb, out string initialization_method) if (skipped_types.Count > 0) { map.AppendLine ("static const MTManagedClassMap __xamarin_skipped_map [] = {"); foreach (var skipped in skipped_types) { - skipped.SkippedTokenReference = CreateTokenReference (skipped.Skipped, TokenType.TypeDef); - skipped.ActualTokenReference = CreateTokenReference (skipped.Actual.Type, TokenType.TypeDef); + if (!TryCreateTokenReference (skipped.Skipped, TokenType.TypeDef, out var skipped_ref, exceptions)) + continue; + if (!TryCreateTokenReference (skipped.Actual.Type, TokenType.TypeDef, out var actual_ref, exceptions)) + continue; + skipped.SkippedTokenReference = skipped_ref; + skipped.ActualTokenReference = actual_ref; } foreach (var skipped in skipped_types.OrderBy ((v) => v.SkippedTokenReference)) @@ -3457,7 +3465,8 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List setup_return.Indentation = indent; cleanup.Indentation = indent; - var token_ref = CreateTokenReference (method.Method, TokenType.Method); + if (!TryCreateTokenReference (method.Method, TokenType.Method, out var token_ref, exceptions)) + return; // A comment describing the managed signature if (trace) { @@ -3764,9 +3773,13 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List setup_call_stack.AppendLine ("paramtype{0} = xamarin_get_parameter_type (managed_method, {0});", i); if (isNativeObjectInterface) { var resolvedElementType = ResolveType (elementType); - var iface_token_ref = $"0x{CreateTokenReference (resolvedElementType, TokenType.TypeDef):X} /* {resolvedElementType} */ "; - var implementation_token_ref = $"0x{CreateTokenReference (nativeObjType, TokenType.TypeDef):X} /* {nativeObjType} */ "; - setup_call_stack.AppendLine ("marr{0} = xamarin_nsarray_to_managed_inativeobject_array_static (arr{0}, paramtype{0}, NULL, {1}, {2}, &exception_gchandle);", i, iface_token_ref, implementation_token_ref); + if (TryCreateTokenReference (resolvedElementType, TokenType.TypeDef, out var iface_token_ref, out _) && TryCreateTokenReference (nativeObjType, TokenType.TypeDef, out var implementation_token_ref, out _)) { + var iface_token_ref_str = $"0x{iface_token_ref:X} /* {resolvedElementType} */ "; + var implementation_token_ref_str = $"0x{implementation_token_ref:X} /* {nativeObjType} */ "; + setup_call_stack.AppendLine ("marr{0} = xamarin_nsarray_to_managed_inativeobject_array_static (arr{0}, paramtype{0}, NULL, {1}, {2}, &exception_gchandle);", i, iface_token_ref_str, implementation_token_ref_str); + } else { + setup_call_stack.AppendLine ("marr{0} = xamarin_nsarray_to_managed_inativeobject_array (arr{0}, paramtype{0}, NULL, &exception_gchandle);", i); + } } else { setup_call_stack.AppendLine ("marr{0} = xamarin_nsarray_to_managed_inativeobject_array (arr{0}, paramtype{0}, NULL, &exception_gchandle);", i); } @@ -3883,20 +3896,29 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List if (!HasIntPtrBoolCtor (nativeObjType, exceptions)) throw ErrorHelper.CreateError (4103, Errors.MT4103, nativeObjType.FullName, descriptiveMethodName); + var findMonoClass = false; + var tdTokenRef = INVALID_TOKEN_REF; + var nativeObjectTypeTokenRef = INVALID_TOKEN_REF; if (!td.IsInterface) { + findMonoClass = true; + } else if (!(isRef && isOut) && (!TryCreateTokenReference (td, TokenType.TypeDef, out tdTokenRef, out _) || !TryCreateTokenReference (nativeObjType, TokenType.TypeDef, out nativeObjectTypeTokenRef, out _))) { + findMonoClass = true; + } + if (findMonoClass) { // find the MonoClass for this parameter body_setup.AppendLine ("MonoType *type{0};", i); cleanup.AppendLine ("xamarin_mono_object_release (&type{0});", i); setup_call_stack.AppendLine ("type{0} = xamarin_get_parameter_type (managed_method, {0});", i); } + body_setup.AppendLine ("MonoObject *inobj{0} = NULL;", i); cleanup.AppendLine ($"xamarin_mono_object_release (&inobj{i});"); if (isRef) { if (isOut) { // Do nothing - } else if (td.IsInterface) { - setup_call_stack.AppendLine ("inobj{0} = xamarin_get_inative_object_static (*p{0}, false, 0x{1:X} /* {2} */, 0x{3:X} /* {4} */, &exception_gchandle);", i, CreateTokenReference (td, TokenType.TypeDef), td.FullName, CreateTokenReference (nativeObjType, TokenType.TypeDef), nativeObjType.FullName); + } else if (td.IsInterface && TryCreateTokenReference (td, TokenType.TypeDef, out var iface_ref, out _) && TryCreateTokenReference (nativeObjType, TokenType.TypeDef, out var objctype_ref, out _)) { + setup_call_stack.AppendLine ("inobj{0} = xamarin_get_inative_object_static (*p{0}, false, 0x{1:X} /* {2} */, 0x{3:X} /* {4} */, &exception_gchandle);", i, iface_ref, td.FullName, objctype_ref, nativeObjType.FullName); setup_call_stack.AppendLine ("if (exception_gchandle != INVALID_GCHANDLE) goto exception_handling;"); } else { body_setup.AppendLine ("MonoReflectionType *reflectiontype{0} = NULL;", i); @@ -3917,8 +3939,8 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List copyback.AppendLine ("}"); copyback.AppendLine ("*p{0} = (id) handle{0};", i); } else { - if (td.IsInterface) { - setup_call_stack.AppendLine ("inobj{0} = xamarin_get_inative_object_static (p{0}, false, 0x{1:X} /* {2} */, 0x{3:X} /* {4} */, &exception_gchandle);", i, CreateTokenReference (td, TokenType.TypeDef), td.FullName, CreateTokenReference (nativeObjType, TokenType.TypeDef), nativeObjType.FullName); + if (td.IsInterface && tdTokenRef != INVALID_TOKEN_REF && nativeObjectTypeTokenRef != INVALID_TOKEN_REF) { + setup_call_stack.AppendLine ($"inobj{i} = xamarin_get_inative_object_static (p{i}, false, 0x{tdTokenRef:X} /* {td.FullName} */, 0x{nativeObjectTypeTokenRef:X} /* {nativeObjType.FullName} */, &exception_gchandle);"); } else { body_setup.AppendLine ("MonoReflectionType *reflectiontype{0} = NULL;", i); cleanup.AppendLine ("xamarin_mono_object_release (&reflectiontype{0});", i); @@ -3945,10 +3967,10 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List var token = "INVALID_TOKEN_REF"; if (App.Optimizations.StaticBlockToDelegateLookup == true) { var creatorMethod = GetBlockWrapperCreator (method, i); - if (creatorMethod != null) { - token = $"0x{CreateTokenReference (creatorMethod, TokenType.Method):X} /* {creatorMethod.FullName} */ "; - } else { + if (creatorMethod is null) { exceptions.Add (ErrorHelper.CreateWarning (App, 4174, method.Method, Errors.MT4174, method.DescriptiveMethodName, i + 1)); + } else if (TryCreateTokenReference (creatorMethod, TokenType.Method, out var creator_method_token_ref, out _)) { + token = $"0x{creator_method_token_ref:X} /* {creatorMethod.FullName} */ "; } } body_setup.AppendLine ("MonoObject *del{0} = NULL;", i); @@ -4107,10 +4129,10 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List } } var delegateProxyType = GetDelegateProxyType (method); - if (delegateProxyType != null) { - token = $"0x{CreateTokenReference (delegateProxyType, TokenType.TypeDef):X} /* {delegateProxyType.FullName} */ "; - } else { + if (delegateProxyType is null) { exceptions.Add (ErrorHelper.CreateWarning (App, 4176, method.Method, "Unable to locate the delegate to block conversion type for the return value of the method {0}.", method.DescriptiveMethodName)); + } else if (TryCreateTokenReference (delegateProxyType, TokenType.TypeDef, out var delegate_proxy_type_token_ref, out _)) { + token = $"0x{delegate_proxy_type_token_ref:X} /* {delegateProxyType.FullName} */ "; } } setup_return.AppendLine ("res = xamarin_get_block_for_delegate (managed_method, retval, {0}, {1}, &exception_gchandle);", signature, token); @@ -4739,8 +4761,8 @@ void GenerateConversionToManaged (TypeReference inputType, TypeReference outputT // method linked away!? this should already be verified ErrorHelper.Show (ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); token = "INVALID_TOKEN_REF"; - } else { - token = $"0x{CreateTokenReference (getValueMethod, TokenType.Method):X} /* {getValueMethod.FullName} */"; + } else if (TryCreateTokenReference (getValueMethod, TokenType.Method, out var get_value_method_token_ref, out _)) { + token = $"0x{get_value_method_token_ref:X} /* {getValueMethod.FullName} */"; } } else { throw ErrorHelper.CreateError (99, Errors.MX0099, $"can't convert from '{inputType.FullName}' to '{outputType.FullName}' in {descriptiveMethodName}"); @@ -4833,8 +4855,8 @@ void GenerateConversionToNative (TypeReference inputType, TypeReference outputTy // method linked away!? this should already be verified ErrorHelper.Show (ErrorHelper.CreateWarning (99, Errors.MX0099, $"the smart enum {underlyingManagedType.FullName} doesn't seem to be a smart enum after all")); token = "INVALID_TOKEN_REF"; - } else { - token = $"0x{CreateTokenReference (getConstantMethod, TokenType.Method):X} /* {getConstantMethod.FullName} */"; + } else if (TryCreateTokenReference (getConstantMethod, TokenType.Method, out var get_constant_method_token_ref, out _)) { + token = $"0x{get_constant_method_token_ref:X} /* {getConstantMethod.FullName} */"; } } else { throw ErrorHelper.CreateError (99, Errors.MX0099, $"can't convert from '{inputType.FullName}' to '{outputType.FullName}' in {descriptiveMethodName}"); @@ -4873,59 +4895,78 @@ public override bool Equals (object obj) } } - uint CreateFullTokenReference (MemberReference member) + bool TryCreateFullTokenReference (MemberReference member, out uint token_ref, out Exception exception) { - var rv = (full_token_reference_count++ << 1) + 1; + token_ref = (full_token_reference_count++ << 1) + 1; switch (member.MetadataToken.TokenType) { case TokenType.TypeDef: case TokenType.Method: break; // OK default: - throw ErrorHelper.CreateError (99, Errors.MX0099, $"unsupported tokentype ({member.MetadataToken.TokenType}) for {member.FullName}"); + exception = ErrorHelper.CreateError (99, Errors.MX0099, $"unsupported tokentype ({member.MetadataToken.TokenType}) for {member.FullName}"); + return false; } var assemblyIndex = registered_assemblies.FindIndex (v => v.Assembly == member.Module.Assembly); + if (assemblyIndex == -1) { + exception = ErrorHelper.CreateError (99, Errors.MX0099, $"Could not find {member.Module.Assembly.Name.Name} in the list of registered assemblies when processing {member.FullName}:\n\t{string.Join ("\n\t", registered_assemblies.Select (v => v.Assembly.Name.Name))}"); + return false; + } var assemblyName = registered_assemblies [assemblyIndex].Name; var moduleToken = member.Module.MetadataToken.ToUInt32 (); var moduleName = member.Module.Name; var memberToken = member.MetadataToken.ToUInt32 (); var memberName = member.FullName; - full_token_references.Append ($"\t\t{{ /* #{full_token_reference_count} = 0x{rv:X} */ {assemblyIndex} /* {assemblyName} */, 0x{moduleToken:X} /* {moduleName} */, 0x{memberToken:X} /* {memberName} */ }},\n"); - return rv; + exception = null; + full_token_references.Append ($"\t\t{{ /* #{full_token_reference_count} = 0x{token_ref:X} */ {assemblyIndex} /* {assemblyName} */, 0x{moduleToken:X} /* {moduleName} */, 0x{memberToken:X} /* {memberName} */ }},\n"); + return true; } Dictionary, uint> token_ref_cache = new Dictionary, uint> (); - uint CreateTokenReference (MemberReference member, TokenType implied_type) + bool TryCreateTokenReference (MemberReference member, TokenType implied_type, out uint token_ref, List exceptions) { - var key = new Tuple (member, implied_type); - uint rv; - if (!token_ref_cache.TryGetValue (key, out rv)) - token_ref_cache [key] = rv = CreateTokenReference2 (member, implied_type); + var rv = TryCreateTokenReference (member, implied_type, out token_ref, out var ex); + if (!rv) + exceptions.Add (ex); return rv; } - uint CreateTokenReference2 (MemberReference member, TokenType implied_type) + bool TryCreateTokenReference (MemberReference member, TokenType implied_type, out uint token_ref, out Exception exception) + { + var key = new Tuple (member, implied_type); + exception = null; + if (!token_ref_cache.TryGetValue (key, out token_ref)) { + if (!TryCreateTokenReferenceUncached (member, implied_type, out token_ref, out exception)) + return false; + token_ref_cache [key] = token_ref; + } + return true; + } + + bool TryCreateTokenReferenceUncached (MemberReference member, TokenType implied_type, out uint token_ref, out Exception exception) { var token = member.MetadataToken; /* We can't create small token references if we're in partial mode, because we may have multiple arrays of registered assemblies, and no way of saying which one we refer to with the assembly index */ if (IsSingleAssembly) - return CreateFullTokenReference (member); + return TryCreateFullTokenReference (member, out token_ref, out exception); /* If the implied token type doesn't match, we need a full token */ if (implied_type != token.TokenType) - return CreateFullTokenReference (member); + return TryCreateFullTokenReference (member, out token_ref, out exception); /* For small token references the only valid module is the first one */ if (member.Module.MetadataToken.ToInt32 () != 1) - return CreateFullTokenReference (member); + return TryCreateFullTokenReference (member, out token_ref, out exception); /* The assembly must be a registered one, and only within the first 128 assemblies */ var assembly_name = GetAssemblyName (member.Module.Assembly); var index = registered_assemblies.FindIndex (v => v.Name == assembly_name); if (index < 0 || index > 127) - return CreateFullTokenReference (member); + return TryCreateFullTokenReference (member, out token_ref, out exception); - return (token.RID << 8) + ((uint) index << 1); + token_ref = (token.RID << 8) + ((uint) index << 1); + exception = null; + return true; } public void GeneratePInvokeWrappersStart (AutoIndentStringBuilder hdr, AutoIndentStringBuilder decls, AutoIndentStringBuilder mthds, AutoIndentStringBuilder ifaces) From 365fe4d9f5ec32094bd026e731d6f4da494ed6d8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Mon, 14 Nov 2022 19:09:34 +0000 Subject: [PATCH 2/3] Auto-format source code --- tools/common/StaticRegistrar.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 6e0c264b88fb..22a7b1f6ab35 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -3969,7 +3969,7 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List var creatorMethod = GetBlockWrapperCreator (method, i); if (creatorMethod is null) { exceptions.Add (ErrorHelper.CreateWarning (App, 4174, method.Method, Errors.MT4174, method.DescriptiveMethodName, i + 1)); - } else if (TryCreateTokenReference (creatorMethod, TokenType.Method, out var creator_method_token_ref, out _)) { + } else if (TryCreateTokenReference (creatorMethod, TokenType.Method, out var creator_method_token_ref, out _)) { token = $"0x{creator_method_token_ref:X} /* {creatorMethod.FullName} */ "; } } @@ -4131,7 +4131,7 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List var delegateProxyType = GetDelegateProxyType (method); if (delegateProxyType is null) { exceptions.Add (ErrorHelper.CreateWarning (App, 4176, method.Method, "Unable to locate the delegate to block conversion type for the return value of the method {0}.", method.DescriptiveMethodName)); - } else if (TryCreateTokenReference (delegateProxyType, TokenType.TypeDef, out var delegate_proxy_type_token_ref, out _)) { + } else if (TryCreateTokenReference (delegateProxyType, TokenType.TypeDef, out var delegate_proxy_type_token_ref, out _)) { token = $"0x{delegate_proxy_type_token_ref:X} /* {delegateProxyType.FullName} */ "; } } From 979918ea72f8db5b991660eadebf70f633c7af62 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Mon, 14 Nov 2022 20:38:14 +0100 Subject: [PATCH 3/3] Reduce code duplication a bit. --- tools/common/StaticRegistrar.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 22a7b1f6ab35..e904d9392e6c 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -3917,8 +3917,8 @@ void Specialize (AutoIndentStringBuilder sb, ObjCMethod method, List if (isRef) { if (isOut) { // Do nothing - } else if (td.IsInterface && TryCreateTokenReference (td, TokenType.TypeDef, out var iface_ref, out _) && TryCreateTokenReference (nativeObjType, TokenType.TypeDef, out var objctype_ref, out _)) { - setup_call_stack.AppendLine ("inobj{0} = xamarin_get_inative_object_static (*p{0}, false, 0x{1:X} /* {2} */, 0x{3:X} /* {4} */, &exception_gchandle);", i, iface_ref, td.FullName, objctype_ref, nativeObjType.FullName); + } else if (td.IsInterface && tdTokenRef != INVALID_TOKEN_REF && nativeObjectTypeTokenRef != INVALID_TOKEN_REF) { + setup_call_stack.AppendLine ("inobj{0} = xamarin_get_inative_object_static (*p{0}, false, 0x{1:X} /* {2} */, 0x{3:X} /* {4} */, &exception_gchandle);", i, tdTokenRef, td.FullName, nativeObjectTypeTokenRef, nativeObjType.FullName); setup_call_stack.AppendLine ("if (exception_gchandle != INVALID_GCHANDLE) goto exception_handling;"); } else { body_setup.AppendLine ("MonoReflectionType *reflectiontype{0} = NULL;", i);