Skip to content

Commit c72cdb1

Browse files
committed
[dotnet] Add support for selecting whether to create P/Invoke wrappers or not. Fixes dotnet#4940. (dotnet#14961)
* This is a potential mitigation for slower transition to native code when exception marshalling is enabled (dotnet#14812). * A minor modification was required in the linker, to make sure any modified assemblies are saved. Fixes dotnet#4940.
1 parent c4f3d65 commit c72cdb1

File tree

8 files changed

+103
-10
lines changed

8 files changed

+103
-10
lines changed

dotnet/targets/Xamarin.Shared.Sdk.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@
493493
PlatformAssembly=$(_PlatformAssemblyName).dll
494494
RelativeAppBundlePath=$(_RelativeAppBundlePath)
495495
Registrar=$(_BundlerRegistrar)
496+
RequirePInvokeWrappers=$(_RequirePInvokeWrappers)
496497
RuntimeConfigurationFile=$(_RuntimeConfigurationFile)
497498
SdkDevPath=$(_SdkDevPath)
498499
SdkRootDirectory=$(_XamarinSdkRootDirectory)

msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ParseBundlerArgumentsTaskBase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public abstract class ParseBundlerArgumentsTaskBase : XamarinTask {
4646
[Output]
4747
public string Registrar { get; set; }
4848

49+
[Output]
50+
public string RequirePInvokeWrappers { get; set; }
51+
4952
// This is input too
5053
[Output]
5154
public string NoStrip { get; set; }
@@ -148,6 +151,9 @@ public override bool Execute ()
148151
case "package-debug-symbols":
149152
PackageDebugSymbols = string.IsNullOrEmpty (value) ? "true" : value;
150153
break;
154+
case "require-pinvoke-wrappers":
155+
RequirePInvokeWrappers = string.IsNullOrEmpty (value) ? "true" : value;
156+
break;
151157
case "registrar":
152158
value = hasValue ? value : nextValue; // requires a value, which might be the next option
153159
Registrar = value;

msbuild/Xamarin.Shared/Xamarin.Shared.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
17821782
<Output TaskParameter="Optimize" PropertyName="_BundlerOptimize"/>
17831783
<Output TaskParameter="PackageDebugSymbols" PropertyName="PackageDebugSymbols" />
17841784
<Output TaskParameter="Registrar" PropertyName="_BundlerRegistrar" />
1785+
<Output TaskParameter="RequirePInvokeWrappers" PropertyName="_RequirePInvokeWrappers" />
17851786
<Output TaskParameter="Verbosity" PropertyName="_BundlerVerbosity" />
17861787
<Output TaskParameter="XmlDefinitions" ItemName="_BundlerXmlDefinitions" />
17871788
<Output TaskParameter="NoStrip" PropertyName="EnableAssemblyILStripping" />

tools/common/Application.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,16 @@ public string Name {
611611
get { return Path.GetFileNameWithoutExtension (AppDirectory); }
612612
}
613613

614+
bool? requires_pinvoke_wrappers;
614615
public bool RequiresPInvokeWrappers {
615616
get {
617+
if (requires_pinvoke_wrappers.HasValue)
618+
return requires_pinvoke_wrappers.Value;
619+
620+
// By default this is disabled for .NET
621+
if (Driver.IsDotNet)
622+
return false;
623+
616624
if (Platform == ApplePlatform.MacOSX)
617625
return false;
618626

@@ -624,6 +632,9 @@ public bool RequiresPInvokeWrappers {
624632

625633
return MarshalObjectiveCExceptions == MarshalObjectiveCExceptionMode.ThrowManagedException || MarshalObjectiveCExceptions == MarshalObjectiveCExceptionMode.Abort;
626634
}
635+
set {
636+
requires_pinvoke_wrappers = value;
637+
}
627638
}
628639

629640
public string PlatformName {

tools/common/Driver.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ static bool ParseOptions (Application app, Mono.Options.OptionSet options, strin
253253
options.Add ("rid=", "The runtime identifier we're building for", v => {
254254
app.RuntimeIdentifier = v;
255255
}, true /* hidden - this is only for build-time --runregistrar support */);
256+
options.Add ("require-pinvoke-wrappers:", v => {
257+
app.RequiresPInvokeWrappers = ParseBool (v, "--require-pinvoke-wrappers");
258+
});
256259

257260

258261
// Keep the ResponseFileSource option at the end.

tools/dotnet-linker/LinkerConfiguration.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public class LinkerConfiguration {
5757

5858
Dictionary<string, List<MSBuildItem>> msbuild_items = new Dictionary<string, List<MSBuildItem>> ();
5959

60+
internal PInvokeWrapperGenerator PInvokeWrapperGenerationState;
61+
6062
public static LinkerConfiguration GetInstance (LinkContext context, bool createIfNotFound = true)
6163
{
6264
if (!configurations.TryGetValue (context, out var instance) && createIfNotFound) {
@@ -231,6 +233,11 @@ public static LinkerConfiguration GetInstance (LinkContext context, bool createI
231233
case "Registrar":
232234
Application.ParseRegistrar (value);
233235
break;
236+
case "RequirePInvokeWrappers":
237+
if (!TryParseOptionalBoolean (value, out var require_pinvoke_wrappers))
238+
throw new InvalidOperationException ($"Unable to parse the {key} value: {value} in {linker_file}");
239+
Application.RequiresPInvokeWrappers = require_pinvoke_wrappers.Value;
240+
break;
234241
case "RuntimeConfigurationFile":
235242
Application.RuntimeConfigurationFile = value;
236243
break;
@@ -401,6 +408,7 @@ public void Write ()
401408
Console.WriteLine ($" RelativeAppBundlePath: {RelativeAppBundlePath}");
402409
Console.WriteLine ($" Registrar: {Application.Registrar} (Options: {Application.RegistrarOptions})");
403410
Console.WriteLine ($" RuntimeConfigurationFile: {Application.RuntimeConfigurationFile}");
411+
Console.WriteLine ($" RequirePInvokeWrappers: {Application.RequiresPInvokeWrappers}");
404412
Console.WriteLine ($" SdkDevPath: {Driver.SdkRoot}");
405413
Console.WriteLine ($" SdkRootDirectory: {SdkRootDirectory}");
406414
Console.WriteLine ($" SdkVersion: {SdkVersion}");

tools/dotnet-linker/Steps/GenerateMainStep.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,24 @@ protected override void TryEndProcess ()
5555
if (app.EnableDebug)
5656
item.Metadata.Add ("Arguments", "-DDEBUG");
5757
items.Add (item);
58+
59+
if (app.RequiresPInvokeWrappers) {
60+
var state = Configuration.PInvokeWrapperGenerationState;
61+
if (state.Started) {
62+
// The generator is 'started' by the linker, which means it may not
63+
// be started if the linker was not executed due to re-using cached results.
64+
state.End ();
65+
}
66+
item = new MSBuildItem {
67+
Include = state.SourcePath,
68+
Metadata = {
69+
{ "Arch", abi.AsArchString () },
70+
},
71+
};
72+
if (app.EnableDebug)
73+
item.Metadata.Add ("Arguments", "-DDEBUG");
74+
items.Add (item);
75+
}
5876
}
5977

6078
Configuration.WriteOutputForMSBuild ("_MainFile", items);

tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,56 @@ namespace Xamarin.Linker.Steps
1818
public class ListExportedSymbols : BaseStep
1919
{
2020
PInvokeWrapperGenerator state;
21+
#if !NET
2122
bool skip_sdk_assemblies;
23+
#endif
24+
25+
PInvokeWrapperGenerator State {
26+
get {
27+
#if NET
28+
if (state is null && DerivedLinkContext.App.RequiresPInvokeWrappers) {
29+
Configuration.PInvokeWrapperGenerationState = new PInvokeWrapperGenerator () {
30+
App = DerivedLinkContext.App,
31+
SourcePath = Path.Combine (Configuration.CacheDirectory, "pinvokes.mm"),
32+
HeaderPath = Path.Combine (Configuration.CacheDirectory, "pinvokes.h"),
33+
Registrar = DerivedLinkContext.StaticRegistrar,
34+
};
35+
state = Configuration.PInvokeWrapperGenerationState;
36+
}
37+
#endif
38+
return state;
39+
}
40+
}
41+
42+
#if NET
43+
public LinkerConfiguration Configuration {
44+
get {
45+
return LinkerConfiguration.GetInstance (Context);
46+
}
47+
}
48+
#endif
2249

2350
public DerivedLinkContext DerivedLinkContext {
2451
get {
2552
#if NET
26-
return LinkerConfiguration.GetInstance (Context).DerivedLinkContext;
53+
return Configuration.DerivedLinkContext;
2754
#else
2855
return (DerivedLinkContext) Context;
2956
#endif
3057
}
3158
}
3259

33-
public ListExportedSymbols () : this (null)
60+
#if NET
61+
public ListExportedSymbols ()
3462
{
3563
}
36-
64+
#else
3765
internal ListExportedSymbols (PInvokeWrapperGenerator state, bool skip_sdk_assemblies = false)
3866
{
3967
this.state = state;
4068
this.skip_sdk_assemblies = skip_sdk_assemblies;
4169
}
70+
#endif
4271

4372
protected override void ProcessAssembly (AssemblyDefinition assembly)
4473
{
@@ -64,23 +93,34 @@ protected override void ProcessAssembly (AssemblyDefinition assembly)
6493
if (!hasSymbols)
6594
return;
6695

96+
var modified = false;
6797
foreach (var type in assembly.MainModule.Types)
68-
ProcessType (type);
98+
modified |= ProcessType (type);
99+
100+
// Make sure the linker saves any changes in the assembly.
101+
if (modified) {
102+
var action = Context.Annotations.GetAction (assembly);
103+
if (action == AssemblyAction.Copy)
104+
Context.Annotations.SetAction (assembly, AssemblyAction.Save);
105+
}
69106
}
70107

71-
void ProcessType (TypeDefinition type)
108+
bool ProcessType (TypeDefinition type)
72109
{
110+
var modified = false;
73111
if (type.HasNestedTypes) {
74112
foreach (var nested in type.NestedTypes)
75-
ProcessType (nested);
113+
modified |= ProcessType (nested);
76114
}
77115

78116
if (type.HasMethods) {
79117
foreach (var method in type.Methods)
80-
ProcessMethod (method);
118+
modified |= ProcessMethod (method);
81119
}
82120

83121
AddRequiredObjectiveCType (type);
122+
123+
return modified;
84124
}
85125

86126
void AddRequiredObjectiveCType (TypeDefinition type)
@@ -106,20 +146,23 @@ void AddRequiredObjectiveCType (TypeDefinition type)
106146
}
107147
}
108148

109-
void ProcessMethod (MethodDefinition method)
149+
bool ProcessMethod (MethodDefinition method)
110150
{
151+
var modified = false;
152+
111153
if (method.IsPInvokeImpl && method.HasPInvokeInfo && method.PInvokeInfo != null) {
112154
var pinfo = method.PInvokeInfo;
113155
bool addPInvokeSymbol = false;
114156

115-
if (state != null) {
157+
if (State != null) {
116158
switch (pinfo.EntryPoint) {
117159
case "objc_msgSend":
118160
case "objc_msgSendSuper":
119161
case "objc_msgSend_stret":
120162
case "objc_msgSendSuper_stret":
121163
case "objc_msgSend_fpret":
122-
state.ProcessMethod (method);
164+
State.ProcessMethod (method);
165+
modified = true;
123166
break;
124167
default:
125168
break;
@@ -181,6 +224,8 @@ void ProcessMethod (MethodDefinition method)
181224
DerivedLinkContext.RequiredSymbols.AddField ((string) symbol).AddMember (property);
182225
}
183226
}
227+
228+
return modified;
184229
}
185230
}
186231
}

0 commit comments

Comments
 (0)