Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup arrays and annotate for nullability #185

Merged
merged 10 commits into from
Oct 5, 2024
Merged
2 changes: 1 addition & 1 deletion Il2CppInterop.Runtime/IL2CPP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public static IntPtr GetIl2CppMethod(IntPtr clazz, bool isGeneric, string method
return new string(chars, 0, length);
}

public static IntPtr ManagedStringToIl2Cpp(string str)
public static IntPtr ManagedStringToIl2Cpp(string? str)
{
if (str == null) return IntPtr.Zero;

Expand Down
21 changes: 18 additions & 3 deletions Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Il2CppInterop.Runtime.Runtime;

namespace Il2CppInterop.Runtime.InteropTypes.Arrays;

Expand All @@ -10,6 +12,11 @@ protected Il2CppArrayBase(IntPtr pointer) : base(pointer)
{
}

/// <summary>
/// The pointer to the first element in the array.
/// </summary>
private protected unsafe IntPtr ArrayStartPointer => IntPtr.Add(Pointer, sizeof(Il2CppObject) /* base */ + sizeof(void*) /* bounds */ + sizeof(nuint) /* max_length */);

public int Length => (int)IL2CPP.il2cpp_array_length(Pointer);

public abstract IEnumerator GetEnumerator();
Expand All @@ -18,6 +25,13 @@ private protected static bool ThrowImmutableLength()
{
throw new NotSupportedException("Arrays have immutable length");
}

private protected void ThrowIfIndexOutOfRange(int index)
{
if ((uint)index >= (uint)Length)
throw new ArgumentOutOfRangeException(nameof(index),
"Array index may not be negative or above length of the array");
}
}
public abstract class Il2CppArrayBase<T> : Il2CppArrayBase, IList<T>, IReadOnlyList<T>
{
Expand Down Expand Up @@ -102,7 +116,8 @@ protected static void StaticCtorBody(Type ownType)
Il2CppClassPointerStore<Il2CppArrayBase<T>>.CreatedTypeRedirect = ownType;
}

public static implicit operator T[](Il2CppArrayBase<T> il2CppArray)
[return: NotNullIfNotNull(nameof(il2CppArray))]
public static implicit operator T[]?(Il2CppArrayBase<T>? il2CppArray)
{
if (il2CppArray == null)
return null;
Expand Down Expand Up @@ -143,7 +158,7 @@ public IndexEnumerator(Il2CppArrayBase<T> array)

public void Dispose()
{
myArray = null;
myArray = null!;
Copy link
Member

Choose a reason for hiding this comment

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

Does it even make sense to null it out?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not really in my opinion

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But I don't want to change it either

}

public bool MoveNext()
Expand All @@ -156,7 +171,7 @@ public void Reset()
myIndex = -1;
}

object IEnumerator.Current => Current;
object? IEnumerator.Current => Current;
public T Current => myArray[myIndex];
}
}
61 changes: 21 additions & 40 deletions Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppReferenceArray.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Il2CppInterop.Runtime.Runtime;

namespace Il2CppInterop.Runtime.InteropTypes.Arrays;

public class Il2CppReferenceArray<T> : Il2CppArrayBase<T> where T : Il2CppObjectBase
public class Il2CppReferenceArray<T> : Il2CppArrayBase<T> where T : Il2CppObjectBase?
{
private static ConstructorInfo ourCachedInstanceCtor;
private static readonly int ourElementTypeSize;
private static readonly bool ourElementIsValueType;

Expand Down Expand Up @@ -41,27 +41,18 @@ public Il2CppReferenceArray(T[] arr) : base(AllocateArray(arr.Length))

public override T this[int index]
{
get
{
if (index < 0 || index >= Length)
throw new ArgumentOutOfRangeException(nameof(index),
"Array index may not be negative or above length of the array");
var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size);
var elementPointer = IntPtr.Add(arrayStartPointer, index * ourElementTypeSize);
return WrapElement(elementPointer);
}
set
{
if (index < 0 || index >= Length)
throw new ArgumentOutOfRangeException(nameof(index),
"Array index may not be negative or above length of the array");
var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size);
var elementPointer = IntPtr.Add(arrayStartPointer, index * ourElementTypeSize);
StoreValue(elementPointer, value?.Pointer ?? IntPtr.Zero);
}
get => WrapElement(GetElementPointer(index))!;
set => StoreValue(GetElementPointer(index), value?.Pointer ?? IntPtr.Zero);
}

private IntPtr GetElementPointer(int index)
{
ThrowIfIndexOutOfRange(index);
return IntPtr.Add(ArrayStartPointer, index * ourElementTypeSize);
}

