Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions dotnet/targets/Xamarin.Shared.Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,23 @@
<CustomNativeMain Condition="'$(OutputType)' == 'Exe'">true</CustomNativeMain>
</PropertyGroup>

<!-- ReadyToRun configuration for CoreCLR -->
<PropertyGroup Condition="'$(UseMonoRuntime)' == 'false' And '$(_PlatformName)' != 'macOS'">
<PublishReadyToRun Condition="'$(PublishReadyToRun)' == ''">true</PublishReadyToRun>
<PublishReadyToRunComposite Condition="'$(PublishReadyToRun)' == 'true'">true</PublishReadyToRunComposite>
<PublishReadyToRunContainerFormat Condition="'$(PublishReadyToRun)' == 'true'">macho</PublishReadyToRunContainerFormat>
<StripSymbols Condition="'$(PublishReadyToRun)' == 'true'">true</StripSymbols>
</PropertyGroup>

<!-- Exclude user assemblies from R2R composite so they run interpreted for debugging -->
<ItemGroup Condition="'$(UseMonoRuntime)' == 'false' And '$(_PlatformName)' != 'macOS' And '$(PublishReadyToRun)' == 'true' And '$(Configuration)' != 'Release'">
<PublishReadyToRunExclude Include="$(TargetFileName)" />
</ItemGroup>

<ItemGroup Condition="'$(UseMonoRuntime)' == 'false' And '$(_PlatformName)' != 'macOS' And '$(PublishReadyToRun)' != 'true'">
<_BundlerEnvironmentVariables Include="DOTNET_ReadyToRun" Value="0" />
</ItemGroup>

<!-- Compute _SdkIsSimulator from the RuntimeIdentifier -->
<PropertyGroup>
<_SdkIsSimulator Condition="'$(RuntimeIdentifier)' != '' And '$(_SdkIsSimulator)' == ''">$(RuntimeIdentifier.Contains('simulator'))</_SdkIsSimulator>
Expand Down
51 changes: 44 additions & 7 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1246,13 +1246,14 @@
'%(ResolvedFileToPublish.NuGetPackageId)' == '$(_MonoNugetPackageId)'
"
/>
</ItemGroup>

<!-- CoreCLR: these are variables currently needed to make CoreCLR work -->
<ItemGroup Condition="'$(UseMonoRuntime)' == 'false' And '$(_PlatformName)' != 'macOS'">
<!-- Only the interpreter works so far, so make sure only the interpreter executes and that everything is executed with the interpreter -->
<_BundlerEnvironmentVariables Include="DOTNET_Interpreter" Value="%2A%21%2A" /> <!-- This is the string "*!*" url encoded -->
<_BundlerEnvironmentVariables Include="DOTNET_ReadyToRun" Value="0" />
<!-- Don't link with libclrjit.dylib when using CoreCLR on Apple mobile platforms -->
<_MonoLibrary
Remove="@(_MonoLibrary)"
Condition=" '$(_XamarinRuntime)' == 'CoreCLR' And
'$(_PlatformName)' != 'macOS' And
'%(Filename)' == 'libclrjit'
"
/>
</ItemGroup>
</Target>

Expand Down Expand Up @@ -2095,6 +2096,19 @@
<ResolvedFileToPublish Remove="@(_CreateDumpExecutable)" />
<ResolvedFileToPublish Include="@(_CreateDumpExecutable)" Condition="'$(BundleCreateDump)' == 'true'" />

<!-- Remove libclrjit.dylib when using CoreCLR on Apple mobile platforms -->
<ResolvedFileToPublish
Remove="@(ResolvedFileToPublish)"
Condition=" '$(_XamarinRuntime)' == 'CoreCLR' And
'$(_PlatformName)' != 'macOS' And
'%(ResolvedFileToPublish.Filename)' == 'libclrjit' And
'%(ResolvedFileToPublish.Extension)' == '.dylib' And
'%(ResolvedFileToPublish.AssetType)' == 'native' And
'%(ResolvedFileToPublish.RuntimeIdentifier)' == '$(RuntimeIdentifier)' And
'%(ResolvedFileToPublish.NuGetPackageId)' == '$(_MonoNugetPackageId)'
"
/>

<!-- Remove any dylibs Mono told us not to link with -->
<ResolvedFileToPublish
Remove="@(_MonoRuntimeComponentDontLink -> '$(_MonoRuntimePackPath)/native/%(Identity)')"
Expand Down Expand Up @@ -2753,4 +2767,27 @@ global using nfloat = global::System.Runtime.InteropServices.NFloat%3B
<Import Project="dotnet-xcsync.targets" />
<Import Project="Microsoft.MaciOS.Sdk.Xcode.targets" />

<!-- TODO: Remove ResolveReadyToRunCompilers target -->
<Target Name="ResolveReadyToRunCompilers" Condition="'$(PublishReadyToRun)' == 'true' And '$(UseMonoRuntime)' != 'true'">
<PropertyGroup>
<_Crossgen2Path Condition="'$(Crossgen2Path)' != ''">$(Crossgen2Path)</_Crossgen2Path>
<_Crossgen2Path Condition="'$(Crossgen2Path)' == ''">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..', '..', 'packs', 'Microsoft.NETCore.App.Runtime.$(_PlatformName.ToLowerInvariant())-$(RuntimeIdentifier.Split('-')[1])', '$(BundledNETCoreAppPackageVersion)', 'tools', 'crossgen2'))</_Crossgen2Path>

