[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:
Родитель
aacedd12c7
Коммит
8285c08c17
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче