Merge remote-tracking branch 'origin/mono-2018-06' into mono-2018-08

This commit is contained in:
Aleksey Kliger 2018-09-20 12:09:07 -04:00
Родитель e79db298dc ec02eb8f9f
Коммит 16481d4ec1
55 изменённых файлов: 1082 добавлений и 164 удалений

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

@ -1340,8 +1340,8 @@ The following shows two such properties in Objective-C:
When you apply the `DisposeAttribute` to a class, you provide a code snippet
that will be added to the `Dispose()` method implementation of the class.
Since the `Dispose` method is automatically generated by the `bmac-native` and `btouch-native`
tools, you need to use the `Dispose` attribute to inject some code in the
Since the `Dispose` method is automatically generated by the `bgen`
tool, you need to use the `Dispose` attribute to inject some code in the
generated `Dispose` method implementation.
For example:

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

@ -378,6 +378,20 @@ will be shown.
Reference: https://github.com/xamarin/xamarin-macios/issues/4072
### <a name="MM4176"/>MM4176: Unable to locate the delegate to block conversion type for the return value of the method {method}.
This is a warning indicating that the static registrar couldn't find the type
used to convert a delegate to an Objective-C block. An attempt will be made at
runtime to find the method, but it will likely fail as well (with an MM8009
exception).
One possible reason for this warning is when manually writing bindings for API
that uses blocks. It's recommended to use a binding project to bind
Objective-C code, in particular when it involves blocks, since it's quite
complicated to get it right when doing it manually.
If this is not the case, please file a bug at [https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin.Mac) with a test case.
# MM5xxx: GCC and toolchain
## MM51xx: compilation
@ -508,3 +522,8 @@ There are a few reasons this may happen:
* It could be a bug in Xamarin.Mac. If this is the case, please file a bug at
[https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin.Mac).
### <a name="MM8028"/>MM8028: The runtime function {function} has been linked away.
This usually indicates a bug in Xamarin.Mac, because runtime functions should
not be linked away if they're needed. Please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).

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

