Skip to content

Commit

Permalink
[registrar] Call INativeObject ctors directly in the managed static r…
Browse files Browse the repository at this point in the history
…egistrar. (#18706)

We can determine the exact constructor to call when creating
INativeObject instances in the generated code, so do exactly that.
This avoids a lot of slow reflection, and also makes the constructor
call visible for any linkers.
  • Loading branch information
rolfbjarne authored Aug 14, 2023
1 parent cb1ffa0 commit f24a016
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 21 deletions.
14 changes: 13 additions & 1 deletion tools/common/StaticRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3309,6 +3309,12 @@ void Specialize (AutoIndentStringBuilder sb, out string initialization_method)

bool HasIntPtrBoolCtor (TypeDefinition type, List<Exception> exceptions)
{
return HasIntPtrBoolCtor (type, exceptions, out var _);
}

bool HasIntPtrBoolCtor (TypeDefinition type, List<Exception> exceptions, [NotNullWhen (true)] out MethodDefinition? ctor)
{
ctor = null;
if (!type.HasMethods)
return false;
foreach (var method in type.Methods) {
Expand All @@ -3330,6 +3336,7 @@ bool HasIntPtrBoolCtor (TypeDefinition type, List<Exception> exceptions)
if (!method.Parameters [0].ParameterType.Is ("System", "IntPtr"))
continue;
}
ctor = method;
return true;
}
return false;
Expand Down Expand Up @@ -4528,6 +4535,11 @@ void GenerateCallToSuperForConstructor (AutoIndentStringBuilder sb, ObjCMethod m
}

public TypeDefinition GetInstantiableType (TypeDefinition td, List<Exception> exceptions, string descriptiveMethodName)
{
return GetInstantiableType (td, exceptions, descriptiveMethodName, out var _);
}

public TypeDefinition GetInstantiableType (TypeDefinition td, List<Exception> exceptions, string descriptiveMethodName, out MethodDefinition ctor)
{
TypeDefinition nativeObjType = td;

Expand All @@ -4540,7 +4552,7 @@ public TypeDefinition GetInstantiableType (TypeDefinition td, List<Exception> ex
}

// verify that the type has a ctor with two parameters
if (!HasIntPtrBoolCtor (nativeObjType, exceptions))
if (!HasIntPtrBoolCtor (nativeObjType, exceptions, out ctor))
throw ErrorHelper.CreateError (4103, Errors.MT4103, nativeObjType.FullName, descriptiveMethodName);

return nativeObjType;
Expand Down
30 changes: 17 additions & 13 deletions tools/dotnet-linker/AppBundleRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ public TypeReference System_IntPtr {
}
}

public FieldReference System_IntPtr_Zero {
get {
return GetFieldReference (CorlibAssembly, System_IntPtr, "Zero", "System.IntPtr::Zero", out var _);
}
}

public TypeReference System_Nullable_1 {
get {
return GetTypeReference (CorlibAssembly, "System.Nullable`1", out var _);
Expand Down Expand Up @@ -779,6 +785,16 @@ public MethodReference Runtime_HasNSObject {
}
}

public MethodReference Runtime_TryGetNSObject {
get {
return GetMethodReference (PlatformAssembly,
ObjCRuntime_Runtime, "TryGetNSObject",
nameof (Runtime_TryGetNSObject),
isStatic: true,
System_IntPtr,
System_Boolean);
}
}
public MethodReference Runtime_GetNSObject__System_IntPtr {
get {
return GetMethodReference (PlatformAssembly,
Expand Down Expand Up @@ -814,19 +830,6 @@ public MethodReference Runtime_GetNSObject_T___System_IntPtr {
}
}

public MethodReference Runtime_GetINativeObject__IntPtr_Boolean_Type_Type {
get {
return GetMethodReference (PlatformAssembly,
ObjCRuntime_Runtime, "GetINativeObject",
nameof (Runtime_GetINativeObject__IntPtr_Boolean_Type_Type),
isStatic: true,
System_IntPtr,
System_Boolean,
System_Type,
System_Type);
}
}

public MethodReference Runtime_CreateRuntimeException {
get {
return GetMethodReference (PlatformAssembly,
Expand Down Expand Up @@ -1142,6 +1145,7 @@ public void ClearCurrentAssembly ()
current_assembly = null;
type_map.Clear ();
method_map.Clear ();
field_map.Clear ();
}
}
}
42 changes: 35 additions & 7 deletions tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -921,14 +921,42 @@ bool EmitConversion (MethodDefinition method, ILProcessor il, TypeReference type
// cast to the generic type to verify that the item is actually of the correct type
il.Emit (OpCodes.Unbox_Any, type);
} else {
var nativeObjType = StaticRegistrar.GetInstantiableType (type.Resolve (), exceptions, GetMethodSignature (method));
StaticRegistrar.GetInstantiableType (type.Resolve (), exceptions, GetMethodSignature (method), out var ctor);
EnsureVisible (method, ctor);
var targetType = method.Module.ImportReference (type);
var handleVariable = il.Body.AddVariable (abr.System_IntPtr);
var objectVariable = il.Body.AddVariable (targetType);
var loadHandle = il.Create (OpCodes.Ldloc, handleVariable);
var loadObjectVariable = il.Create (OpCodes.Ldloc, objectVariable);
il.Emit (OpCodes.Stloc, handleVariable);
// objectVariable = null
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Stloc, objectVariable);
// if (handle == IntPtr.Zero)
// goto done;
il.Emit (OpCodes.Ldloc, handleVariable); // handle
il.Emit (OpCodes.Ldsfld, abr.System_IntPtr_Zero);
il.Emit (OpCodes.Beq, loadObjectVariable);
// objectVariable = TryGetNSObject (handle, false) as TargetType
il.Emit (OpCodes.Ldloc, handleVariable); // handle
il.Emit (OpCodes.Ldc_I4_0); // false
il.Emit (OpCodes.Call, abr.Runtime_TryGetNSObject);
il.Emit (OpCodes.Castclass, targetType);
il.Emit (OpCodes.Stloc, objectVariable);
// if (objectVariable is null)
// objectVariable = new TargetType (handle, false)
il.Emit (OpCodes.Ldloc, objectVariable);
il.Emit (OpCodes.Brfalse, loadHandle);
il.Emit (OpCodes.Br, loadObjectVariable);
il.Append (loadHandle);
if (ctor.Parameters [0].ParameterType.Is ("ObjCRuntime", "NativeHandle"))
il.Emit (OpCodes.Call, abr.NativeObject_op_Implicit_NativeHandle);
il.Emit (OpCodes.Ldc_I4_0); // false
il.Emit (OpCodes.Ldtoken, method.Module.ImportReference (type)); // target type
il.Emit (OpCodes.Call, abr.Type_GetTypeFromHandle);
il.Emit (OpCodes.Ldtoken, method.Module.ImportReference (nativeObjType)); // implementation type
il.Emit (OpCodes.Call, abr.Type_GetTypeFromHandle);
il.Emit (OpCodes.Call, abr.Runtime_GetINativeObject__IntPtr_Boolean_Type_Type);
il.Emit (OpCodes.Castclass, type);
il.Emit (OpCodes.Newobj, method.Module.ImportReference (ctor));
il.Emit (OpCodes.Stloc, objectVariable);
// done:
// (load objectVariable on the stack)
il.Append (loadObjectVariable);
}
nativeType = abr.System_IntPtr;
} else {
Expand Down

5 comments on commit f24a016

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.