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
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
/// JniNativeMethod* methods = stackalloc JniNativeMethod[2];
/// methods[0] = new JniNativeMethod(&__utf8_0, &__utf8_1, &n_OnCreate_uco_0);
/// methods[1] = new JniNativeMethod(&__utf8_2, &__utf8_3, &nctor_0_uco);
/// JniEnvironment.Types.RegisterNatives(jniType.PeerReference, new ReadOnlySpan<JniNativeMethod>(methods, 2));
/// unsafe {
/// // SAFETY: methods points to the stackalloc buffer filled above; the UTF-8 fields and UCO entry points are module-lifetime data.
/// JniEnvironment.Types.RegisterNatives(jniType.PeerReference, new ReadOnlySpan<JniNativeMethod>(methods, 2));
/// }
/// }
/// }
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ internal static string ToLegacyCrc64 (string ns, string assemblyName)
int byteCount = GetNamespaceAssemblyUtf8ByteCount (ns, assemblyName);
byte[] rented = ArrayPool<byte>.Shared.Rent (byteCount);
try {
int bytesWritten = GetNamespaceAssemblyUtf8Bytes (ns, assemblyName, rented.AsSpan (0, byteCount));
int bytesWritten;
unsafe {
// SAFETY: rented is at least byteCount bytes, which is the exact UTF-8 byte count for the data written by GetNamespaceAssemblyUtf8Bytes.
bytesWritten = GetNamespaceAssemblyUtf8Bytes (ns, assemblyName, rented.AsSpan (0, byteCount));
}
ulong crc = ulong.MaxValue;
ulong length = 0;
Crc64Helper.HashCore (rented, 0, bytesWritten, ref crc, ref length);
Expand All @@ -32,7 +36,11 @@ internal static string ToCrc64 (string ns, string assemblyName)
? stackalloc byte [stackallocThresholdBytes]
: new byte [byteCount];

int bytesWritten = GetNamespaceAssemblyUtf8Bytes (ns, assemblyName, utf8Buffer.Slice (0, byteCount));
int bytesWritten;
unsafe {
// SAFETY: utf8Buffer is at least byteCount bytes, which is the exact UTF-8 byte count for the data written by GetNamespaceAssemblyUtf8Bytes.
bytesWritten = GetNamespaceAssemblyUtf8Bytes (ns, assemblyName, utf8Buffer.Slice (0, byteCount));
}
Span<byte> hash = stackalloc byte [8];
System.IO.Hashing.Crc64.Hash (utf8Buffer.Slice (0, bytesWritten), hash);
ulong hashValue = BinaryPrimitives.ReadUInt64LittleEndian (hash);
Expand All @@ -45,12 +53,16 @@ static int GetNamespaceAssemblyUtf8ByteCount (string ns, string assemblyName)
return System.Text.Encoding.UTF8.GetByteCount (ns) + 1 + System.Text.Encoding.UTF8.GetByteCount (assemblyName);
}

/// <safety>
/// <paramref name="destination"/> must contain at least <see cref="GetNamespaceAssemblyUtf8ByteCount"/>
/// bytes for <paramref name="ns"/> and <paramref name="assemblyName"/>.
/// </safety>
static unsafe int GetNamespaceAssemblyUtf8Bytes (string ns, string assemblyName, Span<byte> destination)
{
int bytesWritten = 0;
int bytesWritten;
fixed (char* nsPtr = ns)
fixed (byte* destinationPtr = destination) {
bytesWritten += System.Text.Encoding.UTF8.GetBytes (nsPtr, ns.Length, destinationPtr, destination.Length);
bytesWritten = System.Text.Encoding.UTF8.GetBytes (nsPtr, ns.Length, destinationPtr, destination.Length);
}

destination [bytesWritten++] = (byte) ':';
Expand Down
13 changes: 8 additions & 5 deletions src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static void InitializeCore (ITypeMap typeMap)
}
}

internal static unsafe void RegisterNativeMethods ()
internal static void RegisterNativeMethods ()
{
lock (s_initLock) {
if (s_nativeMethodsRegistered) {
Expand All @@ -142,10 +142,13 @@ internal static unsafe void RegisterNativeMethods ()
}

using var runtimeClass = new JniType ("mono/android/Runtime"u8);
fixed (byte* name = "registerNatives"u8, sig = "(Ljava/lang/Class;)V"u8) {
var onRegisterNatives = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, IntPtr, void>)&OnRegisterNatives;
var method = new JniNativeMethod (name, sig, onRegisterNatives);
JniEnvironment.Types.RegisterNatives (runtimeClass.PeerReference, [method]);
unsafe {
// SAFETY: the UTF-8 literals are pinned for the duration of RegisterNatives, and OnRegisterNatives is a static UCO entry point.
fixed (byte* name = "registerNatives"u8, sig = "(Ljava/lang/Class;)V"u8) {
var onRegisterNatives = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, IntPtr, void>)&OnRegisterNatives;
var method = new JniNativeMethod (name, sig, onRegisterNatives);
JniEnvironment.Types.RegisterNatives (runtimeClass.PeerReference, [method]);
}
}
s_nativeMethodsRegistered = true;
}
Expand Down