@ -1787,6 +1787,20 @@ will be shown.
Reference: https://github.com/xamarin/xamarin-macios/issues/4072
### <a name="MT4176"/>MT4176: Unable to locate the delegate to block conversion type for the return value of the method {method}.
This is a warning indicating that the static registrar couldn't find the type
used to convert a delegate to an Objective-C block. An attempt will be made at
runtime to find the method, but it will likely fail as well (with an MT8009
exception).
One possible reason for this warning is when manually writing bindings for API
that uses blocks. It's recommended to use a binding project to bind
Objective-C code, in particular when it involves blocks, since it's quite
complicated to get it right when doing it manually.
If this is not the case, please file a bug at [https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS) with a test case.
# MT5xxx: GCC and toolchain error messages
### MT51xx: Compilation
@ -2527,3 +2541,8 @@ There are a few reasons this may happen:
* It could be a bug in Xamarin.iOS. If this is the case, please file a bug at
[https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
### <a name="MT8028"/>MT8028: The runtime function {function} has been linked away.
This usually indicates a bug in Xamarin.iOS, because runtime functions should
not be linked away if they're needed. Please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).

6
jenkins/Jenkinsfile поставляемый
Просмотреть файл

@ -366,8 +366,12 @@ timestamps {
} else {
def outputFile = "${workspace}/xamarin-macios/wrench-launch-external.output.tmp"
try {
// VSTS does not allow any branch name anymore, it has to be an existing branch.
// Since pull requests don't create branches in the xamarin org (that VSTS sees at least),
// I've created a 'pull-request' branch which we'll use for pull requests.
def vsts_branch = isPr ? "pull-request" : branchName;
withCredentials ([string (credentialsId: 'macios_provisionator_pat', variable: 'PROVISIONATOR_VSTS_PAT')]) {
sh ("make -C ${workspace}/xamarin-macios/tests wrench-launch-external MAC_PACKAGE_URL=${xmPackageUrl} IOS_PACKAGE_URL=${xiPackageUrl} WRENCH_URL=${env.RUN_DISPLAY_URL} BUILD_REVISION=${gitHash} BUILD_LANE=jenkins/${branchName} BUILD_WORK_HOST=${env.NODE_NAME} 2>&1 | tee ${outputFile}")
sh ("make -C ${workspace}/xamarin-macios/tests wrench-launch-external MAC_PACKAGE_URL=${xmPackageUrl} IOS_PACKAGE_URL=${xiPackageUrl} WRENCH_URL=${env.RUN_DISPLAY_URL} BUILD_REVISION=${gitHash} BUILD_LANE=${vsts_branch} BUILD_WORK_HOST=${env.NODE_NAME} 2>&1 | tee ${outputFile}")
}
processAtMonkeyWrench (outputFile)
} catch (error) {

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

@ -1,5 +1,5 @@
ifdef ENABLE_XAMARIN
NEEDED_MACCORE_VERSION := 07fde84362aac824c6d9596c8dae13cfa48a102e
NEEDED_MACCORE_VERSION := fbb847be2caac894fd3d54889317d808289dd351
NEEDED_MACCORE_BRANCH := master
MACCORE_DIRECTORY := maccore

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

@ -27,8 +27,7 @@ Copyright (C) 2014 Xamarin. All rights reserved.
<PropertyGroup>
<BaseLibDllPath>$(MacBclPath)/Xamarin.Mac.dll</BaseLibDllPath>
<BTouchToolPath>$(XamarinMacFrameworkRoot)/bin/</BTouchToolPath>
<BTouchToolExe Condition="Exists('$(BTouchToolPath)/bgen')">bgen</BTouchToolExe>
<BTouchToolExe Condition="!Exists('$(BTouchToolPath)/bgen')">bmac-mobile-mono</BTouchToolExe>
<BTouchToolExe>bgen</BTouchToolExe>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<DefineConstants>__UNIFIED__;__MACOS__;$(DefineConstants)</DefineConstants>

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

@ -106,8 +106,7 @@ namespace Xamarin.iOS.Tasks
[Required]
public bool EnableSGenConc { get; set; }
[Required]
public bool UseInterpreter { get; set; }
public string Interpreter { get; set; }
[Required]
public bool LinkerDumpDependencies { get; set; }
@ -405,8 +404,8 @@ namespace Xamarin.iOS.Tasks
if (EnableSGenConc)
args.AddLine ("--sgen-conc");
if (UseInterpreter)
args.Add ("--interpreter");
if (!string.IsNullOrEmpty (Interpreter))
args.Add ($"--interpreter={Interpreter}");
switch (LinkMode.ToLowerInvariant ()) {
case "sdkonly": args.AddLine ("--linksdkonly"); break;

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

@ -1,2 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FileList Name="Xamarin.TVOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%" />
<FileList Name="Xamarin.TVOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%">
<File AssemblyName="System.Buffers" Version="4.0.99.0" />
<File AssemblyName="System.Memory" Version="4.0.99.0" />
</FileList>

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

@ -1,2 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FileList Name="Xamarin.WatchOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%" />
<FileList Name="Xamarin.WatchOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%">
<File AssemblyName="System.Buffers" Version="4.0.99.0" />
<File AssemblyName="System.Memory" Version="4.0.99.0" />
</FileList>

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

@ -1,2 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FileList Name="Xamarin.iOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%" />
<FileList Name="Xamarin.iOS" TargetFrameworkDirectory="%TargetFrameworkDirectory%">
<File AssemblyName="System.Buffers" Version="4.0.99.0" />
<File AssemblyName="System.Memory" Version="4.0.99.0" />
</FileList>

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

@ -51,7 +51,6 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
<MtouchUseThumb Condition="'$(MtouchUseThumb)' == ''">False</MtouchUseThumb>
<MtouchProjectDirectory>$(MSBuildProjectDirectory)</MtouchProjectDirectory>
<MtouchEnableSGenConc Condition="'$(MtouchEnableSGenConc)' == ''">False</MtouchEnableSGenConc>
<MtouchUseInterpreter Condition="'$(MtouchUseInterpreter)' == ''">False</MtouchUseInterpreter>
<MtouchVerbosity Condition="$(MtouchVerbosity) == ''">2</MtouchVerbosity>
<IsMacEnabled>true</IsMacEnabled>

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

@ -831,7 +831,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
UseThumb="$(MtouchUseThumb)"
EnableBitcode="$(MtouchEnableBitcode)"
EnableSGenConc="$(MtouchEnableSGenConc)"
UseInterpreter="$(MtouchUseInterpreter)"
Interpreter="$(MtouchInterpreter)"
AppExtensionReferences="@(_ResolvedAppExtensionReferences)"
ArchiveSymbols="$(MonoSymbolArchive)"
Verbosity="$(MtouchVerbosity)"

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

@ -27,10 +27,24 @@ struct Delegates {
static struct Delegates delegates = { 0 };
static guint32
create_linked_away_exception (const char *func)
{
char *msg = xamarin_strdup_printf ("The runtime function %s has been linked away.", func);
guint32 gchandle = xamarin_create_product_exception (8028, msg);
xamarin_free (msg);
return gchandle;
}
<# foreach (var d in delegates) { #>
<#= d.CReturnType #>
<#= d.EntryPoint #> (<#= d.CArgumentSignature #>)
{
<#if (d.ExceptionHandling && d.OnlyDynamicUsage) {#>if (delegates.<#= d.EntryPoint.Substring ("xamarin_".Length) #> == NULL) {
*exception_gchandle = create_linked_away_exception ("<#= d.EntryPoint.Substring ("xamarin_".Length) #>");
return<# if (d.CReturnType != "void") { #> (<#= d.CReturnType #>) 0<# } #>;
}
<#}#>
<# if (d.CReturnType != "void") { #>return <# } #>delegates.<#= d.EntryPoint.Substring ("xamarin_".Length) #> (<#= d.CArgumentNames #>);
}

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

@ -69,7 +69,8 @@
new XDelegate ("id", "IntPtr", "xamarin_create_delegate_proxy",
"MonoObject *", "IntPtr", "method",
"MonoObject *", "IntPtr", "block",
"const char *", "IntPtr", "signature"
"const char *", "IntPtr", "signature",
"unsigned int", "uint", "token_ref"
) {
WrappedManagedFunction = "CreateDelegateProxy",
OnlyDynamicUsage = false,

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

@ -2187,10 +2187,10 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
}
id
xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature, guint32 *exception_gchandle)
xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature, guint32 token_ref, guint32 *exception_gchandle)
{
// COOP: accesses managed memory: unsafe mode.
return delegates.create_delegate_proxy ((MonoObject *) mono_method_get_object (mono_domain_get (), method, NULL), delegate, signature, exception_gchandle);
return delegates.create_delegate_proxy ((MonoObject *) mono_method_get_object (mono_domain_get (), method, NULL), delegate, signature, token_ref, exception_gchandle);
}
void
@ -2424,14 +2424,18 @@ xamarin_process_managed_exception (MonoObject *exception)
void
xamarin_throw_product_exception (int code, const char *message)
{
xamarin_process_managed_exception_gchandle (xamarin_create_product_exception (code, message));
}
guint32
xamarin_create_product_exception (int code, const char *message)
{
guint32 exception_gchandle = 0;
guint32 handle = xamarin_create_product_exception_for_error (code, message, &exception_gchandle);
if (exception_gchandle != 0) {
xamarin_process_managed_exception_gchandle (exception_gchandle);
} else {
xamarin_process_managed_exception_gchandle (handle);
}
if (exception_gchandle != 0)
return exception_gchandle;
return handle;
}
void

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

@ -60,7 +60,7 @@ xamarin_marshal_return_value (MonoType *mtype, const char *type, MonoObject *ret
case _C_PTR: {
MonoClass *klass = mono_class_from_mono_type (mtype);
if (mono_class_is_delegate (klass)) {
return xamarin_get_block_for_delegate (method, retval, NULL, exception_gchandle);
return xamarin_get_block_for_delegate (method, retval, NULL, INVALID_TOKEN_REF, exception_gchandle);
} else {
return *(void **) mono_object_unbox (retval);
}

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

@ -176,7 +176,7 @@ MonoType * xamarin_get_parameter_type (MonoMethod *managed_method, int index);
MonoObject * xamarin_get_nsobject_with_type_for_ptr (id self, bool owns, MonoType* type, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle);
MonoObject * xamarin_get_nsobject_with_type_for_ptr_created (id self, bool owns, MonoType *type, int32_t *created, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle);
int * xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref, int par, void *nativeBlock, guint32 *exception_gchandle);
id xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature /* NULL allowed, but requires the dynamic registrar at runtime to compute */, guint32 *exception_gchandle);
id xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature /* NULL allowed, but requires the dynamic registrar at runtime to compute */, guint32 token_ref /* INVALID_TOKEN_REF allowed, but requires the dynamic registrar at runtime */, guint32 *exception_gchandle);
id xamarin_get_nsobject_handle (MonoObject *obj);
void xamarin_set_nsobject_handle (MonoObject *obj, id handle);
uint8_t xamarin_get_nsobject_flags (MonoObject *obj);
@ -233,6 +233,7 @@ void xamarin_process_nsexception_using_mode (NSException *ns_exception, bool t
void xamarin_process_managed_exception (MonoObject *exc);
void xamarin_process_managed_exception_gchandle (guint32 gchandle);
void xamarin_throw_product_exception (int code, const char *message);
guint32 xamarin_create_product_exception (int code, const char *message);
NSString * xamarin_print_all_exceptions (MonoObject *exc);
id xamarin_invoke_objc_method_implementation (id self, SEL sel, IMP xamarin_impl);

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

@ -59,6 +59,7 @@ namespace Foundation {
public string Name { get; set; }
public string Selector { get; set; }
public Type ReturnType { get; set; }
public Type ReturnTypeDelegateProxy { get; set; }
public Type[] ParameterType { get; set; }
public bool[] ParameterByRef { get; set; }
public Type[] ParameterBlockProxy { get; set; }

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

@ -168,11 +168,7 @@ $(IOS_BUILD_DIR)/reference/System.Drawing.dll: $(IOS_SYSTEM_DRAWING_SOURCES) mon
$(IOS_SYSTEM_DRAWING_SOURCES)
$(IOS_BUILD_DIR)/reference/Xamarin.iOS.dll: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.dll | $(IOS_BUILD_DIR)/reference
@# Don't strip, btouch-native needs to execute code from Xamarin.iOS,
@# and that'll break if we strip out the code from the reference assembly.
@# Note that there is only btouch-native executable for both 32 and 64 bits.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(Q_GEN) mono-cil-strip $< $@
$(IOS_BUILD_DIR)/reference/Xamarin.iOS.pdb: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.pdb | $(IOS_BUILD_DIR)/reference
$(Q) cp $< $@
@ -753,11 +749,7 @@ $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS%dll $(WATCH_BUILD_DIR)/watch-32/Xama
$(WATCHOS_SOURCES) @$(WATCH_BUILD_DIR)/watch/generated_sources
$(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.dll: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.dll | $(WATCH_BUILD_DIR)/reference
@# Don't strip, bwatch needs to execute code from Xamarin.WatchOS (attributes),
@# and that'll break if we strip out the code from the reference assembly.
@# Note that there is only bwatch executable for both 32 and 64 bits.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(Q_GEN) mono-cil-strip $< $@
$(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.pdb: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.pdb | $(WATCH_BUILD_DIR)/reference
$(Q) cp $< $@
@ -966,10 +958,7 @@ $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS%dll $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVO
$(TVOS_SOURCES) @$(TVOS_BUILD_DIR)/tvos/generated_sources
$(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(TVOS_BUILD_DIR)/reference
@# Don't strip, btv needs to execute code from Xamarin.TVOS (attributes),
@# and that'll break if we strip out the code from the reference assembly.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(Q_GEN) mono-cil-strip $< $@
$(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(TVOS_BUILD_DIR)/reference
$(Q) cp $< $@
@ -1060,8 +1049,8 @@ TVOS_TARGETS += \
$(PROJECT_DIR)/MonoTouch.NUnitLite.tvos.csproj \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/OpenTK-1.0.dll \
@ -1088,10 +1077,10 @@ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/%.config: $(TVOS_BUILD_D
$(Q) install -m 0644 $< $@
# the actual architecture-specific versions
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits
$(Q) install -m 0755 $< $@
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits
$(Q) install -m 0644 $< $@
$(TVOS_TARGETS_DIRS):

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

@ -247,8 +247,50 @@ namespace ObjCRuntime {
return descriptor->copy_helper == ((BlockDescriptor *) literal->block_descriptor)->copy_helper;
}
[BindingImpl (BindingImplOptions.Optimizable)]
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, string signature)
static Type GetDelegateProxyType (MethodInfo minfo, uint token_ref, out MethodInfo baseMethod)
{
// A mirror of this method is also implemented in StaticRegistrar:GetDelegateProxyType
// If this method is changed, that method will probably have to be updated too (tests!!!)
baseMethod = null;
if (token_ref != Runtime.INVALID_TOKEN_REF)
return (Type) Class.ResolveTokenReference (token_ref, 0x02000000 /* TypeDef */);
baseMethod = minfo.GetBaseDefinition ();
var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
if (delegateProxies.Length > 0)
return ((DelegateProxyAttribute) delegateProxies [0]).DelegateType;
// We might be implementing a protocol, find any DelegateProxy attributes on the corresponding interface as well.
string selector = null;
foreach (var iface in minfo.DeclaringType.GetInterfaces ()) {
if (!iface.IsDefined (typeof (ProtocolAttribute), false))
continue;
var map = minfo.DeclaringType.GetInterfaceMap (iface);
for (int i = 0; i < map.TargetMethods.Length; i++) {
if (map.TargetMethods [i] == minfo) {
delegateProxies = map.InterfaceMethods [i].ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
if (delegateProxies.Length > 0)
return ((DelegateProxyAttribute) delegateProxies [0]).DelegateType;
}
}
// It might be an optional method/property, in which case we need to check any ProtocolMember attributes
if (selector == null)
selector = Runtime.GetExportAttribute (minfo)?.Selector ?? string.Empty;
if (!string.IsNullOrEmpty (selector)) {
var attrib = Runtime.GetProtocolMemberAttribute (iface, selector, minfo);
if (attrib?.ReturnTypeDelegateProxy != null)
return attrib.ReturnTypeDelegateProxy;
}
}
throw ErrorHelper.CreateError (8011, "Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {0}.{1}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
}
[BindingImpl(BindingImplOptions.Optimizable)]
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, uint token_ref, string signature)
{
if (@delegate == null)
return IntPtr.Zero;
@ -256,26 +298,22 @@ namespace ObjCRuntime {
if (!(@delegate is Delegate))
throw ErrorHelper.CreateError (8016, "Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.", minfo.DeclaringType.FullName, minfo.Name, @delegate.GetType ().FullName);
var baseMethod = minfo.GetBaseDefinition ();
var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
if (delegateProxies.Length == 0)
throw ErrorHelper.CreateError (8011, "Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {0}.{1}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
var delegateProxy = (DelegateProxyAttribute) delegateProxies [0];
if (delegateProxy.DelegateType == null)
Type delegateProxyType = GetDelegateProxyType (minfo, token_ref, out var baseMethod);
if (baseMethod == null)
baseMethod = minfo; // 'baseMethod' is only used in error messages, and if it's null, we just use the closest alternative we have (minfo).
if (delegateProxyType == null)
throw ErrorHelper.CreateError (8012, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
var delegateProxyField = delegateProxy.DelegateType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static);
var delegateProxyField = delegateProxyType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static);
if (delegateProxyField == null)
throw ErrorHelper.CreateError (8013, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType ({2}) specifies a type without a 'Handler' field. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName);
throw ErrorHelper.CreateError (8013, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType ({2}) specifies a type without a 'Handler' field. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName);
var handlerDelegate = delegateProxyField.GetValue (null);
if (handlerDelegate == null)
throw ErrorHelper.CreateError (8014, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName);
throw ErrorHelper.CreateError (8014, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName);
if (!(handlerDelegate is Delegate))
throw ErrorHelper.CreateError (8015, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName, handlerDelegate.GetType ().FullName);
throw ErrorHelper.CreateError (8015, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName, handlerDelegate.GetType ().FullName);
// We now have the information we need to create the block.
// Note that we must create a heap-allocated block, so we

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

@ -32,6 +32,7 @@ using ProductException=MonoMac.RuntimeException;
using ObjCRuntime;
#endif
#else
using System.Linq;
using Mono.Cecil.Cil;
#endif
@ -297,6 +298,26 @@ namespace ObjCRuntime {
Show (new ProductException (code, false, innerException, message, args));
}
#if MMP || MTOUCH
// Shows any warnings, and if there are any errors, throws an AggregateException.
public static void ThrowIfErrors (IList<Exception> exceptions)
{
if (exceptions?.Any () != true)
return;
// Separate warnings from errors
var grouped = exceptions.GroupBy ((v) => (v as ProductException)?.Error == false);
var warnings = grouped.SingleOrDefault ((v) => v.Key);
if (warnings?.Any () == true)
Show (warnings);
var errors = grouped.SingleOrDefault ((v) => !v.Key);
if (errors?.Any () == true)
throw new AggregateException (errors);
}
#endif
public static void Show (IEnumerable<Exception> list)
{
List<Exception> exceptions = new List<Exception> ();

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

@ -448,9 +448,9 @@ namespace ObjCRuntime {
return ObjectWrapper.Convert (CreateBlockProxy ((MethodInfo) ObjectWrapper.Convert (method), block));
}
static IntPtr CreateDelegateProxy (IntPtr method, IntPtr @delegate, IntPtr signature)
static IntPtr CreateDelegateProxy (IntPtr method, IntPtr @delegate, IntPtr signature, uint token_ref)
{
return BlockLiteral.GetBlockForDelegate ((MethodInfo) ObjectWrapper.Convert (method), ObjectWrapper.Convert (@delegate), Marshal.PtrToStringAuto (signature));
return BlockLiteral.GetBlockForDelegate ((MethodInfo) ObjectWrapper.Convert (method), ObjectWrapper.Convert (@delegate), token_ref, Marshal.PtrToStringAuto (signature));
}
static unsafe Assembly GetEntryAssembly ()
@ -777,6 +777,48 @@ namespace ObjCRuntime {
return null;
}
internal static ProtocolMemberAttribute GetProtocolMemberAttribute (Type type, string selector, MethodInfo method)
{
var memberAttributes = type.GetCustomAttributes<ProtocolMemberAttribute> ();
if (memberAttributes == null)
return null;
foreach (var attrib in memberAttributes) {
if (attrib.IsStatic != method.IsStatic)
continue;
if (attrib.Selector != selector)
continue;
if (!attrib.IsProperty) {
var methodParameters = method.GetParameters ();
if ((attrib.ParameterType?.Length ?? 0) != methodParameters.Length)
continue;
var notApplicable = false;
for (int i = 0; i < methodParameters.Length; i++) {
var paramType = methodParameters [i].ParameterType;
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
if (isByRef != attrib.ParameterByRef [i]) {
notApplicable = true;
break;
}
if (paramType != attrib.ParameterType [i]) {
notApplicable = true;
break;
}
}
if (notApplicable)
continue;
}
return attrib;
}
return null;
}
//
// Returns a MethodInfo that represents the method that can be used to turn
// a the block in the given method at the given parameter into a strongly typed
@ -825,39 +867,11 @@ namespace ObjCRuntime {
// We may run into binding assemblies built with earlier versions of the generator,
// which means we can't rely on finding the BlockProxy attribute in the ProtocolMemberAttribute.
if (selector == null)
selector = method.GetCustomAttribute<ExportAttribute> ()?.Selector ?? string.Empty;
selector = GetExportAttribute (method)?.Selector ?? string.Empty;
if (!string.IsNullOrEmpty (selector)) {
var memberAttributes = iface.GetCustomAttributes<ProtocolMemberAttribute> ();
foreach (var attrib in memberAttributes) {
if (attrib.ParameterBlockProxy == null || attrib.ParameterBlockProxy.Length <= parameter || attrib.ParameterBlockProxy [parameter] == null)
continue; // no need to check anything if what we want isn't there
if (attrib.Selector != selector)
continue;
if (attrib.IsStatic != method.IsStatic)
continue;
var methodParameters = method.GetParameters ();
if (attrib.ParameterType.Length != methodParameters.Length)
continue;
var notApplicable = false;
for (int i = 0; i < methodParameters.Length; i++) {
var paramType = methodParameters [i].ParameterType;
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
if (isByRef != attrib.ParameterByRef [i]) {
notApplicable = true;
break;
}
if (paramType != attrib.ParameterType [i]) {
notApplicable = true;
break;
}
}
if (notApplicable)
continue;
var attrib = GetProtocolMemberAttribute (iface, selector, method);
if (attrib != null && attrib.ParameterBlockProxy.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
return attrib.ParameterBlockProxy [parameter].GetMethod ("Create");
}
}
// Might be an implementation of an optional protocol member.
@ -1011,6 +1025,31 @@ namespace ObjCRuntime {
}
}
internal static PropertyInfo FindPropertyInfo (MethodInfo accessor)
{
if (!accessor.IsSpecialName)
return null;
foreach (var pi in accessor.DeclaringType.GetProperties ()) {
if (pi.GetGetMethod () == accessor)
return pi;
if (pi.GetSetMethod () == accessor)
return pi;
}
return null;
}
internal static ExportAttribute GetExportAttribute (MethodInfo method)
{
var attrib = method.GetCustomAttribute<ExportAttribute> ();
if (attrib == null) {
var pinfo = FindPropertyInfo (method);
if (pinfo != null)
attrib = pinfo.GetCustomAttribute<ExportAttribute> ();
}
return attrib;
}
static NSObject IgnoreConstructionError (IntPtr ptr, IntPtr klass, Type type)
{

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

@ -43,7 +43,7 @@ sdk=$(echo $sdk | tr '[:upper:]' '[:lower:]')
case $sdk in
mobile|xamarin.mac|xammac)
bmac="bmac-mobile.exe -no-mono-path"
mono=$ROOT_DIR/bin/bmac-mobile-mono
mono=/Library/Frameworks/Mono.framework/Commands/mono
export MONO_PATH=$ROOT_DIR/lib/mono/Xamarin.Mac
;;
*)
@ -60,7 +60,6 @@ mobile|xamarin.mac|xammac)
refs="-baselib:$ROOT_DIR/lib/reference/mobile/Xamarin.Mac.dll --target-framework=Xamarin.Mac,Version=v2.0,Profile=Mobile"
bmac=bmac-mobile.exe
export MONO_PATH=$ROOT_DIR/lib/mono/Xamarin.Mac
mono="$ROOT_DIR/bin/bmac-mobile-mono"
fi
fi
;;

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

@ -7519,6 +7519,9 @@ namespace Foundation
[Static]
[Export ("dictionaryWithSharedKeySet:")]
NSDictionary FromSharedKeySet (NSObject sharedKeyToken);
[Export ("addEntriesFromDictionary:")]
void AddEntries (NSDictionary other);
}
[BaseType (typeof (NSSet))]

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

@ -4778,6 +4778,7 @@ public partial class Generator : IMemberGatherer {
sel = ba.Selector;
}
PrintBlockProxy (pi.PropertyType);
PrintAttributes (pi, platform:true);
if (not_implemented_attr == null && (!minfo.is_sealed || !minfo.is_wrapper))
@ -5101,6 +5102,15 @@ public partial class Generator : IMemberGatherer {
}
}
void PrintBlockProxy (Type type)
{
type = GetCorrectGenericType (type);
if (type.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (type);
print ("[param: BlockProxy (typeof ({0}.Trampolines.{1}))]", ns.CoreObjCRuntime, ti.NativeInvokerName);
}
}
void PrintExport (MemberInformation minfo)
{
if (minfo.is_export)
@ -5418,8 +5428,14 @@ public partial class Generator : IMemberGatherer {
sb.Append (", IsStatic = ").Append (AttributeManager.HasAttribute<StaticAttribute> (mi) ? "true" : "false");
sb.Append (", Name = \"").Append (mi.Name).Append ("\"");
sb.Append (", Selector = \"").Append (attrib.Selector).Append ("\"");
if (mi.ReturnType != TypeManager.System_Void)
sb.Append (", ReturnType = typeof (").Append (RenderType (GetCorrectGenericType (mi.ReturnType))).Append(")");
if (mi.ReturnType != TypeManager.System_Void) {
var retType = GetCorrectGenericType (mi.ReturnType);
sb.Append (", ReturnType = typeof (").Append (RenderType (retType)).Append (")");
if (retType.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (retType);
sb.Append ($", ReturnTypeDelegateProxy = typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.StaticName})");
}
}
var parameters = mi.GetParameters ();
if (parameters != null && parameters.Length > 0) {
sb.Append (", ParameterType = new Type [] { ");
@ -5489,6 +5505,15 @@ public partial class Generator : IMemberGatherer {
sb.Append (", SetterSelector = \"").Append (ba != null ? ba.Selector : ea.Selector).Append ("\"");
}
sb.Append (", ArgumentSemantic = ArgumentSemantic.").Append (attrib.ArgumentSemantic);
// Check for block/delegate proxies
var propType = GetCorrectGenericType (pi.PropertyType);
if (propType.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (propType);
if (pi.SetMethod != null)
sb.Append ($", ParameterBlockProxy = new Type [] {{ typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.NativeInvokerName}) }}");
if (pi.GetMethod != null)
sb.Append ($", ReturnTypeDelegateProxy = typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.StaticName})");
}
sb.Append (")]");
print (sb.ToString ());
}
@ -5565,6 +5590,7 @@ public partial class Generator : IMemberGatherer {
}
if (pi.CanWrite) {
var setMethod = pi.GetSetMethod ();
PrintBlockProxy (pi.PropertyType);
PrintAttributes (setMethod, notImplemented:true);
if (!AttributeManager.HasAttribute<NotImplementedAttribute> (setMethod))
PrintExport (minfo, GetSetterExportAttribute (pi));

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

@ -360,7 +360,7 @@ namespace HealthKit {
// FIXME NS_EXTENSION_UNAVAILABLE("Not available to extensions") ;
[Async]
[Export ("requestAuthorizationToShareTypes:readTypes:completion:")]
void RequestAuthorizationToShare (NSSet typesToShare, NSSet typesToRead, Action<bool, NSError> completion);
void RequestAuthorizationToShare ([NullAllowed] NSSet typesToShare, [NullAllowed] NSSet typesToRead, Action<bool, NSError> completion);
// FIXME NS_EXTENSION_UNAVAILABLE("Not available to extensions") ;
[Async]

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

@ -289,6 +289,22 @@ namespace Bindings.Test {
[Static]
[Export ("optionalStaticCallback:")]
void OptionalStaticCallback (Action<int> completionHandler);
[Abstract]
[Export ("requiredReturnValue")]
Action<int> RequiredReturnValue ();
[Abstract]
[Static]
[Export ("requiredStaticReturnValue")]
Action<int> RequiredStaticReturnValue ();
[Export ("optionalReturnValue")]
Action<int> OptionalReturnValue ();
[Static]
[Export ("optionalStaticReturnValue")]
Action<int> OptionalStaticReturnValue ();
}
interface IObjCProtocolBlockTest { }
@ -339,6 +355,23 @@ namespace Bindings.Test {
[Static]
[Export ("freedBlockCount")]
int FreedBlockCount { get; }
[Static]
[Export ("calledBlockCount")]
int CalledBlockCount { get; }
[Static]
[Export ("callProtocolWithBlockProperties:required:instance:")]
void CallProtocolWithBlockProperties (IProtocolWithBlockProperties obj, bool required, bool instance);
[Static]
[Export ("callProtocolWithBlockReturnValue:required:instance:")]
void CallProtocolWithBlockReturnValue (IObjCProtocolBlockTest obj, bool required, bool instance);
[Static]
[Export ("setProtocolWithBlockProperties:required:instance:")]
void SetProtocolWithBlockProperties (IProtocolWithBlockProperties obj, bool required, bool instance);
}
delegate void InnerBlock (int magic_number);
@ -350,6 +383,28 @@ namespace Bindings.Test {
[Export ("evilCallback")]
Action<int> EvilCallback { get; set; }
}
delegate void SimpleCallback ();
[BaseType (typeof (NSObject))]
[Protocol]
interface ProtocolWithBlockProperties {
[Abstract]
[Export ("myRequiredProperty")]
SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalProperty")]
SimpleCallback MyOptionalProperty { get; set; }
[Static]
[Abstract]
[Export ("myRequiredStaticProperty")]
SimpleCallback MyRequiredStaticProperty { get; set; }
[Static]
[Export ("myOptionalStaticProperty")]
SimpleCallback MyOptionalStaticProperty { get; set; }
}
interface IProtocolWithBlockProperties { }
}

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

@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace ObjCRuntime {
public static class Messaging {
internal const string LIBOBJC_DYLIB = "/usr/lib/libobjc.dylib";
public struct objc_super {
public IntPtr Handle;
public IntPtr SuperHandle;
}
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr_bool_bool (IntPtr receiver, IntPtr selector, IntPtr a, bool b, bool c);
}
}

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

@ -65,6 +65,37 @@ namespace Xamarin.BindingTests
{
completionHandler (42);
}
public Action<int> RequiredReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalReturnValue")]
public Action<int> OptionalReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("requiredStaticReturnValue")]
public static Action<int> RequiredStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalStaticReturnValue")]
public static Action<int> OptionalStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
}
class BlockCallbackClassExplicit : NSObject, IObjCProtocolBlockTest
@ -92,6 +123,38 @@ namespace Xamarin.BindingTests
{
completionHandler (42);
}
// Explicitly implemented interface member
Action<int> IObjCProtocolBlockTest.RequiredReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalReturnValue")]
public Action<int> OptionalReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("requiredStaticReturnValue")]
public static Action<int> RequiredStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalStaticReturnValue")]
public static Action<int> OptionalStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
}
public class BlockCallbackTester : ObjCBlockTester
@ -101,5 +164,130 @@ namespace Xamarin.BindingTests
completionHandler (42);
}
}
public class PropertyBlock : NSObject, IProtocolWithBlockProperties {
[Export ("myOptionalProperty")]
public SimpleCallback MyOptionalProperty { get; set; }
public SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalStaticProperty")]
public static SimpleCallback MyOptionalStaticProperty { get; set; }
[Export ("myRequiredStaticProperty")]
public static SimpleCallback MyRequiredStaticProperty { get; set; }
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithBlockProperties (bool required, bool instance)
{
using (var pb = new PropertyBlock ()) {
var callbackCalled = false;
SimpleCallback action = () => {
callbackCalled = true;
};
if (required) {
if (instance) {
pb.MyRequiredProperty = action;
} else {
PropertyBlock.MyRequiredStaticProperty = action;
}
} else {
if (instance) {
pb.MyOptionalProperty = action;
} else {
PropertyBlock.MyOptionalStaticProperty = action;
}
}
ObjCBlockTester.CallProtocolWithBlockProperties (pb, required, instance);
Assert.IsTrue (callbackCalled, "Callback");
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithNativeBlockProperties (bool required, bool instance)
{
using (var pb = new PropertyBlock ()) {
var calledCounter = ObjCBlockTester.CalledBlockCount;
ObjCBlockTester.SetProtocolWithBlockProperties (pb, required, instance);
if (required) {
if (instance) {
pb.MyRequiredProperty ();
} else {
PropertyBlock.MyRequiredStaticProperty ();
}
} else {
if (instance) {
pb.MyOptionalProperty ();
} else {
PropertyBlock.MyOptionalStaticProperty ();
}
}
Assert.AreEqual (calledCounter + 1, ObjCBlockTester.CalledBlockCount, "Blocks called");
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithReturnValues (bool required, bool instance)
{
using (var pb = new BlockCallbackClass ()) {
ObjCBlockTester.CallProtocolWithBlockReturnValue (pb, required, instance);
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void LinkedAway (bool required, bool instance)
{
if (!(TestRuntime.IsLinkAll && TestRuntime.IsOptimizeAll))
Assert.Ignore ("This test is only applicable if optimized & linking all assemblies.");
using (var pb = new FakePropertyBlock ()) {
try {
Messaging.void_objc_msgSend_IntPtr_bool_bool (Class.GetHandle (typeof (ObjCBlockTester)), Selector.GetHandle ("setProtocolWithBlockProperties:required:instance:"), pb.Handle, required, instance);
Assert.Fail ("Expected an MT8028 error");
} catch (RuntimeException re) {
Assert.AreEqual (8028, re.Code, "Code");
Assert.AreEqual ("The runtime function get_block_wrapper_creator has been linked away.", re.Message, "Message");
}
}
}
// Each method here will show a warning like this:
// MT4174: Unable to locate the block to delegate conversion method for the method ...
// This is expected.
// This is 'fake' because it doesn't implement the ProtocolWithBlockProperties protocol,
// which means that XI won't be able to find the delegate<->block conversion methods
// (either at runtime or build time).
// The point of this test is to ensure that we don't crash when the runtime tries
// to find those conversion methods, and instead finds that many required functions
// have been linked away (which happen when _forcing_ the dynamic registrar to be linked away).
public class FakePropertyBlock : NSObject {
[Export ("myOptionalProperty")]
public SimpleCallback MyOptionalProperty { get; set; }
[Export ("myRequiredProperty")]
public SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalStaticProperty")]
public static SimpleCallback MyOptionalStaticProperty { get; set; }
[Export ("myRequiredStaticProperty")]
public static SimpleCallback MyRequiredStaticProperty { get; set; }
}
}
}

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

@ -59,6 +59,11 @@ namespace Xamarin.Tests
[Test]
public void MainThreadDeallocationTest ()
{
#if OPTIMIZEALL
if (!TestRuntime.IsLinkAll)
Assert.Ignore ("This test must be processed by the linker if all optimizations are turned on.");
#endif
ObjCBlockTester.CallAssertMainThreadBlockRelease ((callback) => {
callback (42);
});

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

@ -68,6 +68,7 @@
</Compile>
<Compile Include="RuntimeTest.cs" />
<Compile Include="CodeBehind.cs" />
<Compile Include="Messaging.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\tests\test-libraries\libtest.m">

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

@ -80,6 +80,7 @@
</Compile>
<Compile Include="RuntimeTest.cs" />
<Compile Include="CodeBehind.cs" />
<Compile Include="Messaging.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\tests\test-libraries\libtest.m">

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

@ -259,8 +259,11 @@ class D : NSObject {
bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.Delegate in the method D.D4 because System.Delegate doesn't have a specific signature.", "testApp.cs", 24);
bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.MulticastDelegate in the method D.D5 because System.MulticastDelegate doesn't have a specific signature.", "testApp.cs", 30);
bundler.AssertWarning (4174, "Unable to locate the block to delegate conversion method for the method D.D3's parameter #1.", "testApp.cs", 18);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D4.", "testApp.cs", 24);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D5.", "testApp.cs", 30);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D6.", "testApp.cs", 36);
bundler.AssertErrorCount (2);
bundler.AssertWarningCount (3);
bundler.AssertWarningCount (6);
}
}

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

@ -74,6 +74,7 @@ namespace Xamarin.Tests
public int Verbosity;
public int [] WarnAsError; // null array: nothing passed to mtouch/mmp. empty array: pass --warnaserror (which means makes all warnings errors).
public string [] XmlDefinitions;
public string Interpreter;
// These are a bit smarter
public bool NoPlatformAssemblyReference;
@ -291,7 +292,12 @@ namespace Xamarin.Tests
sb.Append (" --xml:").Append (StringUtils.Quote (xd));
}
if (Interpreter != null) {
if (Interpreter.Length == 0)
sb.Append (" --interpreter");
else
sb.Append (" --interpreter=").Append (Interpreter);
}
}
public string CreateTemporaryDirectory ()

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

@ -655,4 +655,14 @@ partial class TestRuntime
}
}
class LinkerSentinel { }
public static bool IsOptimizeAll {
get {
#if OPTIMIZEALL
return true;
#else
return false;
#endif
}
}
}

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

@ -645,6 +645,53 @@ namespace MonoTouchFixtures.Foundation {
Assert.Throws<InvalidCastException> (() => GC.KeepAlive (dictK.Keys), "K Keys");
Assert.Throws<InvalidCastException> (() => dictK.KeysForObject (kv), "K KeysForObject");
}
[Test]
public void AddEntries ()
{
using (var dic1 = new NSMutableDictionary<NSString, NSDate> ()) {
var now = NSDate.Now;
using (var dic2 = NSDictionary.FromObjectAndKey ((NSDate) now, (NSString) "key")) {
Assert.AreEqual (0, dic1.Count, "Count 0");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "Count 1");
Assert.AreEqual (now, dic1 ["key"], "Value 1");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "Count 2");
Assert.AreEqual (now, dic1 ["key"], "Value 2");
}
// Be nasty, and put something of the wrong type in the dictionary
dic1.Clear ();
using (var dic2 = NSDictionary.FromObjectAndKey ((NSString) "value", (NSString) "key")) {
Assert.AreEqual (0, dic1.Count, "X Count 0");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "X Count 1");
Assert.Throws<InvalidCastException> (() =>
{
var obj = dic1 [(NSString) "key"];
}, "ICE 1");
}
// Use a generic dict of the right types
dic1.Clear ();
using (var dic2 = new NSDictionary<NSString,NSDate> ((NSString) "key2", now.AddSeconds (3600))) {
Assert.AreEqual (0, dic1.Count, "Y Count 0");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "Y Count 1");
var obj = dic1 [(NSString) "key2"];
Assert.AreEqual (now.AddSeconds (3600).SecondsSinceReferenceDate, obj.SecondsSinceReferenceDate, "Y Value 1");
}
}
}
}
}

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