<_TargetArch>$(RuntimeIdentifier.Split('-')[1])</_TargetArch>
<_TargetOS>$(RuntimeIdentifier.Split('-')[0])</_TargetOS>
</PropertyGroup>

<ItemGroup>
<Crossgen2Tool Include="$(_Crossgen2Path)"
TargetArch="$(_TargetArch)"
TargetOS="$(_TargetOS)"
PerfmapFormatVersion="$(PublishReadyToRunPerfmapFormatVersion)"/>
</ItemGroup>

<Message Text="Using crossgen2: $(_Crossgen2Path)" Importance="high" />
<Message Text=" RuntimeIdentifier: $(RuntimeIdentifier)" Importance="high" />
<Message Text=" TargetArch: $(_TargetArch)" Importance="high" />
<Message Text=" TargetOS: $(_TargetOS)" Importance="high" />
</Target>

</Project>
1 change: 1 addition & 0 deletions runtime/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ bindings-generated.m
*.dylib
*.o
coreclrhost.h
host_runtime_contract.h
8 changes: 6 additions & 2 deletions runtime/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ IOS_SIMULATOR_ARCHITECTURES+=x86_64
IOS_DEVICE_ARCHITECTURES+=arm64

coreclrhost.h: Makefile
$(Q_CURL) curl -L --retry 3 --retry-all-errors --fail --output "[email protected]" https://raw.githubusercontent.com/dotnet/runtime/f1b8d5a4448d072c9d390744777a87921e45bf2f/src/coreclr/hosts/inc/coreclrhost.h
$(Q_CURL) curl -L --retry 3 --retry-all-errors --fail --output "[email protected]" https://raw.githubusercontent.com/dotnet/runtime/main/src/coreclr/hosts/inc/coreclrhost.h
$(Q) mv "[email protected]" "$@"

coreclr-bridge.m: coreclrhost.h
host_runtime_contract.h: Makefile
$(Q_CURL) curl -L --retry 3 --retry-all-errors --fail --output "[email protected]" https://raw.githubusercontent.com/dotnet/runtime/main/src/native/corehost/host_runtime_contract.h
$(Q) mv "[email protected]" "$@"

coreclr-bridge.m: coreclrhost.h host_runtime_contract.h

xamarin/mono-runtime.h: mono-runtime.h.t4 exports.t4
$(Q_GEN) $(TT) $< -o $@
Expand Down
3 changes: 2 additions & 1 deletion runtime/coreclr-bridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
{
struct TrackedObjectInfo *info = (struct TrackedObjectInfo *) ptr;
info->data->flags = (enum NSObjectFlags) (info->data->flags | NSObjectFlagsInFinalizerQueue);
LOG_CORECLR (stderr, "%s (%p) flags: %i\n", __func__, ptr, (int) info->flags);
LOG_CORECLR (stderr, "%s (%p) flags: %i\n", __func__, ptr, (int) info->data->flags);
}

void
Expand Down Expand Up @@ -492,6 +492,7 @@
xamarin_bridge_compute_properties (propertyCount, propertyKeys, propertyValues, &combinedPropertyCount, &combinedPropertyKeys, &combinedPropertyValues);

const char *executablePath = [[[[NSBundle mainBundle] executableURL] path] UTF8String];

rv = coreclr_initialize (
executablePath,
xamarin_executable_name,
Expand Down
108 changes: 103 additions & 5 deletions runtime/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <sys/stat.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>

#include "product.h"
#include "shared.h"
Expand All @@ -22,6 +24,7 @@
#include "xamarin/monovm-bridge.h"
#else
#include "xamarin/coreclr-bridge.h"
#include "host_runtime_contract.h"
#endif

#if defined (DEBUG)
Expand Down Expand Up @@ -2436,37 +2439,132 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
return rv;
}

#if defined (CORECLR_RUNTIME)
size_t get_image_size(void* base_address)
{
uint32_t image_count = _dyld_image_count();
for (uint32_t i = 0; i < image_count; ++i)
{
const struct mach_header_64* header = (const struct mach_header_64*)_dyld_get_image_header(i);
if ((const void*)header != base_address)
continue;

const struct load_command* cmd = (const struct load_command*)((const char*)header + sizeof(struct mach_header_64));

size_t image_size = 0;
for (uint32_t j = 0; j < header->ncmds; ++j)
{
if (cmd->cmd == LC_SEGMENT_64)
{
const struct segment_command_64* seg = (const struct segment_command_64*)cmd;
size_t end_addr = (size_t)(seg->vmaddr + seg->vmsize);
if (end_addr > image_size)
image_size = end_addr;
}

cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize);
}

return image_size;
}

return 0;
}

