1. Adventures with Mono Runtime on Mobile Platforms
.NET Stammtisch Linz
Bernhard Urban
beurba@microsoft.com
https://www.xamarin.com
https://www.mono-project.com
July 23, 2019
foundation
1 / 13
16. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
5 / 13
17. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
5 / 13
18. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
Users
5 / 13
19. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
Users
Game Studios
5 / 13
20. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
Users
Game Studios
Unity
5 / 13
21. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
Users
Game Studios
Unity
Blazor: check out https://learn-blazor.com/
5 / 13
22. Embedding the Mono Runtime
Embedding Mono
link Mono into your application
allows execution of .NET, e.g. useful for scripting
Users
Game Studios
Unity
Blazor: check out https://learn-blazor.com/
Xamarin.Android & Xamarin.iOS
5 / 13
30. FullAOT
iOS does not allow JIT compilation
Normal AOT uses JIT occasionally at runtime
7 / 13
31. FullAOT
iOS does not allow JIT compilation
Normal AOT uses JIT occasionally at runtime
All trampolines and wrappers must be included in the AOT image
7 / 13
32. FullAOT
iOS does not allow JIT compilation
Normal AOT uses JIT occasionally at runtime
All trampolines and wrappers must be included in the AOT image
Side-effect: System.Reflection.Emit does not work
7 / 13
35. What about generics?
public T return_t<T> (T arg) {
return arg;
}
// "Generic sharing for value types"
public void return_t (T& ret, T& arg, ptr hidden_arg) {
int size = rgctx_fetch (hidden_arg);
memcpy (ret, arg, size);
}
8 / 13
36. What about generics?
public T return_t<T> (T arg) {
return arg;
}
// "Generic sharing for value types"
public void return_t (T& ret, T& arg, ptr hidden_arg) {
int size = rgctx_fetch (hidden_arg);
memcpy (ret, arg, size);
}
int i = return_t<int> (5);
8 / 13
37. What about generics?
public T return_t<T> (T arg) {
return arg;
}
// "Generic sharing for value types"
public void return_t (T& ret, T& arg, ptr hidden_arg) {
int size = rgctx_fetch (hidden_arg);
memcpy (ret, arg, size);
}
int i = return_t<int> (5);
// calling chain
caller
⇒ callee
8 / 13
38. What about generics?
public T return_t<T> (T arg) {
return arg;
}
// "Generic sharing for value types"
public void return_t (T& ret, T& arg, ptr hidden_arg) {
int size = rgctx_fetch (hidden_arg);
memcpy (ret, arg, size);
}
int i = return_t<int> (5);
// calling chain
caller
⇒ gsharedvt_arg_trampoline
⇒ callee
8 / 13
39. What about generics?
public T return_t<T> (T arg) {
return arg;
}
// "Generic sharing for value types"
public void return_t (T& ret, T& arg, ptr hidden_arg) {
int size = rgctx_fetch (hidden_arg);
memcpy (ret, arg, size);
}
int i = return_t<int> (5);
// calling chain
caller
⇒ gsharedvt_arg_trampoline
⇒ gsharedvt_in_trampoline
⇒ callee
8 / 13
44. System.Reflection.Emit?
System.ExecutionEngineException:
Attempting to JIT compile method MyClass:DynamicallyGeneratedMethod ()
Runtime interpreter enables System.Reflection.Emit
Faster “inner dev loop”
No need to run the AOT compiler
Smaller app bundle size ⇒ faster deploy
Best of both worlds: “Mixed Mode” with FullAOT
9 / 13
45. System.Reflection.Emit?
System.ExecutionEngineException:
Attempting to JIT compile method MyClass:DynamicallyGeneratedMethod ()
Runtime interpreter enables System.Reflection.Emit
Faster “inner dev loop”
No need to run the AOT compiler
Smaller app bundle size ⇒ faster deploy
Best of both worlds: “Mixed Mode” with FullAOT
Ships with upcoming release of Xamarin.iOS (Preview available)
9 / 13
46. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
10 / 13
47. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
10 / 13
48. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
x86 64: JIT.
10 / 13
49. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
x86 64: JIT.
watchOS on Apple Watch.
10 / 13
50. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
x86 64: JIT.
watchOS on Apple Watch.
armv7k: FullAOT and bitcode.
10 / 13
51. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
x86 64: JIT.
watchOS on Apple Watch.
armv7k: FullAOT and bitcode.
arm64 32: interpreter (WIP) and bitcode.
10 / 13
52. Platform & Device landscape
iOS on iPhone/iPad.
armv7: FullAOT.
arm64: FullAOT and interpreter.
x86: JIT.
x86 64: JIT.
tvOS on Apple TV.
arm64: FullAOT and interpreter.
x86 64: JIT.
watchOS on Apple Watch.
armv7k: FullAOT and bitcode.
arm64 32: interpreter (WIP) and bitcode.
x86: JIT.
10 / 13
54. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
11 / 13
55. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
11 / 13
56. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
Co-worker in the US got the device.
11 / 13
57. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
Co-worker in the US got the device. He could not reproduce it.
11 / 13
58. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
Co-worker in the US got the device. He could not reproduce it.
US edition: Ships with Snapdragon 820.
11 / 13
59. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
Co-worker in the US got the device. He could not reproduce it.
US edition: Ships with Snapdragon 820.
World edition: Ships with Exynos 8890.
11 / 13
60. Xamarin.Android
Simliar to Linux, except for interop between C# and Java
Two Garbage collectors have to work together
War story: Samsung Galaxy S7
First bug report: “Xamarin.Android apps on the Samsung Galaxy S7
fails to start with the error System.ExecutionEngineException
SIGILL“.
Co-worker in the US got the device. He could not reproduce it.
US edition: Ships with Snapdragon 820.
World edition: Ships with Exynos 8890.
Could reproduce it with Xamarin Test Cloud.
11 / 13
61. War story: Samsung Galaxy S7
$ grep SIGILL *.log
custom_01.log:E/mono (13964): SIGILL at ip=0x0000007f4f15e8d0
custom_02.log:E/mono (13088): SIGILL at ip=0x0000007f8ff76cc0
custom_03.log:E/mono (12824): SIGILL at ip=0x0000007f68e93c70
custom_04.log:E/mono (12876): SIGILL at ip=0x0000007f4b3d55f0
custom_05.log:E/mono (13008): SIGILL at ip=0x0000007f8df1e8d0
custom_06.log:E/mono (14093): SIGILL at ip=0x0000007f6c21edf0
12 / 13
62. War story: Samsung Galaxy S7
$ grep SIGILL *.log
custom_01.log:E/mono (13964): SIGILL at ip=0x0000007f4f15e8d0
custom_02.log:E/mono (13088): SIGILL at ip=0x0000007f8ff76cc0
custom_03.log:E/mono (12824): SIGILL at ip=0x0000007f68e93c70
custom_04.log:E/mono (12876): SIGILL at ip=0x0000007f4b3d55f0
custom_05.log:E/mono (13008): SIGILL at ip=0x0000007f8df1e8d0
custom_06.log:E/mono (14093): SIGILL at ip=0x0000007f6c21edf0
void __clear_cache (char *address, size_t size) {
static int cache_line_size = 0;
if (!cache_line_size)
cache_line_size = get_current_cpu_cache_line_size ();
for (int i = 0; i < size; i += cache_line_size)
flush_cache_line (address + i);
}
63. War story: Samsung Galaxy S7
$ grep SIGILL *.log
custom_01.log:E/mono (13964): SIGILL at ip=0x0000007f4f15e8d0
custom_02.log:E/mono (13088): SIGILL at ip=0x0000007f8ff76cc0
custom_03.log:E/mono (12824): SIGILL at ip=0x0000007f68e93c70
custom_04.log:E/mono (12876): SIGILL at ip=0x0000007f4b3d55f0
custom_05.log:E/mono (13008): SIGILL at ip=0x0000007f8df1e8d0
custom_06.log:E/mono (14093): SIGILL at ip=0x0000007f6c21edf0
void __clear_cache (char *address, size_t size) {
static int cache_line_size = 0;
if (!cache_line_size)
cache_line_size = get_current_cpu_cache_line_size ();
for (int i = 0; i < size; i += cache_line_size)
flush_cache_line (address + i);
}
64. War story: Samsung Galaxy S7
$ grep SIGILL *.log
custom_01.log:E/mono (13964): SIGILL at ip=0x0000007f4f15e8d0
custom_02.log:E/mono (13088): SIGILL at ip=0x0000007f8ff76cc0
custom_03.log:E/mono (12824): SIGILL at ip=0x0000007f68e93c70
custom_04.log:E/mono (12876): SIGILL at ip=0x0000007f4b3d55f0
custom_05.log:E/mono (13008): SIGILL at ip=0x0000007f8df1e8d0
custom_06.log:E/mono (14093): SIGILL at ip=0x0000007f6c21edf0
void __clear_cache (char *address, size_t size) {
static int cache_line_size = 0;
if (!cache_line_size)
cache_line_size = get_current_cpu_cache_line_size ();
for (int i = 0; i < size; i += cache_line_size)
flush_cache_line (address + i);
}
12 / 13
65. War story: Samsung Galaxy S7
$ grep SIGILL *.log
custom_01.log:E/mono (13964): SIGILL at ip=0x0000007f4f15e8d0
custom_02.log:E/mono (13088): SIGILL at ip=0x0000007f8ff76cc0
custom_03.log:E/mono (12824): SIGILL at ip=0x0000007f68e93c70
custom_04.log:E/mono (12876): SIGILL at ip=0x0000007f4b3d55f0
custom_05.log:E/mono (13008): SIGILL at ip=0x0000007f8df1e8d0
custom_06.log:E/mono (14093): SIGILL at ip=0x0000007f6c21edf0
void __clear_cache (char *address, size_t size) {
static int cache_line_size = 0;
if (!cache_line_size)
cache_line_size = get_current_cpu_cache_line_size ();
for (int i = 0; i < size; i += cache_line_size)
flush_cache_line (address + i);
}
64byte buckets:
0x00-0x3f: always flushed
0x40-0x7f: only flushed when cacheline size is 64 byte.
0x80-0xbf: always flushed
0xc0-0xff: only flushed when cacheline size is 64 byte.
12 / 13