@ -93,5 +93,25 @@ namespace monotouchtest
Assert.NotNull (testDict ["Key2"], "Key2");
}
}
[Test]
public void AddEntries ()
{
using (var dic1 = new NSMutableDictionary ()) {
using (var dic2 = NSDictionary.FromObjectAndKey ((NSString) "value", (NSString) "key")) {
Assert.AreEqual (0, dic1.Count, "Count 0");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "Count 1");
Assert.AreEqual ("value", dic1 ["key"].ToString (), "Value 1");
dic1.AddEntries (dic2);
Assert.AreEqual (1, dic1.Count, "Count 2");
Assert.AreEqual ("value", dic1 ["key"].ToString (), "Value 2");
}
}
}
}
}

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

@ -1780,6 +1780,25 @@ public class B
}
}
[Test]
public void MT0138 ()
{
using (var mtouch = new MTouchTool ()) {
var tmpdir = mtouch.CreateTemporaryDirectory ();
mtouch.CreateTemporaryCacheDirectory ();
mtouch.CreateTemporaryApp ();
mtouch.WarnAsError = new int [] { 138 }; // This is just to make mtouch bail out early instead of spending time building the app when that's not what we're interested in.
mtouch.Interpreter = "all,-all,foo,-bar,mscorlib.dll,mscorlib";
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
mtouch.AssertError (138, "Cannot find the assembly 'foo', passed as an argument to --interpreter.");
mtouch.AssertError (138, "Cannot find the assembly 'bar', passed as an argument to --interpreter.");
mtouch.AssertError (138, "Cannot find the assembly 'mscorlib.dll', passed as an argument to --interpreter.");
// just the name, without the extension, is the right way.
mtouch.AssertErrorCount (3);
}
}
[Test]
[TestCase ("all")]
[TestCase ("-all")]

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