bool get_native_code_data(const struct host_runtime_contract_native_code_context* context, struct host_runtime_contract_native_code_data* data)
{
if (!context || !data || !context->assembly_path || !context->owner_composite_name)
return false;

// Look for the owner composite R2R image in the same directory as the assembly
char r2r_path[PATH_MAX];
const char *last_slash = strrchr(context->assembly_path, '/');
size_t dir_len = last_slash ? (size_t)(last_slash - context->assembly_path) : 0;
if (dir_len >= sizeof(r2r_path) - 1)
return false;

strncpy(r2r_path, context->assembly_path, dir_len);
int written = snprintf(r2r_path + dir_len, sizeof(r2r_path) - dir_len, "/%s", context->owner_composite_name);
if (written <= 0 || (size_t)written >= sizeof(r2r_path) - dir_len)
return false;

void* handle = dlopen(r2r_path, RTLD_LAZY | RTLD_LOCAL);
if (handle == NULL) {
return false;
}

void* r2r_header = dlsym(handle, "RTR_HEADER");
if (r2r_header == NULL)
{
dlclose(handle);
return false;
}

Dl_info info;
if (dladdr(r2r_header, &info) == 0)
{
dlclose(handle);
return false;
}

data->size = sizeof(struct host_runtime_contract_native_code_data);
data->r2r_header_ptr = r2r_header;
data->image_size = get_image_size(info.dli_fbase);
data->image_base = info.dli_fbase;

return true;
}
#endif // defined (CORECLR_RUNTIME)

void
xamarin_vm_initialize ()
{
#if defined (CORECLR_RUNTIME)
struct host_runtime_contract host_contract = {
.size = sizeof(struct host_runtime_contract),
.pinvoke_override = &xamarin_pinvoke_override,
.get_native_code_data = &get_native_code_data
};

char contract_str[19]; // 0x + 16 hex digits + '\0'
snprintf(contract_str, 19, "0x%zx", (size_t)(&host_contract));
#else
char *pinvokeOverride = xamarin_strdup_printf ("%p", &xamarin_pinvoke_override);
#endif

char *trusted_platform_assemblies = xamarin_compute_trusted_platform_assemblies ();
char *native_dll_search_directories = xamarin_compute_native_dll_search_directories ();

// All the properties we pass here must also be listed in the _RuntimeConfigReservedProperties item group
// for the _CreateRuntimeConfiguration target in dotnet/targets/Xamarin.Shared.Sdk.targets.
const char *propertyKeys[] = {
"APP_CONTEXT_BASE_DIRECTORY", // path to where the managed assemblies are (usually at least - RID-specific assemblies will be in subfolders)
"APP_PATHS",
#if defined (CORECLR_RUNTIME)
"HOST_RUNTIME_CONTRACT",
#else
"PINVOKE_OVERRIDE",
#endif
"TRUSTED_PLATFORM_ASSEMBLIES",
"NATIVE_DLL_SEARCH_DIRECTORIES",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is NATIVE_DLL_SEARCH_DIRECTORIES removed? It doesn't look related to R2R (it's also removed for Mono).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should revert that. I see it’s used for P/Invoke path resolution. I tried to reduce the scope when testing R2R and it wasn't needed for the MAUI sample.

"RUNTIME_IDENTIFIER",
};
const char *propertyValues[] = {
xamarin_get_bundle_path (),
xamarin_get_bundle_path (),
#if defined (CORECLR_RUNTIME)
contract_str,
#else
pinvokeOverride,
#endif
trusted_platform_assemblies,
native_dll_search_directories,
RUNTIMEIDENTIFIER,
};
static_assert (sizeof (propertyKeys) == sizeof (propertyValues), "The number of keys and values must be the same.");

int propertyCount = (int) (sizeof (propertyValues) / sizeof (propertyValues [0]));
bool rv = xamarin_bridge_vm_initialize (propertyCount, propertyKeys, propertyValues);

#if !defined (CORECLR_RUNTIME)
xamarin_free (pinvokeOverride);
#endif
xamarin_free (trusted_platform_assemblies);
xamarin_free (native_dll_search_directories);

Expand Down Expand Up @@ -2502,7 +2600,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
return rv;
}

void*
const void*
xamarin_pinvoke_override (const char *libraryName, const char *entrypointName)
{

Expand Down
2 changes: 1 addition & 1 deletion runtime/xamarin/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ MonoAssembly* xamarin_assembly_preload_hook (MonoAssemblyName *aname, char **ass
void xamarin_handle_bridge_exception (GCHandle gchandle, const char *method);
void xamarin_vm_initialize ();
bool xamarin_bridge_vm_initialize (int propertyCount, const char **propertyKeys, const char **propertyValues);
void* xamarin_pinvoke_override (const char *libraryName, const char *entrypointName);
const void* xamarin_pinvoke_override (const char *libraryName, const char *entrypointName);
void xamarin_bridge_call_runtime_initialize (struct InitializationOptions* options, GCHandle* exception_gchandle);
void xamarin_bridge_register_product_assembly (GCHandle* exception_gchandle);
MonoMethod * xamarin_bridge_get_mono_method (MonoReflectionMethod *method);
Expand Down