public static implicit operator Il2CppReferenceArray<T>(T[] arr)
[return: NotNullIfNotNull(nameof(arr))]
public static implicit operator Il2CppReferenceArray<T>?(T[]? arr)
{
if (arr == null) return null;

Expand All @@ -77,8 +68,8 @@ private static unsafe void StoreValue(IntPtr targetPointer, IntPtr valuePointer)

var valueRawPointer = (byte*)IL2CPP.il2cpp_object_unbox(valuePointer);
var targetRawPointer = (byte*)targetPointer;
for (var i = 0; i < ourElementTypeSize; i++)
targetRawPointer[i] = valueRawPointer[i];

Unsafe.CopyBlock(targetRawPointer, valueRawPointer, (uint)ourElementTypeSize);
}
else
{
Expand All @@ -88,25 +79,15 @@ private static unsafe void StoreValue(IntPtr targetPointer, IntPtr valuePointer)

private static unsafe T? WrapElement(IntPtr memberPointer)
{
if (ourCachedInstanceCtor == null) ourCachedInstanceCtor = typeof(T).GetConstructor(new[] { typeof(IntPtr) });

if (ourElementIsValueType)
return (T)ourCachedInstanceCtor.Invoke(new object[]
{IL2CPP.il2cpp_value_box(Il2CppClassPointerStore<T>.NativeClassPtr, memberPointer)});

var referencePointer = *(IntPtr*)memberPointer;
if (referencePointer == IntPtr.Zero) return null;
memberPointer = IL2CPP.il2cpp_value_box(Il2CppClassPointerStore<T>.NativeClassPtr, memberPointer);
else
memberPointer = *(IntPtr*)memberPointer;

if (typeof(Il2CppObjectBase).IsAssignableFrom(typeof(T)))
{
var typePtr = Il2CppClassPointerStore<T>.NativeClassPtr;
var referenceClassPtr = IL2CPP.il2cpp_object_get_class(referencePointer);
if (RuntimeSpecificsStore.IsInjected(typePtr) &&
IL2CPP.il2cpp_class_is_assignable_from(typePtr, referenceClassPtr))
return ClassInjectorBase.GetMonoObjectFromIl2CppPointer(referencePointer) as T;
}
if (memberPointer == IntPtr.Zero)
return default;

return (T)ourCachedInstanceCtor.Invoke(new object[] { referencePointer });
return Il2CppObjectPool.Get<T>(memberPointer);
}

private static IntPtr AllocateArray(long size)
Expand Down
34 changes: 13 additions & 21 deletions Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStringArray.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;

namespace Il2CppInterop.Runtime.InteropTypes.Arrays;

Expand All @@ -17,35 +18,26 @@ public Il2CppStringArray(long size) : base(AllocateArray(size))
{
}

public Il2CppStringArray(string[] arr) : base(AllocateArray(arr.Length))
public Il2CppStringArray(string?[] arr) : base(AllocateArray(arr.Length))
{
for (var i = 0; i < arr.Length; i++)
this[i] = arr[i];
}

#nullable disable
public override unsafe string this[int index]
{
get
{
if (index < 0 || index >= Length)
throw new ArgumentOutOfRangeException(nameof(index),
"Array index may not be negative or above length of the array");
var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size);
var elementPointer = IntPtr.Add(arrayStartPointer, index * IntPtr.Size);
return IL2CPP.Il2CppStringToManaged(*(IntPtr*)elementPointer);
}
set
{
if (index < 0 || index >= Length)
throw new ArgumentOutOfRangeException(nameof(index),
"Array index may not be negative or above length of the array");
var arrayStartPointer = IntPtr.Add(Pointer, 4 * IntPtr.Size);
var elementPointer = IntPtr.Add(arrayStartPointer, index * IntPtr.Size);
*(IntPtr*)elementPointer = IL2CPP.ManagedStringToIl2Cpp(value);
}
get => IL2CPP.Il2CppStringToManaged(*GetElementPointer(index));
set => *GetElementPointer(index) = IL2CPP.ManagedStringToIl2Cpp(value);
}
#nullable enable
private unsafe IntPtr* GetElementPointer(int index)
{
ThrowIfIndexOutOfRange(index);
return (IntPtr*)IntPtr.Add(ArrayStartPointer, index * IntPtr.Size).ToPointer();
}

public static implicit operator Il2CppStringArray(string[] arr)
[return: NotNullIfNotNull(nameof(arr))]
public static implicit operator Il2CppStringArray?(string?[]? arr)
{
if (arr == null) return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ static Il2CppStructArray()
StaticCtorBody(typeof(Il2CppStructArray<T>));
}

/// <summary>
/// The pointer to the first element in the array.
/// </summary>
private IntPtr ArrayStartPointer => IntPtr.Add(Pointer, 4 * IntPtr.Size);

public Il2CppStructArray(IntPtr nativeObject) : base(nativeObject)
{
}
Expand Down
Loading