@ -1182,6 +1182,45 @@ namespace NS {
}
}
[Test]
public void MT4176 ()
{
using (var mtouch = new MTouchTool ()) {
var code = @"
namespace NS {
using System;
using Foundation;
using ObjCRuntime;
public class Consumer : NSObject
{
[Export (""getAction"")]
public Action GetFunction ()
{
throw new NotImplementedException ();
}
[Export (""getProperty"")]
public Action GetProperty {
get {
throw new NotImplementedException ();
}
}
}
}
";
mtouch.Linker = MTouchLinker.DontLink; // faster
mtouch.Registrar = MTouchRegistrar.Static;
mtouch.CreateTemporaryApp (extraCode: code, extraArg: "-debug");
mtouch.WarnAsError = new int [] { 4176 };
mtouch.AssertExecuteFailure ("build");
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.GetFunction.", "testApp.cs", 11);
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.get_GetProperty.", "testApp.cs", 17);
mtouch.AssertErrorCount (2);
}
}
[Test]
public void NoWarnings ()
{

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

@ -148,15 +148,29 @@ typedef unsigned int (^RegistrarTestBlock) (unsigned int magic);
-(void) idAsIntPtr: (id)p1;
@end
typedef void (^int_callback)(int32_t magic_number);
@protocol ObjCProtocolBlockTest
@required
-(void) requiredCallback: (void (^)(int32_t magic_number))completionHandler;
+(void) requiredStaticCallback: (void (^)(int32_t magic_number))completionHandler;
-(void) requiredCallback: (int_callback)completionHandler;
+(void) requiredStaticCallback: (int_callback)completionHandler;
-(int_callback) requiredReturnValue;
+(int_callback) requiredStaticReturnValue;
@optional
-(void) optionalCallback: (void (^)(int32_t magic_number))completionHandler;
+(void) optionalStaticCallback: (void (^)(int32_t magic_number))completionHandler;
-(void) optionalCallback: (int_callback)completionHandler;
+(void) optionalStaticCallback: (int_callback)completionHandler;
-(int_callback) optionalReturnValue;
+(int_callback) optionalStaticReturnValue;
@end
typedef void (^simple_callback)();
@protocol ProtocolWithBlockProperties
@required
@property simple_callback myRequiredProperty;
@property (class) simple_callback myRequiredStaticProperty;
@optional
@property simple_callback myOptionalProperty;
@property (class) simple_callback myOptionalStaticProperty;
@end
@interface ObjCBlockTester : NSObject {
}
@property (retain) NSObject<ObjCProtocolBlockTest>* TestObject;
@ -175,6 +189,12 @@ typedef void (^outerBlock) (innerBlock callback);
-(void) testFreedBlocks;
+(int) freedBlockCount;
+(void) callProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
+(void) callProtocolWithBlockReturnValue: (id<ObjCProtocolBlockTest>) obj required: (bool) required instance: (bool) instance;
+(void) setProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
+(int) calledBlockCount;
@end
@interface FreedNotifier : NSObject {

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

@ -527,6 +527,7 @@ static UltimateMachine *shared;
@end
static volatile int freed_blocks = 0;
static volatile int called_blocks = 0;
@implementation ObjCBlockTester
static Class _TestClass = NULL;
@ -654,6 +655,73 @@ static Class _TestClass = NULL;
{
return freed_blocks;
}
+(int) calledBlockCount
{
return called_blocks;
}
static void block_called ()
{
OSAtomicIncrement32 (&called_blocks);
}
+(void) callProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
{
if (required) {
if (instance) {
obj.myRequiredProperty ();
} else {
[[(NSObject *) obj class] myRequiredStaticProperty] ();
}
} else {
if (instance) {
obj.myOptionalProperty ();
} else {
[[(NSObject *) obj class] myOptionalStaticProperty] ();
}
}
}
+(void) callProtocolWithBlockReturnValue: (id<ObjCProtocolBlockTest>) obj required: (bool) required instance: (bool) instance;
{
if (required) {
if (instance) {
[obj requiredReturnValue] (42);
} else {
[[(NSObject *) obj class] requiredStaticReturnValue] (42);
}
} else {
if (instance) {
[obj optionalReturnValue] (42);
} else {
[[(NSObject *) obj class] optionalStaticReturnValue] (42);
}
}
}
+(void) callProtocolWithBlockPropertiesRequired: (id<ProtocolWithBlockProperties>) obj
{
obj.myRequiredProperty ();
}
+(void) setProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance
{
simple_callback callback = ^{ block_called (); };
if (required) {
if (instance) {
obj.myRequiredProperty = callback;
} else {
[[(NSObject *) obj class] setMyRequiredStaticProperty: callback];
}
} else {
if (instance) {
obj.myOptionalProperty = callback;
} else {
[[(NSObject *) obj class] setMyOptionalStaticProperty: callback];
}
}
}
@end
@implementation FreedNotifier

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

@ -182,12 +182,15 @@ namespace xharness
yield return new TestData { Variation = "Release (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all", Debug = false, Profiling = false, Defines = "OPTIMIZEALL" };
yield return new TestData { Variation = "Debug (all optimizations)", MTouchExtraArgs = "--registrar:static --optimize:all", Debug = true, Profiling = false, Defines = "OPTIMIZEALL" };
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Ignored = true, };
yield return new TestData { Variation = "Debug (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = true, Profiling = false, Ignored = true, };
break;
case "mscorlib":
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Ignored = true, Undefines = "FULL_AOT_RUNTIME" };
yield return new TestData { Variation = "Debug (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = true, Profiling = false, Ignored = true, Undefines = "FULL_AOT_RUNTIME" };
break;
case "mini":
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME" };
yield return new TestData { Variation = "Debug (interpreter -mscorlib)", MTouchExtraArgs = "--interpreter=-mscorlib", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME" };
break;
}
break;
@ -2708,7 +2711,7 @@ function toggleAll (show)
xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null;
LogEvent (log, "Building {0} ({1})", TestName, Mode);
if (!Harness.DryRun) {
var timeout = TimeSpan.FromMinutes (15);
var timeout = TimeSpan.FromMinutes (60);
var result = await xbuild.RunAsync (log, true, timeout);
if (result.TimedOut) {
ExecutionResult = TestExecutingResult.TimedOut;

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

@ -366,6 +366,15 @@ namespace xharness
}
}
public override StreamReader GetReader ()
{
if (File.Exists (CapturePath)) {
return new StreamReader (new FileStream (CapturePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
} else {
return new StreamReader (new MemoryStream ());
}
}
public override void Flush ()
{
base.Flush ();

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

@ -380,6 +380,11 @@ namespace xharness
return string.Empty;
}
public static string GetMtouchLink (this XmlDocument csproj, string platform, string configuration)
{
return GetNode (csproj, "MtouchLink", platform, configuration);
}
public static void SetMtouchUseLlvm (this XmlDocument csproj, bool value, string platform, string configuration)
{
SetNode (csproj, "MtouchUseLlvm", true ? "true" : "false", platform, configuration);
@ -390,6 +395,17 @@ namespace xharness
SetNode (csproj, "MtouchEnableBitcode", true ? "true" : "false", platform, configuration);
}
public static IEnumerable<XmlNode> GetPropertyGroups (this XmlDocument csproj, string platform, string configuration)
{
var propertyGroups = csproj.SelectNodes ("//*[local-name() = 'PropertyGroup' and @Condition]");
foreach (XmlNode node in propertyGroups) {
if (!EvaluateCondition (node, platform, configuration))
continue;
yield return node;
}
}
public static void SetNode (this XmlDocument csproj, string node, string value, string platform, string configuration)
{
var projnode = csproj.SelectElementNodes (node);
@ -417,6 +433,16 @@ namespace xharness
}
}
public static string GetNode (this XmlDocument csproj, string name, string platform, string configuration)
{
foreach (var pg in GetPropertyGroups (csproj, platform, configuration)) {
foreach (XmlNode node in pg.ChildNodes)
if (node.Name == name)
return node.InnerText;
}
return null;
}
public static string GetImport (this XmlDocument csproj)
{

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

@ -84,6 +84,13 @@ namespace xharness
csproj.SetMtouchUseBitcode (true, "iPhone", "Release");
csproj.SetMtouchUseLlvm (true, "iPhone", "Release");
// Not linking a watch extensions requires passing -Os to the native compiler.
// https://github.com/mono/mono/issues/9867
var configurations = new string [] { "Debug", "Debug32", "Release", "Release32", "Release-bitcode" };
foreach (var c in configurations)
if (csproj.GetMtouchLink ("iPhone", c) == "None")
csproj.AddExtraMtouchArgs ("--gcc_flags=-Os", "iPhone", c);
Harness.Save (csproj, WatchOSExtensionProjectPath);
WatchOSExtensionGuid = csproj.GetProjectGuid ();

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

@ -630,7 +630,6 @@
!missing-selector! NSMutableArray::sortWithOptions:usingComparator: not bound
!missing-selector! NSMutableData::increaseLengthBy: not bound
!missing-selector! NSMutableData::initWithLength: not bound
!missing-selector! NSMutableDictionary::addEntriesFromDictionary: not bound
!missing-selector! NSMutableDictionary::initWithCapacity: not bound
!missing-selector! NSMutableDictionary::removeObjectsForKeys: not bound
!missing-selector! NSMutableDictionary::setDictionary: not bound

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

@ -63,7 +63,6 @@ namespace Xamarin.Bundler {
public bool? EnableCoopGC;
public bool EnableSGenConc;
public bool UseInterpreter;
public MarshalObjectiveCExceptionMode MarshalObjectiveCExceptions;
public MarshalManagedExceptionMode MarshalManagedExceptions;

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

@ -1397,12 +1397,64 @@ namespace Registrar {
return rv;
}
public DelegateProxyAttribute GetDelegateProxyAttribute (MethodDefinition method)
{
if (!TryGetAttribute (method.MethodReturnType, ObjCRuntime, "DelegateProxyAttribute", out var attrib))
return null;
var rv = new DelegateProxyAttribute ();
switch (attrib.ConstructorArguments.Count) {
case 1:
rv.DelegateType = ((TypeReference) attrib.ConstructorArguments [0].Value).Resolve ();
break;
default:
throw ErrorHelper.CreateError (4124, "Invalid DelegateProxyAttribute found on '{0}'. Please file a bug report at https://bugzilla.xamarin.com", ((MethodReference) method)?.FullName);
}
return rv;
}
protected override string PlatformName {
get {
return App.PlatformName;
}
}
ProtocolMemberAttribute GetProtocolMemberAttribute (TypeReference type, string selector, ObjCMethod obj_method, MethodDefinition method)
{
var memberAttributes = GetProtocolMemberAttributes (type);
foreach (var attrib in memberAttributes) {
if (attrib.IsStatic != method.IsStatic)
continue;
if (attrib.IsProperty) {
if (method.IsSetter && attrib.SetterSelector != selector)
continue;
else if (method.IsGetter && attrib.GetterSelector != selector)
continue;
} else {
if (attrib.Selector != selector)
continue;
}
if (!obj_method.IsPropertyAccessor) {
var attribParameters = new TypeReference [attrib.ParameterType?.Length ?? 0];
for (var i = 0; i < attribParameters.Length; i++) {
attribParameters [i] = attrib.ParameterType [i];
if (attrib.ParameterByRef [i])
attribParameters [i] = new ByReferenceType (attribParameters [i]);
}
if (!ParametersMatch (method.Parameters, attribParameters))
continue;
}
return attrib;
}
return null;
}
protected override IEnumerable<ProtocolMemberAttribute> GetProtocolMemberAttributes (TypeReference type)
{
var td = type.Resolve ();
@ -1434,6 +1486,9 @@ namespace Registrar {
case "ReturnType":
rv.ReturnType = (TypeReference)prop.Argument.Value;
break;
case "ReturnTypeDelegateProxy":
rv.ReturnTypeDelegateProxy = (TypeReference) prop.Argument.Value;
break;
case "ParameterType":
if (prop.Argument.Value != null) {
var arr = (CustomAttributeArgument[])prop.Argument.Value;
@ -3071,8 +3126,7 @@ namespace Registrar {
sb.WriteLine (map.ToString ());
sb.WriteLine (map_init.ToString ());
if (exceptions.Count > 0)
throw new AggregateException (exceptions);
ErrorHelper.ThrowIfErrors (exceptions);
}
static bool HasIntPtrBoolCtor (TypeDefinition type)
@ -3680,7 +3734,7 @@ namespace Registrar {
if (creatorMethod != null) {
token = $"0x{CreateTokenReference (creatorMethod, TokenType.Method):X} /* {creatorMethod.FullName} */ ";
} else {
ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4174, method.Method, "Unable to locate the block to delegate conversion method for the method {0}'s parameter #{1}.",
exceptions.Add (ErrorHelper.CreateWarning (App, 4174, method.Method, "Unable to locate the block to delegate conversion method for the method {0}'s parameter #{1}.",
method.DescriptiveMethodName, i + 1));
}
}
@ -3832,6 +3886,7 @@ namespace Registrar {
setup_return.AppendLine ("res = nsstr;");
} else if (IsDelegate (type.Resolve ())) {
var signature = "NULL";
var token = "INVALID_TOKEN_REF";
if (App.Optimizations.OptimizeBlockLiteralSetupBlock == true) {
if (type.Is ("System", "Delegate") || type.Is ("System", "MulticastDelegate")) {
ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4173, method.Method, $"The registrar can't compute the block signature for the delegate of type {type.FullName} in the method {descriptiveMethodName} because {type.FullName} doesn't have a specific signature."));
@ -3843,8 +3898,14 @@ namespace Registrar {
signature = "\"" + ComputeSignature (method.DeclaringType.Type, null, method, isBlockSignature: true) + "\"";
}
}
var delegateProxyType = GetDelegateProxyType (method);
if (delegateProxyType != null) {
token = $"0x{CreateTokenReference (delegateProxyType, TokenType.TypeDef):X} /* {delegateProxyType.FullName} */ ";
} else {
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));
}
}
setup_return.AppendLine ("res = xamarin_get_block_for_delegate (managed_method, retval, {0}, &exception_gchandle);", signature);
setup_return.AppendLine ("res = xamarin_get_block_for_delegate (managed_method, retval, {0}, {1}, &exception_gchandle);", signature, token);
setup_return.AppendLine ("if (exception_gchandle != 0) goto exception_handling;");
} else {
throw ErrorHelper.CreateError (4104,
@ -4049,6 +4110,52 @@ namespace Registrar {
}
}
TypeDefinition GetDelegateProxyType (ObjCMethod obj_method)
{
// A mirror of this method is also implemented in BlockLiteral:GetDelegateProxyType
// If this method is changed, that method will probably have to be updated too (tests!!!)
MethodDefinition method = obj_method.Method;
MethodDefinition first = method;
MethodDefinition last = null;
while (method != last) {
last = method;
var delegateProxyType = GetDelegateProxyAttribute (method);
if (delegateProxyType?.DelegateType != null)
return delegateProxyType.DelegateType;
method = GetBaseMethodInTypeHierarchy (method);
}
// Might be the implementation of an interface method, so find the corresponding
// MethodDefinition for the interface, and check for DelegateProxy attributes there as well.
var map = PrepareMethodMapping (first.DeclaringType);
if (map != null && map.TryGetValue (first, out var list)) {
if (list.Count != 1)
throw Shared.GetMT4127 (first, list);
var delegateProxyType = GetDelegateProxyAttribute (list [0]);
if (delegateProxyType?.DelegateType != null)
return delegateProxyType.DelegateType;
}
// Might be an implementation of an optional protocol member.
if (obj_method.DeclaringType.Protocols != null) {
string selector = null;
foreach (var proto in obj_method.DeclaringType.Protocols) {
// We store the DelegateProxy type in the ProtocolMemberAttribute, so check those.
if (selector == null)
selector = obj_method.Selector ?? string.Empty;
if (selector != null) {
var attrib = GetProtocolMemberAttribute (proto.Type, selector, obj_method, method);
if (attrib?.ReturnTypeDelegateProxy != null)
return attrib.ReturnTypeDelegateProxy.Resolve ();
}
}
}
return null;
}
MethodDefinition GetBlockWrapperCreator (ObjCMethod obj_method, int parameter)
{
// A mirror of this method is also implemented in Runtime:GetBlockWrapperCreator
@ -4087,48 +4194,35 @@ namespace Registrar {
if (selector == null)
selector = obj_method.Selector ?? string.Empty;
if (selector != null) {
var memberAttributes = GetProtocolMemberAttributes (proto.Type);
foreach (var attrib in memberAttributes) {
if (attrib.ParameterBlockProxy == null || attrib.ParameterBlockProxy.Length <= parameter || attrib.ParameterBlockProxy [parameter] == null)
continue; // no need to check anything if what we want isn't there
if (attrib.Selector != selector)
continue;
if (attrib.IsStatic != method.IsStatic)
continue;
var attribParameters = new TypeReference [attrib.ParameterType?.Length ?? 0];
for (var i = 0; i < attribParameters.Length; i++) {
attribParameters [i] = attrib.ParameterType [i];
if (attrib.ParameterByRef [i])
attribParameters [i] = new ByReferenceType (attribParameters [i]);
}
if (!ParametersMatch (method.Parameters, attribParameters))
continue;
var attrib = GetProtocolMemberAttribute (proto.Type, selector, obj_method, method);
if (attrib?.ParameterBlockProxy?.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
return attrib.ParameterBlockProxy [parameter].Resolve ().Methods.First ((v) => v.Name == "Create");
}
if (proto.Methods != null) {
foreach (var pMethod in proto.Methods) {
if (!pMethod.IsOptional)
continue;
if (pMethod.Name != method.Name)
continue;
if (!TypeMatch (pMethod.ReturnType, method.ReturnType))
continue;
if (ParametersMatch (method.Parameters, pMethod.Parameters))
continue;
MethodDefinition extensionMethod = pMethod.Method;
if (extensionMethod == null) {
MapProtocolMember (obj_method.Method, out extensionMethod);
if (extensionMethod == null)
return null;
}
var createMethod = GetBlockProxyAttributeMethod (extensionMethod, parameter + 1);
if (createMethod != null)
return createMethod;
}
}
foreach (var pMethod in proto.Methods) {
if (!pMethod.IsOptional)
continue;
if (pMethod.Name != method.Name)
continue;
if (!TypeMatch (pMethod.ReturnType, method.ReturnType))
continue;
if (ParametersMatch (method.Parameters, pMethod.Parameters))
continue;
MethodDefinition extensionMethod = pMethod.Method;
if (extensionMethod == null) {
MapProtocolMember (obj_method.Method, out extensionMethod);
if (extensionMethod == null)
return null;
}
var createMethod = GetBlockProxyAttributeMethod (extensionMethod, parameter + 1);
if (createMethod != null)
return createMethod;
}
}
}
@ -4762,6 +4856,7 @@ namespace Registrar {
header.WriteLine ("#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"");
header.WriteLine ("#pragma clang diagnostic ignored \"-Wtypedef-redefinition\""); // temporary hack until we can stop including glib.h
header.WriteLine ("#pragma clang diagnostic ignored \"-Wobjc-designated-initializers\"");
header.WriteLine ("#pragma clang diagnostic ignored \"-Wunguarded-availability-new\"");
if (App.EnableDebug) {
header.WriteLine ("#define DEBUG 1");
@ -4843,6 +4938,11 @@ namespace Registrar {
public TypeDefinition Type { get; set; }
}
class DelegateProxyAttribute : Attribute
{
public TypeDefinition DelegateType { get; set; }
}
class BindAsAttribute : Attribute
{
public BindAsAttribute (TypeReference type)
@ -4863,6 +4963,7 @@ namespace Registrar {
public string Name { get; set; }
public string Selector { get; set; }
public TypeReference ReturnType { get; set; }
public TypeReference ReturnTypeDelegateProxy { get; set; }
public TypeReference[] ParameterType { get; set; }
public bool[] ParameterByRef { get; set; }
public TypeReference [] ParameterBlockProxy { get; set; }

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

@ -48,6 +48,7 @@ namespace Xamarin.Linker {
"Microsoft.Win32.Registry.AccessControl",
"Microsoft.Win32.Registry",
"System.AppContext",
"System.Buffers",
"System.Collections.Concurrent",
"System.Collections.NonGeneric",
"System.Collections.Specialized",

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

@ -491,7 +491,7 @@ namespace Xamarin.Bundler {
App.InitializeCommon ();
Log ("Xamarin.Mac {0}{1}", Constants.Version, verbose > 0 ? "." + Constants.Revision : string.Empty);
Log ("Xamarin.Mac {0}.{1}", Constants.Version, Constants.Revision);
if (verbose > 0)
Console.WriteLine ("Selected target framework: {0}; API: {1}", targetFramework, IsClassic ? "Classic" : "Unified");

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

@ -116,6 +116,8 @@ namespace Xamarin.Bundler {
public string AotOtherArguments = string.Empty;
public bool? LLVMAsmWriter;
public Dictionary<string, string> LLVMOptimizations = new Dictionary<string, string> ();
public bool UseInterpreter;
public List<string> InterpretedAssemblies = new List<string> ();
public Dictionary<string, string> EnvironmentVariables = new Dictionary<string, string> ();
@ -129,6 +131,44 @@ namespace Xamarin.Bundler {
public bool? BuildDSym;
public bool IsInterpreted (string assembly)
{
// IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both.
if (!UseInterpreter)
return false;
// Go through the list of assemblies to interpret in reverse order,
// so that the last option passed to mtouch takes precedence.
for (int i = InterpretedAssemblies.Count - 1; i >= 0; i--) {
var opt = InterpretedAssemblies [i];
if (opt == "all")
return true;
else if (opt == "-all")
return false;
else if (opt == assembly)
return true;
else if (opt [0] == '-' && opt.Substring (1) == assembly)
return false;
}
// There's an implicit 'all' at the start of the list.
return true;
}
public bool IsAOTCompiled (string assembly)
{
if (!UseInterpreter)
return true;
// IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both:
// - mscorlib will always be processed by the AOT compiler to generate required wrapper functions for the interpreter to work
// - mscorlib might also be fully AOT-compiled (both when the interpreter is enabled and when it's not)
if (assembly == "mscorlib")
return true;
return !IsInterpreted (assembly);
}
// If we're targetting a 32 bit arch.
bool? is32bits;
public bool Is32Build {
@ -462,7 +502,7 @@ namespace Xamarin.Bundler {
if (EnableLLVMOnlyBitCode)
return false;
if (UseInterpreter)
if (IsInterpreted (Assembly.GetIdentity (assembly)))
return true;
switch (Platform) {
@ -2124,7 +2164,20 @@ namespace Xamarin.Bundler {
public void BundleAssemblies ()
{
var strip = !UseInterpreter && ManagedStrip && IsDeviceBuild && !EnableDebug && !PackageManagedDebugSymbols;
Assembly.StripAssembly strip = ((path) =>
{
if (!ManagedStrip)
return false;
if (!IsDeviceBuild)
return false;
if (EnableDebug)
return false;
if (PackageManagedDebugSymbols)
return false;
if (IsInterpreted (Assembly.GetIdentity (path)))
return false;
return true;
});
var grouped = Targets.SelectMany ((Target t) => t.Assemblies).GroupBy ((Assembly asm) => asm.Identity);
foreach (var @group in grouped) {

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

@ -54,11 +54,7 @@ namespace Xamarin.Bundler {
public bool IsAOTCompiled {
get {
if (App.UseInterpreter)
/* interpreter only requires a few stubs that are attached
* to mscorlib.dll, other assemblies won't be AOT compiled */
return FileName == "mscorlib.dll";
return true;
return App.IsAOTCompiled (Identity);
}
}
@ -108,15 +104,18 @@ namespace Xamarin.Bundler {
ComputeDependencies (exceptions);
}
public delegate bool StripAssembly (string path);
// returns false if the assembly was not copied (because it was already up-to-date).
public bool CopyAssembly (string source, string target, bool copy_debug_symbols = true, bool strip = false)
public bool CopyAssembly (string source, string target, bool copy_debug_symbols = true, StripAssembly strip = null)
{
var copied = false;
try {
if (!Application.IsUptodate (source, target) && (strip || !Cache.CompareAssemblies (source, target))) {
var strip_assembly = strip != null && strip (source);
if (!Application.IsUptodate (source, target) && (strip_assembly || !Cache.CompareAssemblies (source, target))) {
copied = true;
if (strip) {
if (strip_assembly) {
Driver.FileDelete (target);
Directory.CreateDirectory (Path.GetDirectoryName (target));
MonoTouch.Tuner.Stripper.Process (source, target);
@ -195,7 +194,7 @@ namespace Xamarin.Bundler {
// Aot data is copied separately, because we might want to copy aot data
// even if we don't want to copy the assembly (if 32/64-bit assemblies are identical,
// only one is copied, but we still want the aotdata for both).
public void CopyToDirectory (string directory, bool reload = true, bool check_case = false, bool only_copy = false, bool copy_debug_symbols = true, bool strip = false)
public void CopyToDirectory (string directory, bool reload = true, bool check_case = false, bool only_copy = false, bool copy_debug_symbols = true, StripAssembly strip = null)
{
var target = Path.Combine (directory, FileName);

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

@ -486,7 +486,7 @@ namespace Xamarin.Bundler
throw new ArgumentNullException (nameof (install_name));
flags.AddOtherFlag ("-shared");
if (!App.EnableBitCode)
if (!App.EnableBitCode && !Target.Is64Build)
flags.AddOtherFlag ("-read_only_relocs suppress");
if (App.EnableBitCode)
flags.AddOtherFlag ("-lc++");

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

@ -283,6 +283,29 @@ namespace Xamarin.Bundler
}
linker_flags = new CompilerFlags (this);
// Verify that there are no entries in our list of intepreted assemblies that doesn't match
// any of the assemblies we know about.
if (App.UseInterpreter) {
var exceptions = new List<Exception> ();
foreach (var entry in App.InterpretedAssemblies) {
var assembly = entry;
if (string.IsNullOrEmpty (assembly))
continue;
if (assembly [0] == '-')
assembly = assembly.Substring (1);
if (assembly == "all")
continue;
if (Assemblies.ContainsKey (assembly))
continue;
exceptions.Add (ErrorHelper.CreateWarning (138, $"Cannot find the assembly '{assembly}', passed as an argument to --interpreter."));
}
ErrorHelper.ThrowIfErrors (exceptions);
}
}
// This is to load the symbols for all assemblies, so that we can give better error messages
@ -1134,6 +1157,8 @@ namespace Xamarin.Bundler
}
if (App.UseInterpreter)
/* TODO: not sure? we might have to continue here, depending on
* the set of assemblies are AOT'd? */
return;
// Code in one assembly (either in a P/Invoke or a third-party library) can depend on a third-party library in another assembly.

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

@ -455,7 +455,8 @@ namespace Xamarin.Bundler
bool enable_debug = app.EnableDebug;
bool enable_debug_symbols = app.PackageManagedDebugSymbols;
bool llvm_only = app.EnableLLVMOnlyBitCode;
bool interp = app.UseInterpreter;
bool interp = app.IsInterpreted (Assembly.GetIdentity (filename));
bool interp_full = !interp && app.UseInterpreter && fname == "mscorlib.dll";
bool is32bit = (abi & Abi.Arch32Mask) > 0;
string arch = abi.AsArchString ();
@ -474,9 +475,15 @@ namespace Xamarin.Bundler
args.Append (app.AotArguments);
if (llvm_only)
args.Append ("llvmonly,");
else if (interp)
else if (interp) {
if (fname != "mscorlib.dll")
throw ErrorHelper.CreateError (99, $"Internal error: can only enable the interpreter for mscorlib.dll when AOT-compiling assemblies (tried to interpret {fname}). Please file an issue at https://github.com/xamarin/xamarin-macios/issues/new.");
args.Append ("interp,");
else
} else if (interp_full) {
if (fname != "mscorlib.dll")
throw ErrorHelper.CreateError (99, $"Internal error: can only enable the interpreter for mscorlib.dll when AOT-compiling assemblies (tried to interpret {fname}). Please file an issue at https://github.com/xamarin/xamarin-macios/issues/new.");
args.Append ("interp,full,");
} else
args.Append ("full,");
var aname = Path.GetFileNameWithoutExtension (fname);
@ -1247,7 +1254,14 @@ namespace Xamarin.Bundler
app.LLVMOptimizations [asm] = opt;
}
},
{ "interpreter", "Enable the *experimental* interpreter.", v => { app.UseInterpreter = true; }},
{ "interpreter:", "Enable the *experimental* interpreter. Optionally takes a comma-separated list of assemblies to interpret (if prefixed with a minus sign, the assembly will be AOT-compiled instead). 'all' can be used to specify all assemblies. This argument can be specified multiple times.", v =>
{
app.UseInterpreter = true;
if (!string.IsNullOrEmpty (v)) {
app.InterpretedAssemblies.AddRange (v.Split (new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
}
},
{ "http-message-handler=", "Specify the default HTTP message handler for HttpClient", v => { http_message_handler = v; }},
{ "output-format=", "Specify the output format for some commands. Possible values: Default, XML", v =>
{
@ -1341,7 +1355,7 @@ namespace Xamarin.Bundler
throw new MonoTouchException (25, true, "No SDK version was provided. Please add --sdk=X.Y to specify which {0} SDK should be used to build your application.", app.PlatformName);
var framework_dir = GetFrameworkDirectory (app);
Driver.Log ("Xamarin.iOS {0}{1} using framework: {2}", Constants.Version, verbose > 1 ? "." + Constants.Revision : string.Empty, framework_dir);
Driver.Log ("Xamarin.iOS {0}.{1} using framework: {2}", Constants.Version, Constants.Revision, framework_dir);
if (action == Action.None)
throw new MonoTouchException (52, true, "No command specified.");