[registrar] Improve support for pointers to value types in exported signatures. (#17608)

This will be required when we make blocks use blittable callbacks, since we'll
have to use pointers in a few cases (because ref/out arguments aren't
blittable).
This commit is contained in:
Rolf Bjarne Kvinge 2023-02-28 11:48:27 +01:00 коммит произвёл GitHub
Родитель aacedd12c7
Коммит 8285c08c17
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 106 добавлений и 22 удалений

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

@ -620,6 +620,11 @@ namespace Registrar {
return type.IsAbstract;
}
protected override bool IsPointer (Type type)
{
return type.IsPointer;
}
protected override bool IsINativeObject (Type type)
{
return typeof (INativeObject).IsAssignableFrom (type);

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

@ -1126,6 +1126,7 @@ namespace Registrar {
protected abstract bool IsGenericMethod (TMethod method);
protected abstract bool IsInterface (TType type);
protected abstract bool IsAbstract (TType type);
protected abstract bool IsPointer (TType type);
protected abstract TType GetGenericTypeDefinition (TType type);
protected abstract bool VerifyIsConstrainedToNSObject (TType type, out TType constrained_type);
protected abstract TType GetEnumUnderlyingType (TType type);
@ -2715,6 +2716,9 @@ namespace Registrar {
return "@"; // But we don't care about the actual type, we'll just return '@'. We only support NSArrays of the element type, so '@' is always right.
}
if (IsPointer (type))
return "^" + ToSignature (GetElementType (type), member, ref success);
success = false;
return string.Empty;
}

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

@ -689,6 +689,11 @@ namespace ObjCRuntime {
parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr (nativeParam);
}
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsPointer) {
log_coreclr ($" IsPointer nativeParam: 0x{nativeParam.ToString ("x")} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero)
parameters [i] = nativeParam;
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsClass || paramType.IsInterface || (paramType.IsValueType && IsNullable (paramType))) {
log_coreclr ($" IsClass/IsInterface/IsNullable IsByRef: {isByRef} IsOut: {p.IsOut} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero) {

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

@ -287,6 +287,13 @@ public partial class Generator : IMemberGatherer {
return (mai.IsOut ? "out " : "ref ") + (formatted ? FormatType (null, elementType) : elementType.Name);
}
// Pass "ValueType*" directly
if (mai.Type.IsPointer) {
var elementType = mai.Type.GetElementType ();
if (elementType.IsValueType)
return (formatted ? FormatType (null, elementType) : elementType.Name) + "*";
}
if (mai.Type.IsSubclassOf (TypeManager.System_Delegate)) {
return NativeHandleType;
}
@ -968,6 +975,13 @@ public partial class Generator : IMemberGatherer {
return (pi.IsOut ? "out " : "ref ") + safe_name;
}
// Handle 'ValueType* foo'
if (pi.ParameterType.IsPointer) {
var et = pi.ParameterType.GetElementType ();
if (et.IsValueType)
return safe_name;
}
if (pi.ParameterType.IsSubclassOf (TypeManager.System_Delegate)) {
return String.Format ("(IntPtr) block_ptr_{0}", pi.Name);
}
@ -1077,7 +1091,7 @@ public partial class Generator : IMemberGatherer {
continue;
sb.Append ("_");
try {
sb.Append (ParameterGetMarshalType (new MarshalInfo (this, mi, pi)).Replace (' ', '_'));
sb.Append (ParameterGetMarshalType (new MarshalInfo (this, mi, pi)).Replace (' ', '_').Replace ('*', '_'));
} catch (BindingException ex) {
throw new BindingException (1079, ex.Error, ex, ex.Message, pi.Name.GetSafeParamName (), mi.DeclaringType, mi.Name);
}
@ -1145,7 +1159,7 @@ public partial class Generator : IMemberGatherer {
else if (returnType == "char")
print (m, "\t\t[return: MarshalAs (UnmanagedType.U2)]");
print (m, "\t\tpublic extern static {0} {1} ({3}IntPtr receiver, IntPtr selector{2});",
print (m, "\t\tpublic unsafe extern static {0} {1} ({3}IntPtr receiver, IntPtr selector{2});",
returnType, method_name, b.ToString (),
need_stret ? (aligned ? "IntPtr" : "out " + FormatTypeUsedIn ("ObjCRuntime", mi.ReturnType)) + " retval, " : "");
}
@ -3703,6 +3717,8 @@ public partial class Generator : IMemberGatherer {
// convs.AppendFormat ("{0}.Handle", pi.Name.GetSafeParamName ());
} else if (HasBindAsAttribute (pi)) {
convs.AppendFormat ("var nsb_{0} = {1}\n", pi.Name, GetToBindAsWrapper (mi, null, pi));
} else if (mai.Type.IsPointer && mai.Type.GetElementType ().IsValueType) {
// nothing to do
} else {
if (mai.Type.IsClass && !mai.Type.IsByRef &&
(mai.Type != TypeManager.Selector && mai.Type != TypeManager.Class && mai.Type != TypeManager.System_String && !TypeManager.INativeObject.IsAssignableFrom (mai.Type)))

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

@ -21,8 +21,8 @@ namespace BI1064 {
[Export ("testString:a:b:")]
void TestString (int action, ref string refValue, out string outValue);
[Export ("testInt:a:b:")]
void TestInt (int action, ref int refValue, out int outValue);
[Export ("testInt:a:b:c:")]
unsafe void TestInt (int action, ref int refValue, out int outValue, int* ptrValue);
[Export ("testSelector:a:b:")]
void TestSelector (int action, ref Selector refValue, out Selector outValue);

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

@ -253,6 +253,9 @@ namespace ObjCRuntime {
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_int_int_int (IntPtr receiver, IntPtr selector, int p1, ref int p2, out int p3);
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public unsafe extern static void void_objc_msgSend_int_int_int_int (IntPtr receiver, IntPtr selector, int p1, ref int p2, out int p3, int* p4);
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr_IntPtr_IntPtr_IntPtr_IntPtr_IntPtr_IntPtr (IntPtr receiver, IntPtr selector, ref IntPtr p1, ref IntPtr p2, ref IntPtr p3, ref IntPtr p4, ref IntPtr p5, ref IntPtr p6, ref IntPtr p7);

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

@ -3688,13 +3688,14 @@ namespace MonoTouchFixtures.ObjCRuntime {
}
[Test]
public void RefOutTest_Int ()
public unsafe void RefOutTest_Int ()
{
using (var obj = new RefOutParametersSubclass ()) {
var sel = Selector.GetHandle ("testInt:a:b:");
var sel = Selector.GetHandle ("testInt:a:b:c:");
var dummyObj = 314;
int refObj = 0;
int outObj = 0;
int ptrObj = 0;
int action;
/// 1: set both to 0
@ -3703,30 +3704,38 @@ namespace MonoTouchFixtures.ObjCRuntime {
// native
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
obj.TestInt (action << 0, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
obj.TestInt (action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreEqual (0, refObj, "Int-1A-ref");
Assert.AreEqual (0, outObj, "Int-1A-out");
Assert.AreEqual (0, ptrObj, "Int-1A-ptr");
// managed
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
obj.TestInt (action << 8, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
obj.TestInt (action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreEqual (0, refObj, "Int-1M-ref");
Assert.AreEqual (0, outObj, "Int-1M-out");
Assert.AreEqual (0, ptrObj, "Int-1M-ptr");
// direct native
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreEqual (0, refObj, "Int-1DA-ref");
Assert.AreEqual (0, outObj, "Int-1DA-out");
Assert.AreEqual (0, ptrObj, "Int-1DA-ptr");
// direct managed
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreEqual (0, refObj, "Int-1DM-ref");
Assert.AreEqual (0, outObj, "Int-1DM-out");
Assert.AreEqual (0, ptrObj, "Int-1DM-ptr");
/// 2: N/A for testInt
@ -3736,34 +3745,46 @@ namespace MonoTouchFixtures.ObjCRuntime {
// native
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
obj.TestInt (action << 0, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
obj.TestInt (action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (dummyObj, refObj, "Int-3A-ref");
Assert.AreNotEqual (dummyObj, outObj, "Int-3A-out");
Assert.AreNotEqual (dummyObj, ptrObj, "Int-3A-ptr");
Assert.AreEqual (refObj, outObj, "Int-3A-out-ref-eq");
Assert.AreEqual (refObj, ptrObj, "Int-3A-out-ptr-eq");
// managed
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
obj.TestInt (action << 8, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
obj.TestInt (action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (dummyObj, refObj, "Int-3M-ref");
Assert.AreNotEqual (dummyObj, outObj, "Int-3M-out");
Assert.AreNotEqual (dummyObj, ptrObj, "Int-3M-ptr");
Assert.AreEqual (refObj, outObj, "Int-3M-out-ref-eq");
Assert.AreEqual (refObj, ptrObj, "Int-3M-out-ptr-eq");
// direct native
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (dummyObj, refObj, "Int-3DA-ref");
Assert.AreNotEqual (dummyObj, outObj, "Int-3DA-out");
Assert.AreNotEqual (dummyObj, ptrObj, "Int-3DA-ptr");
Assert.AreEqual (refObj, outObj, "Int-3DA-out-ref-same");
Assert.AreEqual (refObj, ptrObj, "Int-3DA-out-ptr-same");
// direct managed
refObj = dummyObj; // set to non-null
outObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj);
ptrObj = dummyObj; // set to non-null
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (dummyObj, refObj, "Int-3DM-ref");
Assert.AreNotEqual (dummyObj, outObj, "Int-3DM-out");
Assert.AreNotEqual (dummyObj, ptrObj, "Int-3DM-ptr");
Assert.AreEqual (refObj, outObj, "Int-3DM-out-ref-eq");
Assert.AreEqual (refObj, ptrObj, "Int-3DM-out-ptr-eq");
/// 4 set both parameteres to different pointers of a Int
@ -3772,38 +3793,52 @@ namespace MonoTouchFixtures.ObjCRuntime {
// native
refObj = 0; // set to 0
outObj = 0; // set to 0
obj.TestInt (action << 0, ref refObj, out outObj);
ptrObj = 0; // set to 0
obj.TestInt (action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (0, refObj, "Int-4A-ref");
Assert.AreNotEqual (0, outObj, "Int-4A-out");
Assert.AreNotEqual (0, ptrObj, "Int-4A-ptr");
Assert.AreNotEqual (refObj, outObj, "Int-4A-ref-distinct");
Assert.AreNotEqual (refObj, ptrObj, "Int-4A-ptr-distinct");
// managed
refObj = 0; // set to 0
outObj = 0; // set to 0
obj.TestInt (action << 8, ref refObj, out outObj);
ptrObj = 0; // set to 0
obj.TestInt (action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (0, refObj, "Int-4M-ref");
Assert.AreNotEqual (0, outObj, "Int-4M-out");
Assert.AreNotEqual (0, ptrObj, "Int-4M-ptr");
Assert.AreNotEqual (refObj, outObj, "Int-4M-ref-distinct");
Assert.AreNotEqual (refObj, ptrObj, "Int-4M-ptr-distinct");
// direct native
refObj = 0; // set to 0
outObj = 0; // set to 0
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj);
ptrObj = 0; // set to 0
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 0, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (0, refObj, "Int-4DA-ref");
Assert.AreNotEqual (0, outObj, "Int-4DA-out");
Assert.AreNotEqual (0, ptrObj, "Int-4DA-ptr");
Assert.AreNotEqual (refObj, outObj, "Int-4DA-ref-distinct");
Assert.AreNotEqual (refObj, ptrObj, "Int-4DA-ptr-distinct");
Assert.AreEqual (3141592, refObj, "Int-4DA-ref-value");
Assert.AreEqual (2718282, outObj, "Int-4DA-out-value");
Assert.AreEqual (5772156, ptrObj, "Int-4DA-ptr-value");
// direct managed
refObj = 0; // set to 0
outObj = 0; // set to 0
Messaging.void_objc_msgSend_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj);
ptrObj = 0; // set to 0
Messaging.void_objc_msgSend_int_int_int_int (obj.Handle, sel, action << 8, ref refObj, out outObj, &ptrObj);
Assert.AreNotEqual (0, refObj, "Int-4DM-ref");
Assert.AreNotEqual (0, outObj, "Int-4DM-out");
Assert.AreNotEqual (0, ptrObj, "Int-4DM-ptr");
Assert.AreNotEqual (refObj, outObj, "Int-4DM-ref-distinct");
Assert.AreNotEqual (refObj, ptrObj, "Int-4DM-ptr-distinct");
Assert.AreEqual (3141592, refObj, "Int-4DM-ref-value");
Assert.AreEqual (2718282, outObj, "Int-4DM-out-value");
Assert.AreEqual (5772156, ptrObj, "Int-4DM-ptr-value");
}
}
@ -5174,24 +5209,27 @@ namespace MonoTouchFixtures.ObjCRuntime {
}
}
public override void TestInt (int action, ref int refValue, out int outValue)
public unsafe override void TestInt (int action, ref int refValue, out int outValue, int* ptrValue)
{
var managedAction = (action & 0xFF00) >> 8;
switch (managedAction) {
case 0: // call native
base.TestInt (action, ref refValue, out outValue);
base.TestInt (action, ref refValue, out outValue, ptrValue);
break;
case 1: // set both to null
refValue = 0;
outValue = 0;
*ptrValue = 0;
break;
case 3: // set both parameteres to the same value
refValue = 314159;
outValue = 314159;
*ptrValue = 314159;
break;
case 4: // set both parameteres to different values
refValue = 3141592;
outValue = 2718282;
*ptrValue = 5772156;
break;
default:
throw new NotImplementedException ();

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

@ -262,7 +262,7 @@ typedef void (^outerBlock) (innerBlock callback);
-(void) testNSObject: (int) action a:(id *) refValue b:(id *) outValue;
-(void) testNSValue: (int) action a:(NSValue **) refValue b:(NSValue **) outValue;
-(void) testString: (int) action a:(NSString **) refValue b:(NSString **) outValue;
-(void) testInt: (int) action a:(int32_t *) refValue b:(int32_t *) outValue;
-(void) testInt: (int) action a:(int32_t *) refValue b:(int32_t *) outValue c:(int32_t *) pointerValue;
-(void) testSelector: (int) action a:(SEL *) refValue b:(SEL *) outValue;
-(void) testClass: (int) action a:(Class *) refValue b:(Class *) outValue;

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

@ -1064,7 +1064,7 @@ static void block_called ()
}
}
-(void) testInt: (int) action a:(int32_t *) refValue b:(int32_t *) outValue
-(void) testInt: (int) action a:(int32_t *) refValue b:(int32_t *) outValue c:(int32_t *) pointerValue
{
NSString *obj __attribute__((unused)) = NULL;
@ -1076,15 +1076,18 @@ static void block_called ()
case 1: // Set both to 0
*refValue = 0;
*outValue = 0;
*pointerValue = 0;
break;
case 3: // set both parameteres to the same value
obj = @"A constant native string";
*refValue = 314159;
*outValue = 314159;
*pointerValue = 314159;
return;
case 4: // set both parameteres to different objects
*refValue = 3141592;
*outValue = 2718282;
*pointerValue = 5772156;
break;
default:
abort ();

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

@ -1105,6 +1105,11 @@ namespace Registrar {
return type.Resolve ()?.IsAbstract == true;
}
protected override bool IsPointer (TypeReference type)
{
return type is PointerType;
}
protected override TypeReference [] GetInterfaces (TypeReference type)
{
var td = type.Resolve ();
@ -2480,6 +2485,9 @@ namespace Registrar {
return res + "*";
}
if (type is PointerType pt)
return ToObjCParameterType (pt.ElementType, descriptiveMethodName, exceptions, inMethod, delegateToBlockType) + "*";
ArrayType arrtype = type as ArrayType;
if (arrtype != null)
return "NSArray *";
@ -3959,6 +3967,8 @@ namespace Registrar {
} else {
setup_call_stack.AppendLine ("arg_ptrs [{0}] = &p{0};", i);
}
} else if (type.IsPointer) {
setup_call_stack.AppendLine ("arg_ptrs [{0}] = p{0};", i);
} else if (td.BaseType.FullName == "System.MulticastDelegate") {
if (isRef) {
throw ErrorHelper.CreateError (4110, Errors.MT4110, type.FullName, descriptiveMethodName);