Skip to content

Commit 805aa9b

Browse files
authored
Add support for iOS sample app to publish and run with R2R on coreclr (#121824)
Runtime: - Stop disabling R2R by default on Apple mobile - Update runtime to interpret everything on Apple moblie iOS sample app: - Update AppleAppBuilder host template to use `host_runtime_contract` - Use in-build crossgen2 and in-repo targets when publishing iOS app - Make AppleAppBuilder sign `*.r2r.dylib`
1 parent 8dff353 commit 805aa9b

File tree

10 files changed

+124
-16
lines changed

10 files changed

+124
-16
lines changed

src/coreclr/inc/clrconfigvalues.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,11 +579,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_CreateDumpDiagnostics, W("CreateDumpDiagnostic
579579
/// R2R
580580
///
581581
RETAIL_CONFIG_STRING_INFO(INTERNAL_NativeImageSearchPaths, W("NativeImageSearchPaths"), "Extra search paths for native composite R2R images")
582-
#if defined(TARGET_IOS) || defined(TARGET_TVOS) || defined(TARGET_MACCATALYST)
583-
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ReadyToRun, W("ReadyToRun"), 0, "Enable/disable use of ReadyToRun native code") // Off by default for Apple mobile
584-
#else
585582
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ReadyToRun, W("ReadyToRun"), 1, "Enable/disable use of ReadyToRun native code") // On by default for CoreCLR
586-
#endif // defined(TARGET_IOS) || defined(TARGET_TVOS) || defined(TARGET_MACCATALYST)
587583
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ReadyToRunExcludeList, W("ReadyToRunExcludeList"), "List of assemblies that cannot use Ready to Run images")
588584
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ReadyToRunLogFile, W("ReadyToRunLogFile"), "Name of file to log success/failure of using Ready to Run images")
589585

src/coreclr/interpreter/eeinterp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ CorJitResult CILInterp::compileMethod(ICorJitInfo* compHnd,
8585
break;
8686
}
8787

88-
#ifdef TARGET_WASM
89-
// interpret everything on wasm
88+
#if !defined(FEATURE_JIT)
89+
// interpret everything when we do not have a JIT
9090
doInterpret = true;
9191
#else
9292
// NOTE: We do this check even if doInterpret==true in order to populate g_interpModule

src/mono/msbuild/apple/build/AppleBuild.InTree.targets

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,19 @@
3333
</ItemGroup>
3434
<Message Text="Used runtime pack: %(ResolvedRuntimePack.PackageDirectory)" Importance="high" />
3535
</Target>
36+
37+
<!-- Override the ResolveReadyToRunCompilers target to use the in-build crossgen2.
38+
This needs to be imported after SDK targets, so any project requiring this should set AfterMicrosoftNETSdkTargets -->
39+
<Target Name="ResolveReadyToRunCompilers" Condition="'$(PublishReadyToRun)' == true" DependsOnTargets="ResolveRuntimeFilesFromLocalBuild">
40+
<PropertyGroup>
41+
<Crossgen2Path>$([MSBuild]::NormalizePath('$(Crossgen2InBuildDir)', 'crossgen2$(ExeSuffix)'))</Crossgen2Path>
42+
</PropertyGroup>
43+
44+
<ItemGroup>
45+
<Crossgen2Tool Include="$(Crossgen2Path)"
46+
TargetArch="$(TargetArchitecture)"
47+
TargetOS="$(TargetOS)"
48+
PerfmapFormatVersion="$(PublishReadyToRunPerfmapFormatVersion)"/>
49+
</ItemGroup>
50+
</Target>
3651
</Project>

src/mono/msbuild/apple/build/AppleBuild.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@
257257
<_MonoLLVMPath Condition="'$(_MonoLLVMPath)' == '' and '$(MonoEnableLLVM)' == 'true'">$([System.IO.Path]::GetDirectoryName("$(_CompilerBinaryPath)"))</_MonoLLVMPath>
258258
</PropertyGroup>
259259

260-
<MonoAOTCompiler Condition="'$(RunAOTCompilation)' == 'true'"
260+
<MonoAOTCompiler Condition="'$(RunAOTCompilation)' == 'true' and '$(UseMonoRuntime)' != 'false'"
261261
AotModulesTablePath="$(_AotModuleTablePath)"
262262
AotModulesTableLanguage="ObjC"
263263
Assemblies="@(_AotInputAssemblies)"

src/mono/sample/iOS/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ APP_SANDBOX?=false
1111
STRIP_DEBUG_SYMBOLS?=false # only used when measuring SOD via build-appbundle make target
1212
USE_MONO_RUNTIME?=true
1313
AOT?=true
14+
R2R?=false
1415

1516
#If DIAGNOSTIC_PORTS is enabled, @(RuntimeComponents) must also include 'diagnostics_tracing'.
1617
#If @(RuntimeComponents) includes 'diagnostics_tracing', DIAGNOSTIC_PORTS is optional.
@@ -44,6 +45,7 @@ build-appbundle: clean appbuilder
4445
/p:DeployAndRun=false \
4546
/p:RunAOTCompilation=$(AOT) \
4647
/p:UseMonoRuntime=$(USE_MONO_RUNTIME) \
48+
/p:PublishReadyToRun=$(R2R) \
4749
/bl
4850

4951
run: clean appbuilder

src/mono/sample/iOS/Program.csproj

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,24 @@
2626
<BuildAppBundleDependsOnTargets Condition="'$(ArchiveTests)' == 'true'">Publish</BuildAppBundleDependsOnTargets>
2727
</PropertyGroup>
2828

29+
<PropertyGroup Condition="'$(PublishReadyToRun)' == 'true' and '$(UseMonoRuntime)' != 'true'">
30+
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
31+
<PublishReadyToRunContainerFormat>macho</PublishReadyToRunContainerFormat>
32+
</PropertyGroup>
33+
2934
<ItemGroup>
3035
<RuntimeComponents Condition="'$(DiagnosticPorts)' != ''" Include="diagnostics_tracing" />
31-
<EnvironmentVariables Condition="'$(UseMonoRuntime)' != 'true'" Include="DOTNET_Interpreter=%2A%21%2A" />
32-
<EnvironmentVariables Condition="'$(UseMonoRuntime)' != 'true'" Include="DOTNET_InterpMode=3" />
33-
<EnvironmentVariables Condition="'$(UseMonoRuntime)' != 'true'" Include="DOTNET_ReadyToRun=0" />
3436
</ItemGroup>
3537

38+
<!-- Use the repo's CrossGen props/targets.
39+
This can be removed once we upstream Mach-O support in the targets to the SDK -->
40+
<Import Project="$(Crossgen2SdkOverridePropsPath)" Condition="'$(PublishReadyToRun)' == 'true' and '$(Crossgen2SdkOverridePropsPath)' != ''" />
3641
<Import Project="$(MonoProjectRoot)\msbuild\apple\build\AppleBuild.props" />
37-
<Import Project="$(MonoProjectRoot)\msbuild\apple\build\AppleBuild.InTree.targets" />
42+
<PropertyGroup>
43+
<!-- Import after SDK targets in order to override R2R-related targets in the SDK -->
44+
<AfterMicrosoftNETSdkTargets Condition="'$(PublishReadyToRun)' == 'true' and '$(Crossgen2SdkOverrideTargetsPath)' != ''">$(Crossgen2SdkOverrideTargetsPath)</AfterMicrosoftNETSdkTargets>
45+
<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MonoProjectRoot)\msbuild\apple\build\AppleBuild.InTree.targets</AfterMicrosoftNETSdkTargets>
46+
</PropertyGroup>
3847

