552 строки
17 KiB
Plaintext
552 строки
17 KiB
Plaintext
<# // vim: set filetype=cs :
|
|
#>
|
|
<#@ template language="C#" #>
|
|
<#@ import namespace="System" #>
|
|
<#@ import namespace="System.Text" #>
|
|
<#@ import namespace="System.Collections.Generic" #>
|
|
<#
|
|
var delegates = new XDelegates {
|
|
new XDelegate ("void", "void", "xamarin_register_nsobject",
|
|
// Do not automatically convert the 'managed_obj' parameter, the
|
|
// automatic conversion doesn't support neither the GCHandle type
|
|
// RegisterNSObject expects (tracking resurrection), nor the fact
|
|
// that the called method takes ownership of the GCHandle.
|
|
"GCHandle", "IntPtr", "managed_obj",
|
|
"id", "IntPtr", "native_obj"
|
|
) {
|
|
WrappedManagedFunction = "RegisterNSObject",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_register_assembly",
|
|
"GCHandle->MonoReflectionAssembly *", "IntPtr", "assembly"
|
|
) {
|
|
WrappedManagedFunction = "RegisterAssembly",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_throw_ns_exception",
|
|
"NSException *", "IntPtr", "exc"
|
|
) {
|
|
WrappedManagedFunction = "ThrowNSException",
|
|
ExceptionHandling = false,
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_rethrow_managed_exception",
|
|
"GCHandle", "IntPtr", "original_exception_gchandle"
|
|
) {
|
|
WrappedManagedFunction = "RethrowManagedException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle", "IntPtr", "xamarin_create_ns_exception",
|
|
"NSException *", "IntPtr", "exc"
|
|
) {
|
|
WrappedManagedFunction = "CreateNSException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("NSException *", "IntPtr", "xamarin_unwrap_ns_exception",
|
|
"GCHandle", "IntPtr", "exc_handle"
|
|
) {
|
|
WrappedManagedFunction = "UnwrapNSException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_block_wrapper_creator",
|
|
"GCHandle->MonoReflectionMethod *", "IntPtr", "method",
|
|
"int", "int", "parameter"
|
|
) {
|
|
WrappedManagedFunction = "GetBlockWrapperCreator",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_create_block_proxy",
|
|
// Don't convert the 'method' parameter, we already have a GCHandle
|
|
// available we can use.
|
|
"GCHandle", "IntPtr", "method",
|
|
"void *", "IntPtr", "block"
|
|
) {
|
|
WrappedManagedFunction = "CreateBlockProxy",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("id", "IntPtr", "xamarin_create_delegate_proxy",
|
|
"GCHandle->MonoReflectionMethod *", "IntPtr", "method",
|
|
"GCHandle->MonoObject *", "IntPtr", "block",
|
|
"const char *", "IntPtr", "signature",
|
|
"unsigned int", "uint", "token_ref"
|
|
) {
|
|
WrappedManagedFunction = "CreateDelegateProxy",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_register_entry_assembly",
|
|
"GCHandle->MonoReflectionAssembly *", "IntPtr", "assembly"
|
|
) {
|
|
WrappedManagedFunction = "RegisterEntryAssembly",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_class",
|
|
"Class", "IntPtr", "ptr"
|
|
) {
|
|
WrappedManagedFunction = "GetClass",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_selector",
|
|
"SEL", "IntPtr", "ptr"
|
|
) {
|
|
WrappedManagedFunction = "GetSelector",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_get_method_for_selector",
|
|
"Class", "IntPtr", "cls",
|
|
"SEL", "IntPtr", "sel",
|
|
"bool", "bool", "is_static",
|
|
"MethodDescription *", "IntPtr", "desc"
|
|
) {
|
|
WrappedManagedFunction = "GetMethodForSelector",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("bool", "bool", "xamarin_has_nsobject",
|
|
"id", "IntPtr", "obj"
|
|
) {
|
|
WrappedManagedFunction = "HasNSObject",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("id", "IntPtr", "xamarin_get_handle_for_inativeobject",
|
|
"GCHandle->MonoObject *", "IntPtr", "obj_handle"
|
|
) {
|
|
WrappedManagedFunction = "GetHandleForINativeObject",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_unregister_nsobject",
|
|
"id", "IntPtr", "native_obj",
|
|
// Do not automatically convert the 'managed_obj' parameter,
|
|
// in one case where call this method we already have a GCHandle
|
|
// available we can use.
|
|
"GCHandle", "IntPtr", "managed_obj"
|
|
) {
|
|
WrappedManagedFunction = "UnregisterNSObject",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_try_get_or_construct_nsobject",
|
|
"id", "IntPtr", "obj"
|
|
) {
|
|
WrappedManagedFunction = "TryGetOrConstructNSObjectWrapped",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_inative_object_dynamic",
|
|
"id", "IntPtr", "obj",
|
|
"bool", "bool", "owns",
|
|
"GCHandle->MonoReflectionType *", "IntPtr", "type"
|
|
) {
|
|
WrappedManagedFunction = "GetINativeObject_Dynamic",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
// Do not automatically unwrap the return value, because otherwise we might need to immediately wrap it in a GCHandle again.
|
|
new XDelegate ("GCHandle", "IntPtr", "xamarin_get_method_from_token",
|
|
"unsigned int", "uint", "token_ref"
|
|
) {
|
|
WrappedManagedFunction = "GetMethodFromToken",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
// Do not automatically unwrap the return value, because otherwise we might need to immediately wrap it in a GCHandle again.
|
|
new XDelegate ("GCHandle", "IntPtr", "xamarin_get_generic_method_from_token",
|
|
"GCHandle->MonoObject *", "IntPtr", "obj_handle",
|
|
"unsigned int", "uint", "token_ref"
|
|
) {
|
|
WrappedManagedFunction = "GetGenericMethodFromToken",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_inative_object_static",
|
|
"id", "IntPtr", "obj",
|
|
"bool", "bool", "owns",
|
|
"unsigned int", "uint", "iface_token_ref",
|
|
"unsigned int", "uint", "implementation_token_ref"
|
|
) {
|
|
WrappedManagedFunction = "GetINativeObject_Static",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_get_nsobject_with_type",
|
|
"id", "IntPtr", "obj",
|
|
"GCHandle->MonoReflectionType *", "IntPtr", "type",
|
|
"int32_t *", "out bool", "created"
|
|
) {
|
|
WrappedManagedFunction = "GetNSObjectWithType",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_dispose",
|
|
"GCHandle->MonoObject*", "IntPtr", "mobj"
|
|
) {
|
|
WrappedManagedFunction = "Dispose",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("bool", "bool", "xamarin_is_parameter_transient",
|
|
"GCHandle->MonoReflectionMethod *", "IntPtr", "method",
|
|
"int", "int", "parameter"
|
|
) {
|
|
WrappedManagedFunction = "IsParameterTransient",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("bool", "bool", "xamarin_is_parameter_out",
|
|
"GCHandle->MonoReflectionMethod *", "IntPtr", "method",
|
|
"int", "int", "parameter"
|
|
) {
|
|
WrappedManagedFunction = "IsParameterOut",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("void", "void", "xamarin_get_method_and_object_for_selector",
|
|
"Class", "IntPtr", "cls",
|
|
"SEL", "IntPtr", "sel",
|
|
"bool", "bool", "is_static",
|
|
"id", "IntPtr", "obj",
|
|
"GCHandle *", "ref IntPtr", "mthis",
|
|
"MethodDescription *", "IntPtr", "desc"
|
|
) {
|
|
WrappedManagedFunction = "GetMethodAndObjectForSelector",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("GCHandle", "IntPtr", "xamarin_create_product_exception_for_error",
|
|
"int", "int", "code",
|
|
"GCHandle", "IntPtr", "inner_exception_gchandle",
|
|
"const char *", "string", "message"
|
|
) {
|
|
WrappedManagedFunction = "CreateProductException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("char *", "IntPtr", "xamarin_reflection_type_get_full_name",
|
|
"GCHandle->MonoReflectionType *", "IntPtr", "type"
|
|
) {
|
|
WrappedManagedFunction = "TypeGetFullName",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("char *", "IntPtr", "xamarin_lookup_managed_type_name",
|
|
"Class", "IntPtr", "klass"
|
|
) {
|
|
WrappedManagedFunction = "LookupManagedTypeName",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("enum MarshalManagedExceptionMode", "MarshalManagedExceptionMode", "xamarin_on_marshal_managed_exception",
|
|
"GCHandle", "IntPtr", "exception"
|
|
) {
|
|
WrappedManagedFunction = "OnMarshalManagedException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("enum MarshalObjectiveCExceptionMode", "MarshalObjectiveCExceptionMode", "xamarin_on_marshal_objectivec_exception",
|
|
"id", "IntPtr", "exception",
|
|
"bool", "bool", "throwManagedAsDefault"
|
|
) {
|
|
WrappedManagedFunction = "OnMarshalObjectiveCException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
|
|
new XDelegate ("NSString *", "IntPtr", "xamarin_convert_smart_enum_to_nsstring",
|
|
"GCHandle->MonoObject *", "IntPtr", "value"
|
|
) {
|
|
WrappedManagedFunction = "ConvertSmartEnumToNSString",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("GCHandle->MonoObject *", "IntPtr", "xamarin_convert_nsstring_to_smart_enum",
|
|
"NSString *", "IntPtr", "value",
|
|
"GCHandle->MonoReflectionType *", "IntPtr", "type"
|
|
) {
|
|
WrappedManagedFunction = "ConvertNSStringToSmartEnum",
|
|
OnlyDynamicUsage = true,
|
|
},
|
|
|
|
new XDelegate ("GCHandle", "IntPtr", "xamarin_create_runtime_exception",
|
|
"int32_t", "int", "code",
|
|
"const char *", "IntPtr", "message"
|
|
) {
|
|
WrappedManagedFunction = "CreateRuntimeException",
|
|
OnlyDynamicUsage = false,
|
|
},
|
|
};
|
|
delegates.CalculateLengths ();
|
|
#><#+
|
|
class Arg
|
|
{
|
|
public string MangledCType;
|
|
public string ExposedCType; // the CType exposed to native code
|
|
public string InterfaceCType; // the CType as interfaced with managed code
|
|
public string MType;
|
|
public string Name;
|
|
public bool IsGCHandleConversion => MangledCType.Contains ("->");
|
|
public Arg (string mangledCType, string mType, string name)
|
|
{
|
|
MangledCType = mangledCType;
|
|
var is_conv = IsGCHandleConversion;
|
|
var interfaced = is_conv ? "GCHandle" : mangledCType;
|
|
var exposed = is_conv ? XDelegate.GetConvertedGCHandleType (mangledCType) : mangledCType;
|
|
ExposedCType = exposed;
|
|
InterfaceCType = interfaced;
|
|
MType = mType;
|
|
Name = name;
|
|
}
|
|
public bool IsVoid => ExposedCType == "void";
|
|
}
|
|
|
|
class XDelegates : List<XDelegate>
|
|
{
|
|
public void CalculateLengths ()
|
|
{
|
|
foreach (var x in this) {
|
|
MaxEntryPointLength = Math.Max (MaxEntryPointLength, x.EntryPoint.Length);
|
|
MaxCReturnTypeLength = Math.Max (MaxCReturnTypeLength, x.ReturnType.ExposedCType.Length);
|
|
x.Delegates = this;
|
|
}
|
|
}
|
|
|
|
public int MaxEntryPointLength;
|
|
public int MaxCReturnTypeLength;
|
|
}
|
|
|
|
class XDelegate
|
|
{
|
|
public Arg ReturnType;
|
|
public string EntryPoint;
|
|
public List<Arg> Arguments;
|
|
public string WrappedManagedFunction;
|
|
public bool ExceptionHandling = true;
|
|
// Detemines whether the function is only used by the dynamic registrar (in which case we might be able to link the function away if the static registrar is being used)
|
|
public bool OnlyDynamicUsage;
|
|
|
|
public string DelegateName {
|
|
get {
|
|
return EntryPoint.Substring ("xamarin_".Length);
|
|
}
|
|
}
|
|
|
|
public static string GetConvertedGCHandleType (string type)
|
|
{
|
|
return type.Substring ("GCHandle->".Length);
|
|
}
|
|
|
|
public XDelegates Delegates;
|
|
|
|
public XDelegate (string cReturnType, string mReturnType, string entryPoint, params string [] arguments)
|
|
{
|
|
ReturnType = new Arg (cReturnType, mReturnType, string.Empty);
|
|
EntryPoint = entryPoint;
|
|
|
|
if (arguments == null || arguments.Length == 0)
|
|
return;
|
|
|
|
if (arguments.Length % 3 != 0)
|
|
throw new Exception (string.Format ("Export arguments params must be a multiple of 3 to form a set of (c type, managed name, name) triples for {0}", entryPoint));
|
|
|
|
if (!entryPoint.StartsWith ("xamarin_"))
|
|
throw new Exception ("All entry points must start with 'xamarin_'");
|
|
|
|
Arguments = new List<Arg> ();
|
|
for (var i = 0; i < arguments.Length; i += 3)
|
|
Arguments.Add (new Arg (arguments [i], arguments [i + 1], arguments [i + 2]));
|
|
}
|
|
|
|
public string Function {
|
|
get {
|
|
var sb = new StringBuilder ();
|
|
|
|
// This function generates the helper function that actually calls the managed delegate
|
|
// It supports converting input arguments of MonoObject* (and equivalent types) to GCHandle,
|
|
// and converting GCHandle return values to MonoObject* (or equivalent types). In both cases
|
|
// the GCHandle will be freed before the generated function returns.
|
|
|
|
sb.AppendLine (ReturnType.ExposedCType);
|
|
|
|
sb.Append (EntryPoint);
|
|
sb.Append (" (");
|
|
sb.Append (CArgumentSignatureExposed);
|
|
sb.AppendLine (")");
|
|
sb.AppendLine ("{");
|
|
|
|
if (ExceptionHandling && OnlyDynamicUsage) {
|
|
sb.AppendLine ($"\tif (delegates.{DelegateName} == NULL) {{");
|
|
sb.AppendLine ($"\t\t*exception_gchandle = create_linked_away_exception (\"{DelegateName}\");");
|
|
sb.AppendLine ($"\t\treturn{(ReturnType.IsVoid ? string.Empty : $" ({ReturnType.ExposedCType}) 0")};");
|
|
sb.AppendLine ($"\t}}");
|
|
} else {
|
|
sb.AppendLine ($"#if DEBUG");
|
|
sb.AppendLine ($"\tif (delegates.{DelegateName} == NULL) {{");
|
|
sb.AppendLine ($"\t\tNSLog (@PRODUCT \": The managed function {DelegateName} could not be loaded.\");");
|
|
sb.AppendLine ($"\t\txamarin_assertion_message (\"The managed function {DelegateName} could not be loaded.\");");
|
|
sb.AppendLine ($"\t}}");
|
|
sb.AppendLine ($"#endif");
|
|
}
|
|
|
|
var invoke_args = new StringBuilder ();
|
|
var post_invoke = new StringBuilder ();
|
|
for (var i = 0; i < Arguments.Count; i++) {
|
|
var arg = Arguments [i];
|
|
if (i > 0)
|
|
invoke_args.Append (", ");
|
|
if (arg.IsGCHandleConversion) {
|
|
// Convert to GCHandle before calling the managed functino
|
|
var argname = $"{arg.Name}__handle";
|
|
sb.AppendLine ($"\tGCHandle {argname} = xamarin_gchandle_new ((MonoObject *) {arg.Name}, false);");
|
|
invoke_args.Append (argname);
|
|
// and free the GCHandle after returning from the managed function
|
|
post_invoke.AppendLine ($"\txamarin_gchandle_free ({argname});");
|
|
} else {
|
|
invoke_args.Append (arg.Name);
|
|
}
|
|
}
|
|
|
|
sb.Append ("\t");
|
|
if (!ReturnType.IsVoid) {
|
|
sb.Append ($"{ReturnType.ExposedCType} rv = ");
|
|
// Unwrap the GCHandle and free it
|
|
if (ReturnType.IsGCHandleConversion)
|
|
sb.Append ("xamarin_gchandle_unwrap (");
|
|
}
|
|
|
|
sb.Append ("delegates.");
|
|
sb.Append (EntryPoint.Substring ("xamarin_".Length));
|
|
sb.Append (" (");
|
|
sb.Append (invoke_args);
|
|
if (ExceptionHandling)
|
|
sb.Append (", exception_gchandle");
|
|
|
|
if (ReturnType.IsGCHandleConversion)
|
|
sb.Append (")");
|
|
|
|
sb.AppendLine (");");
|
|
|
|
sb.Append (post_invoke);
|
|
|
|
if (!ReturnType.IsVoid)
|
|
sb.AppendLine ("\treturn rv;");
|
|
|
|
sb.AppendLine ("}");
|
|
return sb.ToString ();
|
|
}
|
|
}
|
|
|
|
public string SimpleEntryPoint {
|
|
get {
|
|
return EntryPoint.Substring ("xamarin_".Length);
|
|
}
|
|
}
|
|
|
|
public string AlignEntryPoint {
|
|
get {
|
|
return new string (' ', Delegates.MaxEntryPointLength - EntryPoint.Length);
|
|
}
|
|
}
|
|
|
|
public string AlignCReturnType {
|
|
get {
|
|
return new string (' ', Delegates.MaxCReturnTypeLength - ReturnType.ExposedCType.Length);
|
|
}
|
|
}
|
|
|
|
string CFormatArgs (string empty, bool nameOnly, bool exposed = false)
|
|
{
|
|
if (Arguments == null || Arguments.Count == 0)
|
|
return empty;
|
|
|
|
var builder = new StringBuilder ();
|
|
|
|
foreach (var arg in Arguments) {
|
|
if (!nameOnly) {
|
|
builder.Append (exposed ? arg.ExposedCType : arg.InterfaceCType);
|
|
builder.Append (' ');
|
|
}
|
|
|
|
builder.Append (arg.Name);
|
|
builder.Append (", ");
|
|
}
|
|
|
|
builder.Length -= 2;
|
|
|
|
if (ExceptionHandling) {
|
|
if (nameOnly) {
|
|
builder.Append (", exception_gchandle");
|
|
} else {
|
|
builder.Append (", GCHandle *exception_gchandle");
|
|
}
|
|
}
|
|
|
|
return builder.ToString ();
|
|
}
|
|
|
|
string MFormatArgs (string empty, bool nameOnly)
|
|
{
|
|
if (Arguments == null || Arguments.Count == 0)
|
|
return empty;
|
|
|
|
var builder = new StringBuilder ();
|
|
|
|
foreach (var arg in Arguments) {
|
|
if (!nameOnly) {
|
|
builder.Append (arg.MType);
|
|
builder.Append (' ');
|
|
} else if (arg.MType.StartsWith ("out ")) {
|
|
builder.Append ("out ");
|
|
} else if (arg.MType.StartsWith ("ref ")) {
|
|
builder.Append ("ref ");
|
|
}
|
|
|
|
builder.Append (arg.Name);
|
|
builder.Append (", ");
|
|
}
|
|
|
|
builder.Length -= 2;
|
|
|
|
if (ExceptionHandling) {
|
|
if (nameOnly) {
|
|
// nothing to do
|
|
} else {
|
|
builder.Append (", out IntPtr exception_gchandle");
|
|
}
|
|
}
|
|
|
|
return builder.ToString ();
|
|
}
|
|
|
|
public string CArgumentSignature {
|
|
get { return CFormatArgs ("void", nameOnly: false); }
|
|
}
|
|
|
|
public string CArgumentSignatureExposed {
|
|
get { return CFormatArgs ("void", nameOnly: false, exposed: true); }
|
|
}
|
|
|
|
public string CArgumentNames {
|
|
get { return CFormatArgs (String.Empty, nameOnly: true); }
|
|
}
|
|
|
|
public string MArgumentSignature {
|
|
get { return MFormatArgs ("", nameOnly: false); }
|
|
}
|
|
|
|
public string MArgumentNames {
|
|
get { return MFormatArgs (String.Empty, nameOnly: true); }
|
|
}
|
|
}
|
|
#>
|