3948
<Target Name="BuildAppBundle" AfterTargets="$(BuildAppBundleAfterTargets)" DependsOnTargets="$(BuildAppBundleDependsOnTargets)"/>
4049
<Target Name="_SetAppleGenerateAppBundleProps" Condition="'$(TargetOS)' != 'ios' and '$(ArchiveTests)' != 'true'" BeforeTargets="_AppleGenerateAppBundle">

src/tasks/AppleAppBuilder/AppleAppBuilder.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<ItemGroup>
1111
<EmbeddedResource Include="Templates\*.*" />
1212
<EmbeddedResource Include="$(CoreClrProjectRoot)hosts\inc\coreclrhost.h" Link="Templates\coreclrhost.h" />
13+
<EmbeddedResource Include="$(SharedNativeRoot)corehost\host_runtime_contract.h" Link="Templates\host_runtime_contract.h" />
1314
</ItemGroup>
1415
<ItemGroup>
1516
<Compile Include="AppleAppBuilder.cs" />

src/tasks/AppleAppBuilder/Templates/CMakeLists.txt.template

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ add_custom_command(
7979
if ls -1 $CODESIGNING_FOLDER_PATH/*.dylib 2>/dev/null | grep -q .\; then
8080
codesign --force --sign \"$SIGN_IDENTITY\" --timestamp $CODESIGNING_FOLDER_PATH/*.dylib\;
8181
fi\;
82+
if ls -1 $CODESIGNING_FOLDER_PATH/Contents/Resources/*.r2r.dylib 2>/dev/null | grep -q .\; then
83+
codesign --force --sign \"$SIGN_IDENTITY\" --timestamp $CODESIGNING_FOLDER_PATH/Contents/Resources/*.r2r.dylib\;
84+
fi\;
85+
if ls -1 $CODESIGNING_FOLDER_PATH/*.r2r.dylib 2>/dev/null | grep -q .\; then
86+
codesign --force --sign \"$SIGN_IDENTITY\" --timestamp $CODESIGNING_FOLDER_PATH/*.r2r.dylib\;
87+
fi\;
8288
fi\;
8389
fi
8490
)

src/tasks/AppleAppBuilder/Templates/runtime-coreclr.m

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#import <Foundation/Foundation.h>
55
#include "coreclrhost.h"
6+
#include "host_runtime_contract.h"
67
#include <TargetConditionals.h>
78
#import <os/log.h>
89
#include <sys/stat.h>
@@ -68,7 +69,7 @@
6869
return strdup([joined UTF8String]);
6970
}
7071

71-
void*
72+
const void*
7273
pinvoke_override (const char *libraryName, const char *entrypointName)
7374
{
7475
if (!strcmp (libraryName, "__Internal"))
@@ -79,6 +80,75 @@
7980
return NULL;
8081
}
8182

83+
#include <mach-o/dyld.h>
84+
#include <mach-o/loader.h>
85+
size_t get_image_size(const struct mach_header_64* header)
86+
{
87+
const struct load_command* cmd = (const struct load_command*)((const char*)header + sizeof(struct mach_header_64));
88+
89+
size_t image_size = 0;
90+
for (uint32_t j = 0; j < header->ncmds; ++j)
91+
{
92+
if (cmd->cmd == LC_SEGMENT_64)
93+
{
94+
const struct segment_command_64* seg = (const struct segment_command_64*)cmd;
95+
size_t end_addr = (size_t)(seg->vmaddr + seg->vmsize);
96+
if (end_addr > image_size)
97+
image_size = end_addr;
98+
}
99+
100+
cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize);
101+
}
102+
103+
return image_size;
104+
}
105+
106+
bool get_native_code_data(const struct host_runtime_contract_native_code_context* context, struct host_runtime_contract_native_code_data* data)
107+
{
108+
if (!context || !data || !context->assembly_path || !context->owner_composite_name)
109+
return false;
110+
111+
// Look for the owner composite R2R image in the same directory as the assembly
112+
char r2r_path[PATH_MAX];
113+
const char *last_slash = strrchr(context->assembly_path, '/');
114+
size_t dir_len = last_slash ? (size_t)(last_slash - context->assembly_path) : 0;
115+
if (dir_len >= sizeof(r2r_path) - 1)
116+
return false;
117+
118+
strncpy(r2r_path, context->assembly_path, dir_len);
119+
int written = snprintf(r2r_path + dir_len, sizeof(r2r_path) - dir_len, "/%s", context->owner_composite_name);
120+
if (written <= 0 || (size_t)written >= sizeof(r2r_path) - dir_len)
121+
return false;
122+
123+
void* handle = dlopen(r2r_path, RTLD_LAZY | RTLD_LOCAL);
124+
if (handle == NULL)
125+
return false;
126+
127+
void* r2r_header = dlsym(handle, "RTR_HEADER");
128+
if (r2r_header == NULL)
129+
{
130+
dlclose(handle);
131+
return false;
132+
}
133+
134+
Dl_info info;
135+
if (dladdr(r2r_header, &info) == 0)
136+
{
137+
dlclose(handle);
138+
return false;
139+
}
140+
141+
// The base address points to the Mach header
142+
void* base_address = info.dli_fbase;
143+
const struct mach_header_64* header = (const struct mach_header_64*)base_address;
144+
145+
data->size = sizeof(struct host_runtime_contract_native_code_data);
146+
data->r2r_header_ptr = r2r_header;
147+
data->image_size = get_image_size(header);
148+
data->image_base = base_address;
149+
return true;
150+
}
151+
82152
void
83153
mono_ios_runtime_init (void)
84154
{
@@ -116,15 +186,22 @@
116186
#endif
117187
assert (res > 0);
118188

119-
char pinvoke_override_addr [16];
120-
sprintf (pinvoke_override_addr, "%p", &pinvoke_override);
189+
// Contract lasts the lifetime of the app. The app exists before the end of this function.
190+
struct host_runtime_contract host_contract = {
191+
.size = sizeof(struct host_runtime_contract),
192+
.pinvoke_override = &pinvoke_override,
193+
.get_native_code_data = &get_native_code_data
194+
};
195+
196+
char contract_str[19]; // 0x + 16 hex digits + '\0'
197+
snprintf(contract_str, 19, "0x%zx", (size_t)(&host_contract));
121198

122199
// TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES
123200
const char *appctx_keys [] = {
124201
"RUNTIME_IDENTIFIER",
125202
"APP_CONTEXT_BASE_DIRECTORY",
126203
"TRUSTED_PLATFORM_ASSEMBLIES",
127-
"PINVOKE_OVERRIDE",
204+
"HOST_RUNTIME_CONTRACT",
128205
#if !defined(INVARIANT_GLOBALIZATION)
129206
"ICU_DAT_FILE_PATH"
130207
#endif
@@ -133,7 +210,7 @@
133210
APPLE_RUNTIME_IDENTIFIER,
134211
bundle,
135212
compute_trusted_platform_assemblies(),
136-
pinvoke_override_addr,
213+
contract_str,
137214
#if !defined(INVARIANT_GLOBALIZATION)
138215
icu_dat_path
139216
#endif

src/tasks/AppleAppBuilder/Xcode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ public string GenerateCMake(
618618
{
619619
File.WriteAllText(Path.Combine(binDir, "coreclrhost.h"),
620620
Utils.GetEmbeddedResource("coreclrhost.h"));
621+
File.WriteAllText(Path.Combine(binDir, "host_runtime_contract.h"),
622+
Utils.GetEmbeddedResource("host_runtime_contract.h"));
621623

622624
// NOTE: Library mode is not supported yet
623625
File.WriteAllText(Path.Combine(binDir, "runtime.m"),

0 commit comments

Comments
 (0)