-
-
Save mattwarren/a248782078d15c4ca2999f986ba7eacb to your computer and use it in GitHub Desktop.
See https://github.com/dotnet/corert/blob/master/src/Test.CoreLib/readme.md for more info
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/Runtime.Base/src/System/Exception.cs b/src/Runtime.Base/src/System/Exception.cs | |
index cda417df7..3cf83434b 100644 | |
--- a/src/Runtime.Base/src/System/Exception.cs | |
+++ b/src/Runtime.Base/src/System/Exception.cs | |
@@ -87,4 +87,25 @@ namespace System | |
{ | |
public OutOfMemoryException() { } | |
} | |
+ | |
+ internal class ObjectDisposedException : Exception | |
+ { | |
+ public ObjectDisposedException() { } | |
+ | |
+ public ObjectDisposedException(string msg) { } | |
+ } | |
+ | |
+ internal class DllNotFoundException : Exception | |
+ { | |
+ public DllNotFoundException() { } | |
+ | |
+ public DllNotFoundException(string msg) { } | |
+ } | |
+ | |
+ internal class EntryPointNotFoundException : Exception | |
+ { | |
+ public EntryPointNotFoundException() : base() { } | |
+ | |
+ public EntryPointNotFoundException(string msg) : base(msg) { } | |
+ } | |
} | |
diff --git a/src/Runtime.Base/src/System/Runtime/GCStress.cs b/src/Runtime.Base/src/System/Runtime/GCStress.cs | |
index f4b64ed21..ffc0b7875 100644 | |
--- a/src/Runtime.Base/src/System/Runtime/GCStress.cs | |
+++ b/src/Runtime.Base/src/System/Runtime/GCStress.cs | |
@@ -36,7 +36,7 @@ namespace System.Runtime | |
Head = Head.Next; | |
// notify redhawku.dll | |
- InternalCalls.RhpInitializeGcStress(); | |
+ //InternalCalls.RhpInitializeGcStress(); | |
#endif // FEATURE_GC_STRESS | |
} | |
diff --git a/src/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/Runtime.Base/src/System/Runtime/InternalCalls.cs | |
index e647e3ab0..0431c5bc0 100644 | |
--- a/src/Runtime.Base/src/System/Runtime/InternalCalls.cs | |
+++ b/src/Runtime.Base/src/System/Runtime/InternalCalls.cs | |
@@ -194,10 +194,10 @@ namespace System.Runtime | |
// | |
// internal calls for GC stress | |
// | |
- [RuntimeImport(Redhawk.BaseName, "RhpInitializeGcStress")] | |
- [MethodImpl(MethodImplOptions.InternalCall)] | |
- [ManuallyManaged(GcPollPolicy.Never)] | |
- internal extern static unsafe void RhpInitializeGcStress(); | |
+ //[RuntimeImport(Redhawk.BaseName, "RhpInitializeGcStress")] | |
+ //[MethodImpl(MethodImplOptions.InternalCall)] | |
+ //[ManuallyManaged(GcPollPolicy.Never)] | |
+ //internal extern static unsafe void RhpInitializeGcStress(); | |
#endif // FEATURE_GC_STRESS | |
[RuntimeImport(Redhawk.BaseName, "RhpEHEnumInitFromStackFrameIterator")] | |
diff --git a/src/Runtime.Base/src/System/Runtime/InteropServices/CharSet.cs b/src/Runtime.Base/src/System/Runtime/InteropServices/CharSet.cs | |
index 87d91c2c7..b7d0795e5 100644 | |
--- a/src/Runtime.Base/src/System/Runtime/InteropServices/CharSet.cs | |
+++ b/src/Runtime.Base/src/System/Runtime/InteropServices/CharSet.cs | |
@@ -11,7 +11,7 @@ namespace System.Runtime.InteropServices | |
// Generally you probably want to use Auto, which does the | |
// right thing 99% of the time. | |
- internal enum CharSet | |
+ public enum CharSet | |
{ | |
None = 1, // User didn't specify how to marshal strings. | |
Ansi = 2, // Strings should be marshalled as ANSI 1 byte chars. | |
diff --git a/src/Runtime.Base/src/System/Runtime/InteropServices/DllImportAttribute.cs b/src/Runtime.Base/src/System/Runtime/InteropServices/DllImportAttribute.cs | |
index 53a6fea04..4834423e9 100644 | |
--- a/src/Runtime.Base/src/System/Runtime/InteropServices/DllImportAttribute.cs | |
+++ b/src/Runtime.Base/src/System/Runtime/InteropServices/DllImportAttribute.cs | |
@@ -7,6 +7,9 @@ namespace System.Runtime.InteropServices | |
[AttributeUsage(AttributeTargets.Method)] | |
public sealed class DllImportAttribute : Attribute | |
{ | |
+ public string EntryPoint; | |
+ public CharSet CharSet; | |
+ public bool SetLastError; | |
public CallingConvention CallingConvention; | |
public DllImportAttribute(string dllName) | |
diff --git a/src/Runtime.Base/src/System/String.cs b/src/Runtime.Base/src/System/String.cs | |
index 0173be678..890f6e140 100644 | |
--- a/src/Runtime.Base/src/System/String.cs | |
+++ b/src/Runtime.Base/src/System/String.cs | |
@@ -54,14 +54,14 @@ namespace System | |
// This type does not override GetHashCode, Equals | |
#pragma warning disable 0661, 0660 | |
[StructLayout(LayoutKind.Sequential)] | |
- public class String | |
+ public partial class String | |
{ | |
#if BIT64 | |
private const int POINTER_SIZE = 8; | |
#else | |
private const int POINTER_SIZE = 4; | |
#endif | |
- // m_pEEType + m_stringLength | |
+ // m_pEEType + m_stringLength | |
internal const int FIRST_CHAR_OFFSET = POINTER_SIZE + sizeof(int); | |
// CS0169: The private field '{blah}' is never used | |
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs b/src/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs | |
index db6977ee5..8fa240d37 100644 | |
--- a/src/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs | |
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs | |
@@ -55,7 +55,9 @@ namespace Internal.Runtime | |
object[] newStorage = new object[requiredSize]; | |
if (existingStorage != null) | |
{ | |
- Array.Copy(existingStorage, newStorage, existingStorage.Length); | |
+ // TODO MattW FIX THIS!!! | |
+ //Array.Copy(existingStorage, newStorage, existingStorage.Length); | |
+ throw new InvalidOperationException(); | |
} | |
// Install the newly created array as thread static storage for the given module | |
diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs | |
index 79f5c2e83..1159cd81a 100644 | |
--- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs | |
+++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs | |
@@ -446,7 +446,7 @@ namespace System.Runtime.InteropServices | |
// which throws ObjectDisposed if someone passes an uninitialized WaitHandle into one of the Wait apis. We use an extension method | |
// because otherwise, the "null this" would trigger a NullReferenceException before we ever get to this check. | |
if (safeHandle == null) | |
- throw new ObjectDisposedException(SR.ObjectDisposed_Generic); | |
+ throw new ObjectDisposedException("ObjectDisposed_Generic"); // SR.ObjectDisposed_Generic); | |
safeHandle.DangerousAddRef_WithNoNullCheck(); | |
} | |
} | |
diff --git a/src/Test.CoreLib/src/System/Console.cs b/src/Test.CoreLib/src/System/Console.cs | |
new file mode 100644 | |
index 000000000..5ed92e2d5 | |
--- /dev/null | |
+++ b/src/Test.CoreLib/src/System/Console.cs | |
@@ -0,0 +1,49 @@ | |
+//using System.Text; | |
+//using System.Security; | |
+using Microsoft.Win32; | |
+using Microsoft.Win32.SafeHandles; | |
+ | |
+namespace System | |
+{ | |
+ // Code below 'borrowed' from https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/Internal/Console.cs | |
+ public static class Console | |
+ { | |
+ // Using static initialisers (or whatever these are) causes the program to hang!!!! | |
+ //private static readonly SafeFileHandle _outputHandle = | |
+ // new SafeFileHandle(Win32Native.GetStdHandle(Win32Native.STD_OUTPUT_HANDLE), false); | |
+ | |
+ public static unsafe void Write(string s) | |
+ { | |
+ // TODO MattW - Cheat, until we've implemented UnicodeEncoding.GetBytes(string) | |
+ // This is 'Hello World! (hard-coded!!)' in UTF8 | |
+ byte[] bytes = new byte[] { | |
+ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 32, | |
+ 40, 104, 97, 114, 100, 45, 99, 111, 100, 101, 100, 33, 33, 41 | |
+ }; | |
+ //byte[] bytes = Encoding.UTF8.GetBytes(s); | |
+ //byte [] bytes = UnicodeEncoding.GetString() | |
+ | |
+ Interop.mincore.OutputDebugString("Console.Write - (1) - " + s); | |
+ SafeFileHandle _outputHandle = | |
+ new SafeFileHandle(Win32Native.GetStdHandle(Win32Native.STD_OUTPUT_HANDLE), false); | |
+ Interop.mincore.OutputDebugString("Console.Write - (2)"); | |
+ fixed (byte* pBytes = bytes) | |
+ { | |
+ int bytesWritten; | |
+ Interop.mincore.OutputDebugString("Console.Write - (3)"); | |
+ Win32Native.WriteFile(_outputHandle, pBytes, bytes.Length, out bytesWritten, IntPtr.Zero); | |
+ Interop.mincore.OutputDebugString("Console.Write - (4)"); | |
+ } | |
+ } | |
+ | |
+ public static void WriteLine(string s) | |
+ { | |
+ Write(s + Environment.NewLine); | |
+ } | |
+ | |
+ public static void WriteLine() | |
+ { | |
+ Write(Environment.NewLine); | |
+ } | |
+ } | |
+} | |
diff --git a/src/Test.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/Test.CoreLib/src/System/Runtime/RuntimeImports.cs | |
index 014fe31b5..ea5626123 100644 | |
--- a/src/Test.CoreLib/src/System/Runtime/RuntimeImports.cs | |
+++ b/src/Test.CoreLib/src/System/Runtime/RuntimeImports.cs | |
@@ -25,7 +25,7 @@ namespace System.Runtime | |
// but if a class library wants to factor differently (such as putting the GCHandle methods in an | |
// optional library, those methods can be moved to a different file/namespace/dll | |
- public static class RuntimeImports | |
+ public static partial class RuntimeImports | |
{ | |
private const string RuntimeLibrary = "[MRT]"; | |
@@ -99,6 +99,14 @@ namespace System.Runtime | |
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")] | |
internal extern static int InterlockedCompareExchange(ref int location1, int value, int comparand); | |
+ [MethodImplAttribute(MethodImplOptions.InternalCall)] | |
+#if BIT64 | |
+ [RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg64")] | |
+#else | |
+ [RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")] | |
+#endif | |
+ internal extern static IntPtr InterlockedCompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand); | |
+ | |
[MethodImplAttribute(MethodImplOptions.InternalCall)] | |
[RuntimeImport(RuntimeLibrary, "RhpMemoryBarrier")] | |
internal extern static void MemoryBarrier(); | |
@@ -109,5 +117,25 @@ namespace System.Runtime | |
[MethodImplAttribute(MethodImplOptions.InternalCall)] | |
[RuntimeImport(RuntimeLibrary, "RhBulkMoveWithWriteBarrier")] | |
internal static extern unsafe void RhBulkMoveWithWriteBarrier(ref byte dmem, ref byte smem, nuint size); | |
+ | |
+ // Mark an object instance as already finalized. | |
+ [MethodImpl(MethodImplOptions.InternalCall)] | |
+ [RuntimeImport(RuntimeLibrary, "RhSuppressFinalize")] | |
+ internal static extern void RhSuppressFinalize(Object obj); | |
+ | |
+ [MethodImpl(MethodImplOptions.InternalCall)] | |
+ [RuntimeImport(RuntimeLibrary, "RhNewString")] | |
+ internal static extern String RhNewString(EETypePtr pEEType, int length); | |
+ | |
+ [DllImport(RuntimeImports.RuntimeLibrary)] | |
+ internal static extern unsafe void memmove(byte* dmem, byte* smem, nuint size); | |
+ | |
+ [MethodImplAttribute(MethodImplOptions.InternalCall)] | |
+ [RuntimeImport(RuntimeLibrary, "RhGetThreadStaticStorageForModule")] | |
+ internal static unsafe extern Array RhGetThreadStaticStorageForModule(Int32 moduleIndex); | |
+ | |
+ [MethodImplAttribute(MethodImplOptions.InternalCall)] | |
+ [RuntimeImport(RuntimeLibrary, "RhSetThreadStaticStorageForModule")] | |
+ internal static unsafe extern bool RhSetThreadStaticStorageForModule(Array storage, Int32 moduleIndex); | |
} | |
} | |
diff --git a/src/Test.CoreLib/src/System/String.Test.CoreLib.cs b/src/Test.CoreLib/src/System/String.Test.CoreLib.cs | |
new file mode 100644 | |
index 000000000..004e929cd | |
--- /dev/null | |
+++ b/src/Test.CoreLib/src/System/String.Test.CoreLib.cs | |
@@ -0,0 +1,247 @@ | |
+using System.Runtime; | |
+using System.Runtime.CompilerServices; | |
+using System.Runtime.InteropServices; | |
+using System.Text; | |
+ | |
+// From corert\src\System.Private.CoreLib\src\System\Buffer.cs | |
+#if BIT64 | |
+using nint = System.Int64; | |
+using nuint = System.UInt64; | |
+#else | |
+using nint = System.Int32; | |
+using nuint = System.UInt32; | |
+#endif | |
+ | |
+namespace System | |
+{ | |
+ public partial class String | |
+ { | |
+ // From corert\src\System.Private.CoreLib\src\System\String.CoreRT.cs | |
+ internal static String FastAllocateString(int length) | |
+ { | |
+ // We allocate one extra char as an interop convenience so that our strings are null- | |
+ // terminated, however, we don't pass the extra +1 to the string allocation because the base | |
+ // size of this object includes the _firstChar field. | |
+ string newStr = RuntimeImports.RhNewString(EETypePtr.EETypePtrOf<string>(), length); | |
+ //Debug.Assert(newStr._stringLength == length); | |
+ return newStr; | |
+ } | |
+ | |
+ internal static String FromChar(char c) | |
+ { | |
+ string result = string.FastAllocateString(1); | |
+ result._firstChar = c; | |
+ return result; | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\src\System\Buffer.cs | |
+ [MethodImplAttribute(MethodImplOptions.NoInlining)] | |
+ private static unsafe void _Memmove(byte* dest, byte* src, nuint len) | |
+ { | |
+ RuntimeImports.memmove(dest, src, len); | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.cs | |
+ internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) | |
+ { | |
+ //Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2); | |
+ // For simplicity, I think we can just fall back to the runtime version, | |
+ // Buffer.Memmove(..) *seems* to be an optimised version for non-overlapping buffers | |
+ _Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2); | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs | |
+ private static unsafe void FillStringChecked(string dest, int destPos, string src) | |
+ { | |
+ //Debug.Assert(dest != null); | |
+ //Debug.Assert(src != null); | |
+ if (src.Length > dest.Length - destPos) | |
+ { | |
+ throw new IndexOutOfRangeException(); | |
+ } | |
+ | |
+ fixed (char* pDest = &dest._firstChar) | |
+ fixed (char* pSrc = &src._firstChar) | |
+ { | |
+ wstrcpy(pDest + destPos, pSrc, src.Length); | |
+ } | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.cs | |
+ public static bool IsNullOrEmpty(string value) | |
+ { | |
+ // Using 0u >= (uint)value.Length rather than | |
+ // value.Length == 0 as it will elide the bounds check to | |
+ // the first char: value[0] if that is performed following the test | |
+ // for the same test cost. | |
+ // Ternary operator returning true/false prevents redundant asm generation: | |
+ // https://github.com/dotnet/coreclr/issues/914 | |
+ return (value == null || 0u >= (uint)value.Length) ? true : false; | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs | |
+ public static string Concat(string str0, string str1) | |
+ { | |
+ if (IsNullOrEmpty(str0)) | |
+ { | |
+ if (IsNullOrEmpty(str1)) | |
+ { | |
+ return ""; //string.Empty; | |
+ } | |
+ return str1; | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str1)) | |
+ { | |
+ return str0; | |
+ } | |
+ | |
+ int str0Length = str0.Length; | |
+ | |
+ string result = FastAllocateString(str0Length + str1.Length); | |
+ | |
+ FillStringChecked(result, 0, str0); | |
+ FillStringChecked(result, str0Length, str1); | |
+ | |
+ return result; | |
+ } | |
+ | |
+ public static string Concat(string str0, int int1) | |
+ { | |
+ return Concat(str0, UnicodeEncoding.IntToString(int1)); | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs | |
+ public static string Concat(string str0, string str1, string str2) | |
+ { | |
+ if (IsNullOrEmpty(str0)) | |
+ { | |
+ return Concat(str1, str2); | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str1)) | |
+ { | |
+ return Concat(str0, str2); | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str2)) | |
+ { | |
+ return Concat(str0, str1); | |
+ } | |
+ | |
+ int totalLength = str0.Length + str1.Length + str2.Length; | |
+ | |
+ string result = FastAllocateString(totalLength); | |
+ FillStringChecked(result, 0, str0); | |
+ FillStringChecked(result, str0.Length, str1); | |
+ FillStringChecked(result, str0.Length + str1.Length, str2); | |
+ | |
+ return result; | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs | |
+ public static string Concat(string str0, string str1, string str2, string str3) | |
+ { | |
+ if (IsNullOrEmpty(str0)) | |
+ { | |
+ return Concat(str1, str2, str3); | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str1)) | |
+ { | |
+ return Concat(str0, str2, str3); | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str2)) | |
+ { | |
+ return Concat(str0, str1, str3); | |
+ } | |
+ | |
+ if (IsNullOrEmpty(str3)) | |
+ { | |
+ return Concat(str0, str1, str2); | |
+ } | |
+ | |
+ int totalLength = str0.Length + str1.Length + str2.Length + str3.Length; | |
+ | |
+ string result = FastAllocateString(totalLength); | |
+ FillStringChecked(result, 0, str0); | |
+ FillStringChecked(result, str0.Length, str1); | |
+ FillStringChecked(result, str0.Length + str1.Length, str2); | |
+ FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3); | |
+ | |
+ return result; | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs | |
+ public static string Concat(params string[] values) | |
+ { | |
+ if (values == null) | |
+ throw new ArgumentNullException(); // nameof(values)); | |
+ | |
+ if (values.Length <= 1) | |
+ { | |
+ return values.Length == 0 ? | |
+ "" : //string.Empty : | |
+ values[0] ?? ""; // string.Empty; | |
+ } | |
+ | |
+ // It's possible that the input values array could be changed concurrently on another | |
+ // thread, such that we can't trust that each read of values[i] will be equivalent. | |
+ // Worst case, we can make a defensive copy of the array and use that, but we first | |
+ // optimistically try the allocation and copies assuming that the array isn't changing, | |
+ // which represents the 99.999% case, in particular since string.Concat is used for | |
+ // string concatenation by the languages, with the input array being a params array. | |
+ | |
+ // Sum the lengths of all input strings | |
+ long totalLengthLong = 0; | |
+ for (int i = 0; i < values.Length; i++) | |
+ { | |
+ string value = values[i]; | |
+ if (value != null) | |
+ { | |
+ totalLengthLong += value.Length; | |
+ } | |
+ } | |
+ | |
+ // If it's too long, fail, or if it's empty, return an empty string. | |
+ if (totalLengthLong > int.MaxValue) | |
+ { | |
+ throw new OutOfMemoryException(); | |
+ } | |
+ int totalLength = (int)totalLengthLong; | |
+ if (totalLength == 0) | |
+ { | |
+ return ""; //string.Empty; | |
+ } | |
+ | |
+ // Allocate a new string and copy each input string into it | |
+ string result = FastAllocateString(totalLength); | |
+ int copiedLength = 0; | |
+ for (int i = 0; i < values.Length; i++) | |
+ { | |
+ string value = values[i]; | |
+ if (!string.IsNullOrEmpty(value)) | |
+ { | |
+ int valueLen = value.Length; | |
+ if (valueLen > totalLength - copiedLength) | |
+ { | |
+ copiedLength = -1; | |
+ break; | |
+ } | |
+ | |
+ FillStringChecked(result, copiedLength, value); | |
+ copiedLength += valueLen; | |
+ } | |
+ } | |
+ | |
+ // If we copied exactly the right amount, return the new string. Otherwise, | |
+ // something changed concurrently to mutate the input array: fall back to | |
+ // doing the concatenation again, but this time with a defensive copy. This | |
+ // fall back should be extremely rare. | |
+ // TODO MattW Fix This!! | |
+ //return copiedLength == totalLength ? result : Concat((string[])values.Clone()); | |
+ return result; | |
+ } | |
+ } | |
+} | |
diff --git a/src/Test.CoreLib/src/System/Text/Encoding.cs b/src/Test.CoreLib/src/System/Text/Encoding.cs | |
new file mode 100644 | |
index 000000000..27572f018 | |
--- /dev/null | |
+++ b/src/Test.CoreLib/src/System/Text/Encoding.cs | |
@@ -0,0 +1,9 @@ | |
+using System; | |
+ | |
+namespace System.Text | |
+{ | |
+ public class Encoding | |
+ { | |
+ public static UnicodeEncoding UTF8 = new UnicodeEncoding(); | |
+ } | |
+} | |
diff --git a/src/Test.CoreLib/src/System/Text/UnicodeEncoding.cs b/src/Test.CoreLib/src/System/Text/UnicodeEncoding.cs | |
new file mode 100644 | |
index 000000000..419500c39 | |
--- /dev/null | |
+++ b/src/Test.CoreLib/src/System/Text/UnicodeEncoding.cs | |
@@ -0,0 +1,193 @@ | |
+using System; | |
+ | |
+namespace System.Text | |
+{ | |
+ public class UnicodeEncoding //: Encoding | |
+ { | |
+ public static unsafe string GetString(byte* bytesPtr, int length) | |
+ { | |
+ Interop.mincore.OutputDebugString("Got here (1)"); | |
+ bool succeeded = true; | |
+ int _index = 0, _currentLenCache = 0; | |
+ var _utf8Bytes = new byte[length]; | |
+ Interop.mincore.OutputDebugString("Got here (2)"); | |
+ Interop.mincore.OutputDebugString("Got here (3): " + IntToString(length)); | |
+ for (int i = 0; i < length; ++i) | |
+ { | |
+ _utf8Bytes[i] = *bytesPtr; | |
+ bytesPtr++; | |
+ } | |
+ | |
+ string result = ""; | |
+ while (succeeded) | |
+ { | |
+ succeeded = Utf8Helper.TryDecodeCodePoint(_utf8Bytes, _index, out uint codePoint, out _currentLenCache); | |
+ | |
+ if (succeeded) | |
+ { | |
+ var currentChar = String.FromChar((char)codePoint); | |
+ Interop.mincore.OutputDebugString(IntToString(_index) + " - SUCCEEDED - " + currentChar); // IntToString((int)codePoint)); | |
+ result += currentChar; | |
+ } | |
+ else | |
+ Interop.mincore.OutputDebugString(IntToString(_index) + " - FAILED - " + String.FromChar((char)codePoint)); // IntToString((int)codePoint)); | |
+ _index += _currentLenCache; | |
+ } | |
+ | |
+ return result; | |
+ } | |
+ | |
+ // From https://stackoverflow.com/questions/17575375/how-do-i-convert-an-int-to-a-string-in-c-sharp-without-using-tostring/17575453#17575453 | |
+ public static string IntToString(int a) | |
+ { | |
+ var chars = new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | |
+ var str = ""; // string.Empty; | |
+ if (a == 0) | |
+ { | |
+ str = chars[0]; | |
+ } | |
+ else if (a == int.MinValue) | |
+ { | |
+ str = "-2147483648"; | |
+ } | |
+ else | |
+ { | |
+ bool isNegative = (a < 0); | |
+ if (isNegative) | |
+ { | |
+ a = -a; | |
+ } | |
+ | |
+ while (a > 0) | |
+ { | |
+ str = chars[a % 10] + str; | |
+ a /= 10; | |
+ } | |
+ | |
+ if (isNegative) | |
+ { | |
+ str = "-" + str; | |
+ } | |
+ } | |
+ | |
+ return str; | |
+ } | |
+ } | |
+ | |
+ // From https://github.com/dotnet/corefxlab/blob/master/src/System.Text.Utf8String/System/Text/Primitives/Utf8Helper.cs#L30 | |
+ // Just changed from ReadOnlySpan<byte> -> byte[] | |
+ internal static class Utf8Helper | |
+ { | |
+ #region Constants | |
+ // To get this to compile with dotnet cli, we need to temporarily un-binary the magic values | |
+ private const byte b0000_0111U = 0x07; //7 | |
+ private const byte b0000_1111U = 0x0F; //15 | |
+ private const byte b0001_1111U = 0x1F; //31 | |
+ private const byte b0011_1111U = 0x3F; //63 | |
+ private const byte b0111_1111U = 0x7F; //127 | |
+ private const byte b1000_0000U = 0x80; //128 | |
+ private const byte b1100_0000U = 0xC0; //192 | |
+ private const byte b1110_0000U = 0xE0; //224 | |
+ private const byte b1111_0000U = 0xF0; //240 | |
+ private const byte b1111_1000U = 0xF8; //248 | |
+ | |
+ private const byte NonFirstByteInCodePointValue = 0x80; | |
+ private const byte NonFirstByteInCodePointMask = 0xC0; | |
+ | |
+ public const int MaxCodeUnitsPerCodePoint = 4; | |
+ #endregion Constants | |
+ | |
+ public static bool TryDecodeCodePoint(byte[] utf8, int index, out uint codePoint, out int bytesConsumed) | |
+ { | |
+ if (index >= utf8.Length) | |
+ { | |
+ codePoint = default; | |
+ bytesConsumed = 0; | |
+ return false; | |
+ } | |
+ | |
+ var first = utf8[index]; | |
+ | |
+ bytesConsumed = GetEncodedBytes(first); | |
+ if (bytesConsumed == 0 || utf8.Length - index < bytesConsumed) | |
+ { | |
+ bytesConsumed = 0; | |
+ codePoint = default; | |
+ return false; | |
+ } | |
+ | |
+ switch (bytesConsumed) | |
+ { | |
+ case 1: | |
+ codePoint = first; | |
+ break; | |
+ | |
+ case 2: | |
+ codePoint = (uint)(first & b0001_1111U); | |
+ break; | |
+ | |
+ case 3: | |
+ codePoint = (uint)(first & b0000_1111U); | |
+ break; | |
+ | |
+ case 4: | |
+ codePoint = (uint)(first & b0000_0111U); | |
+ break; | |
+ | |
+ default: | |
+ codePoint = default; | |
+ bytesConsumed = 0; | |
+ return false; | |
+ } | |
+ | |
+ for (var i = 1; i < bytesConsumed; i++) | |
+ { | |
+ uint current = utf8[index + i]; | |
+ if ((current & b1100_0000U) != b1000_0000U) | |
+ { | |
+ bytesConsumed = 0; | |
+ codePoint = default; | |
+ return false; | |
+ } | |
+ | |
+ codePoint = (codePoint << 6) | (b0011_1111U & current); | |
+ } | |
+ | |
+ return true; | |
+ } | |
+ | |
+ private static int GetEncodedBytes(byte b) | |
+ { | |
+ if ((b & b1000_0000U) == 0) | |
+ return 1; | |
+ | |
+ if ((b & b1110_0000U) == b1100_0000U) | |
+ return 2; | |
+ | |
+ if ((b & b1111_0000U) == b1110_0000U) | |
+ return 3; | |
+ | |
+ if ((b & b1111_1000U) == b1111_0000U) | |
+ return 4; | |
+ | |
+ return 0; | |
+ } | |
+ | |
+ public static int GetNumberOfEncodedBytes(uint codePoint) | |
+ { | |
+ if (codePoint <= 0x7F) | |
+ return 1; | |
+ | |
+ if (codePoint <= 0x7FF) | |
+ return 2; | |
+ | |
+ if (codePoint <= 0xFFFF) | |
+ return 3; | |
+ | |
+ if (codePoint <= 0x10FFFF) | |
+ return 4; | |
+ | |
+ return 0; | |
+ } | |
+ } | |
+} | |
diff --git a/src/Test.CoreLib/src/System/Threading/Interlocked.cs b/src/Test.CoreLib/src/System/Threading/Interlocked.cs | |
index 73f72f46c..de2e2c4b1 100644 | |
--- a/src/Test.CoreLib/src/System/Threading/Interlocked.cs | |
+++ b/src/Test.CoreLib/src/System/Threading/Interlocked.cs | |
@@ -15,6 +15,12 @@ namespace System.Threading | |
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand); | |
} | |
+ [Intrinsic] | |
+ public static IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand) | |
+ { | |
+ return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand); | |
+ } | |
+ | |
[Intrinsic] | |
public static void MemoryBarrier() | |
{ | |
diff --git a/src/Test.CoreLib/src/System/__OtherRequiredCode.cs b/src/Test.CoreLib/src/System/__OtherRequiredCode.cs | |
new file mode 100644 | |
index 000000000..1e4d7c856 | |
--- /dev/null | |
+++ b/src/Test.CoreLib/src/System/__OtherRequiredCode.cs | |
@@ -0,0 +1,520 @@ | |
+using System; | |
+using System.Runtime.InteropServices; | |
+using Microsoft.Win32.SafeHandles; | |
+using System.Runtime; | |
+using System.Threading; | |
+using System.Text; | |
+using System.Runtime.ConstrainedExecution; | |
+ | |
+// From corert\src\System.Private.CoreLib\src\System\Buffer.cs | |
+#if BIT64 | |
+using nint = System.Int64; | |
+using nuint = System.UInt64; | |
+#else | |
+using nint = System.Int32; | |
+using nuint = System.UInt32; | |
+#endif | |
+ | |
+internal static partial class Interop | |
+{ | |
+ // From corert\src\System.Private.CoreLib\shared\Interop\Windows\Interop.Libraries.cs | |
+ internal static partial class Libraries | |
+ { | |
+ internal const string Kernel32 = "kernel32.dll"; | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\Interop\Windows\Kernel32\Interop.CloseHandle.cs | |
+ internal partial class Kernel32 | |
+ { | |
+ [DllImport(Libraries.Kernel32, SetLastError = true)] | |
+ [return: MarshalAs(UnmanagedType.Bool)] | |
+ internal static extern bool CloseHandle(IntPtr handle); | |
+ } | |
+ | |
+ internal static unsafe partial class mincore | |
+ { | |
+ // From corert\src\Common\src\Interop\Windows\mincore\Interop.DynamicLoad.cs | |
+ [DllImport("api-ms-win-core-libraryloader-l1-2-0.dll")] | |
+ internal static extern IntPtr GetProcAddress(IntPtr hModule, byte* lpProcName); | |
+ | |
+ [DllImport("api-ms-win-core-libraryloader-l1-2-0.dll", EntryPoint = "LoadLibraryExW", CharSet = CharSet.Unicode)] | |
+ internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags); | |
+ | |
+ [DllImport("api-ms-win-core-libraryloader-l1-2-0.dll")] | |
+ internal static extern bool FreeLibrary(IntPtr hModule); | |
+ | |
+ // From corert\src\Common\src\Interop\Windows\mincore\Interop.GetLastError.cs | |
+ [DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")] | |
+ internal extern static int GetLastError(); | |
+ | |
+ // From corert\src\Common\src\Interop\Windows\mincore\Interop.SetLastError.cs | |
+ [DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")] | |
+ internal extern static void SetLastError(uint dwErrCode); | |
+ | |
+ // From corert\src\System.Private.CoreLib\src\Interop\Interop.manual.cs | |
+ [DllImport("api-ms-win-core-debug-l1-1-0.dll", EntryPoint = "OutputDebugStringW", CharSet = CharSet.Unicode)] | |
+ internal extern static void OutputDebugString(string lpOutputString); | |
+ } | |
+} | |
+ | |
+// From https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/Microsoft/Win32/Win32Native.cs | |
+namespace Microsoft.Win32 | |
+{ | |
+ internal static class Win32Native | |
+ { | |
+ [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] | |
+ internal static extern unsafe int WriteFile(SafeFileHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero); | |
+ | |
+ // Note, these are #defines used to extract handles, and are NOT handles. | |
+ internal const int STD_INPUT_HANDLE = -10; | |
+ internal const int STD_OUTPUT_HANDLE = -11; | |
+ internal const int STD_ERROR_HANDLE = -12; | |
+ | |
+ [DllImport(Interop.Libraries.Kernel32, SetLastError = true)] | |
+ internal static extern IntPtr GetStdHandle(int nStdHandle); // param is NOT a handle, but it returns one! | |
+ } | |
+} | |
+ | |
+namespace System.Diagnostics.CodeAnalysis | |
+{ | |
+ public class SuppressMessageAttribute : Attribute | |
+ { | |
+ public SuppressMessageAttribute(string category, string checkId) | |
+ { } | |
+ } | |
+ | |
+} | |
+ | |
+namespace Microsoft.Win32.SafeHandles | |
+{ | |
+ // From corert\src\System.Private.CoreLib\shared\Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs | |
+ // Class of safe handle which uses 0 or -1 as an invalid handle. | |
+ public abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle | |
+ { | |
+ protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) | |
+ { | |
+ } | |
+ | |
+ public override bool IsInvalid => handle == IntPtr.Zero || handle == new IntPtr(-1); | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\shared\Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs (cut-down) | |
+ public sealed class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid | |
+ { | |
+ public SafeFileHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) | |
+ { | |
+ SetHandle(preexistingHandle); | |
+ } | |
+ | |
+ override protected bool ReleaseHandle() | |
+ { | |
+ return Interop.Kernel32.CloseHandle(handle); | |
+ } | |
+ } | |
+ | |
+} | |
+ | |
+namespace System | |
+{ | |
+ // Code from corert\src\System.Private.CoreLib\src\System\GC.cs | |
+ public static partial class GC | |
+ { | |
+ public static void SuppressFinalize(Object obj) | |
+ { | |
+ if (obj == null) | |
+ { | |
+ throw new ArgumentNullException(); // nameof(obj)); | |
+ } | |
+ | |
+ RuntimeImports.RhSuppressFinalize(obj); | |
+ } | |
+ } | |
+ | |
+ // Code from corert\src\System.Private.CoreLib\src\System\Environment.cs | |
+ public static partial class Environment | |
+ { | |
+ public static String NewLine | |
+ { | |
+ get | |
+ { | |
+#if !PLATFORM_UNIX | |
+ return "\r\n"; | |
+#else | |
+ return "\n"; | |
+#endif // !PLATFORM_UNIX | |
+ } | |
+ } | |
+ } | |
+ | |
+ // From corert\src\System.Private.CoreLib\src\System\InvokeUtils.cs | |
+ public class InvokeUtils | |
+ { | |
+ public class ArgSetupState | |
+ { | |
+ | |
+ } | |
+ | |
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] | |
+ internal static void DynamicInvokeArgSetupComplete(ref ArgSetupState argSetupState) | |
+ { | |
+ //int parametersLength = s_parameters != null ? s_parameters.Length : 0; | |
+ | |
+ //if (s_curIndex != parametersLength) | |
+ //{ | |
+ // throw new System.Reflection.TargetParameterCountException(); | |
+ //} | |
+ //argSetupState.fComplete = true; | |
+ //argSetupState.nullableCopyBackObjects = s_nullableCopyBackObjects; | |
+ //s_nullableCopyBackObjects = null; | |
+ | |
+ // TODO MattW fix this!! | |
+ //Console.WriteLine("## InvalidOperationException - DynamicInvokeArgSetupComplete ##"); | |
+ throw new InvalidOperationException(); | |
+ } | |
+ | |
+ //[DebuggerStepThrough] | |
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] | |
+ internal static ref IntPtr DynamicInvokeParamHelperIn(RuntimeTypeHandle rth) | |
+ { | |
+ //// | |
+ //// Call DynamicInvokeParamHelperCore as an in parameter, and return a managed byref to the interesting bit. | |
+ //// | |
+ //// This function exactly matches DynamicInvokeParamHelperRef except for the value of the enum passed to DynamicInvokeParamHelperCore | |
+ //// | |
+ | |
+ //int index; | |
+ //DynamicInvokeParamLookupType paramLookupType; | |
+ //object obj = DynamicInvokeParamHelperCore(rth, out paramLookupType, out index, DynamicInvokeParamType.In); | |
+ | |
+ //if (paramLookupType == DynamicInvokeParamLookupType.ValuetypeObjectReturned) | |
+ //{ | |
+ // return ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData()); | |
+ //} | |
+ //else | |
+ //{ | |
+ // return ref Unsafe.As<object, IntPtr>(ref Unsafe.As<object[]>(obj)[index]); | |
+ //} | |
+ // TODO MattW fix this!! | |
+ //Console.WriteLine("## InvalidOperationException - DynamicInvokeParamHelperIn ##"); | |
+ throw new InvalidOperationException(); | |
+ } | |
+ | |
+ //[DebuggerStepThrough] | |
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] | |
+ internal static ref IntPtr DynamicInvokeParamHelperRef(RuntimeTypeHandle rth) | |
+ { | |
+ //// | |
+ //// Call DynamicInvokeParamHelperCore as a ref parameter, and return a managed byref to the interesting bit. As this can't actually be defined in C# there is an IL transform that fills this in. | |
+ //// | |
+ //// This function exactly matches DynamicInvokeParamHelperIn except for the value of the enum passed to DynamicInvokeParamHelperCore | |
+ //// | |
+ | |
+ //int index; | |
+ //DynamicInvokeParamLookupType paramLookupType; | |
+ //object obj = DynamicInvokeParamHelperCore(rth, out paramLookupType, out index, DynamicInvokeParamType.Ref); | |
+ | |
+ //if (paramLookupType == DynamicInvokeParamLookupType.ValuetypeObjectReturned) | |
+ //{ | |
+ // return ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData()); | |
+ //} | |
+ //else | |
+ //{ | |
+ // return ref Unsafe.As<object, IntPtr>(ref Unsafe.As<object[]>(obj)[index]); | |
+ //} | |
+ // TODO MattW fix this!! | |
+ //Console.WriteLine("## InvalidOperationException - DynamicInvokeParamHelperRef ##"); | |
+ throw new InvalidOperationException(); | |
+ } | |
+ } | |
+} | |
+ | |
+namespace System.Runtime.InteropServices | |
+{ | |
+ // From corert\src\System.Private.CoreLib\src\System\Runtime\InteropServices\PInvokeMarshal.Windows.cs | |
+ public partial class PInvokeMarshal | |
+ { | |
+ [ThreadStatic] | |
+ internal static int s_lastWin32Error; | |
+ | |
+ public static void SaveLastWin32Error() | |
+ { | |
+ s_lastWin32Error = Interop.mincore.GetLastError(); | |
+ } | |
+ | |
+ public static void ClearLastWin32Error() | |
+ { | |
+ Interop.mincore.SetLastError(0); | |
+ } | |
+ } | |
+} | |
+ | |
+namespace System.Runtime.CompilerServices | |
+{ | |
+ // From corert\src\System.Private.CoreLib\src\System\Runtime\CompilerServices\RuntimeHelpers.cs | |
+ public static class RuntimeHelpers | |
+ { | |
+ public static int OffsetToStringData | |
+ { | |
+ get | |
+ { | |
+ // Number of bytes from the address pointed to by a reference to | |
+ // a String to the first 16-bit character in the String. | |
+ // This property allows C#'s fixed statement to work on Strings. | |
+ return String.FIRST_CHAR_OFFSET; | |
+ } | |
+ } | |
+ } | |
+} | |
+ | |
+// From corert\src\System.Private.CoreLib\src\Internal\Runtime\CompilerHelpers\InteropHelpers.cs | |
+namespace Internal.Runtime.CompilerHelpers | |
+{ | |
+ internal static class InteropHelpers | |
+ { | |
+ internal static unsafe IntPtr ResolvePInvoke(MethodFixupCell* pCell) | |
+ { | |
+ Interop.mincore.OutputDebugString("In ResolvePInvoke"); | |
+ if (pCell->Target != IntPtr.Zero) | |
+ return pCell->Target; | |
+ | |
+ //return ResolvePInvokeSlow(pCell); | |
+ IntPtr result = ResolvePInvokeSlow(pCell); | |
+ Interop.mincore.OutputDebugString("In ResolvePInvoke (After ResolvePInvokeSlow())"); | |
+ return result; | |
+ } | |
+ | |
+ internal static unsafe IntPtr ResolvePInvokeSlow(MethodFixupCell* pCell) | |
+ { | |
+ Interop.mincore.OutputDebugString("In ResolvePInvokeSlow"); | |
+ ModuleFixupCell* pModuleCell = pCell->Module; | |
+ IntPtr hModule = pModuleCell->Handle; | |
+ if (hModule == IntPtr.Zero) | |
+ { | |
+ FixupModuleCell(pModuleCell); | |
+ hModule = pModuleCell->Handle; | |
+ } | |
+ | |
+ FixupMethodCell(hModule, pCell); | |
+ return pCell->Target; | |
+ } | |
+ | |
+ internal static unsafe IntPtr TryResolveModule(string moduleName) | |
+ { | |
+ Interop.mincore.OutputDebugString("In TryResolveModule - " + moduleName); | |
+ IntPtr hModule = IntPtr.Zero; | |
+ | |
+ // Try original name first | |
+ hModule = LoadLibrary(moduleName); | |
+ if (hModule != IntPtr.Zero) | |
+ return hModule; | |
+ | |
+#if PLATFORM_UNIX | |
+ const string PAL_SHLIB_PREFIX = "lib"; | |
+#if PLATFORM_OSX | |
+ const string PAL_SHLIB_SUFFIX = ".dylib"; | |
+#else | |
+ const string PAL_SHLIB_SUFFIX = ".so"; | |
+#endif | |
+ | |
+ // Try prefix+name+suffix | |
+ hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName + PAL_SHLIB_SUFFIX); | |
+ if (hModule != IntPtr.Zero) return hModule; | |
+ | |
+ // Try name+suffix | |
+ hModule = LoadLibrary(moduleName + PAL_SHLIB_SUFFIX); | |
+ if (hModule != IntPtr.Zero) return hModule; | |
+ | |
+ // Try prefix+name | |
+ hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName); | |
+ if (hModule != IntPtr.Zero) return hModule; | |
+#endif | |
+ return IntPtr.Zero; | |
+ } | |
+ | |
+ internal static unsafe IntPtr LoadLibrary(string moduleName) | |
+ { | |
+ Interop.mincore.OutputDebugString("In LoadLibrary " + moduleName); | |
+ IntPtr hModule; | |
+ | |
+#if !PLATFORM_UNIX | |
+ hModule = Interop.mincore.LoadLibraryEx(moduleName, IntPtr.Zero, 0); | |
+#else | |
+ hModule = Interop.Sys.LoadLibrary(moduleName); | |
+#endif | |
+ | |
+ return hModule; | |
+ } | |
+ | |
+ internal static unsafe void FreeLibrary(IntPtr hModule) | |
+ { | |
+ Interop.mincore.OutputDebugString("In FreeLibrary"); | |
+#if !PLATFORM_UNIX | |
+ Interop.mincore.FreeLibrary(hModule); | |
+#else | |
+ Interop.Sys.FreeLibrary(hModule); | |
+#endif | |
+ } | |
+ | |
+ private static unsafe string GetModuleName(ModuleFixupCell* pCell) | |
+ { | |
+ byte* pModuleName = (byte*)pCell->ModuleName; | |
+ //return Encoding.UTF8.GetString(pModuleName, strlen(pModuleName)); | |
+ Interop.mincore.OutputDebugString("In GetModuleName (Before strlen())"); | |
+ var len = strlen(pModuleName); | |
+ Interop.mincore.OutputDebugString("In GetModuleName (Before Encoding.UTF8.GetString())"); | |
+ //var moduleName = Encoding.UTF8.GetString(pModuleName, len); //, strlen(pModuleName)); | |
+ var moduleName = UnicodeEncoding.GetString(pModuleName, strlen(pModuleName)); | |
+ Interop.mincore.OutputDebugString("In GetModuleName -> " + moduleName + " (After Encoding.UTF8.GetString())"); | |
+ return moduleName; | |
+ } | |
+ | |
+ internal static unsafe void FixupModuleCell(ModuleFixupCell* pCell) | |
+ { | |
+ Interop.mincore.OutputDebugString("In FixupModuleCell (1a)"); | |
+ string moduleName = GetModuleName(pCell); | |
+ Interop.mincore.OutputDebugString("In FixupModuleCell (1b)"); | |
+ IntPtr hModule = TryResolveModule(moduleName); | |
+ Interop.mincore.OutputDebugString("In FixupModuleCell (1c)"); | |
+ if (hModule != IntPtr.Zero) | |
+ { | |
+ var oldValue = Interlocked.CompareExchange(ref pCell->Handle, hModule, IntPtr.Zero); | |
+ if (oldValue != IntPtr.Zero) | |
+ { | |
+ // Some other thread won the race to fix it up. | |
+ FreeLibrary(hModule); | |
+ } | |
+ } | |
+ else | |
+ { | |
+ //throw new DllNotFoundException(SR.Format(SR.Arg_DllNotFoundExceptionParameterized, moduleName)); | |
+ throw new DllNotFoundException("DllNotFoundExceptionParameterized - " + moduleName); | |
+ } | |
+ } | |
+ | |
+ internal static unsafe void FixupMethodCell(IntPtr hModule, MethodFixupCell* pCell) | |
+ { | |
+ Interop.mincore.OutputDebugString("In FixupModuleCell (2a)"); | |
+ byte* methodName = (byte*)pCell->MethodName; | |
+ Interop.mincore.OutputDebugString("In FixupModuleCell (2a) - " + UnicodeEncoding.GetString(methodName, strlen(methodName))); | |
+ | |
+#if PLATFORM_WINDOWS | |
+ pCell->Target = GetProcAddress(hModule, methodName, pCell->CharSetMangling); | |
+#else | |
+ pCell->Target = Interop.Sys.GetProcAddress(hModule, methodName); | |
+#endif | |
+ if (pCell->Target == IntPtr.Zero) | |
+ { | |
+ //string entryPointName = Encoding.UTF8.GetString(methodName, strlen(methodName)); | |
+ string entryPointName = UnicodeEncoding.GetString(methodName, strlen(methodName)); | |
+ Interop.mincore.OutputDebugString("In FixupMethodCell -> " + entryPointName); | |
+ //throw new EntryPointNotFoundException(SR.Format(SR.Arg_EntryPointNotFoundExceptionParameterized, entryPointName, GetModuleName(pCell->Module))); | |
+ throw new EntryPointNotFoundException("EntryPointNotFoundExceptionParameterized - " + entryPointName + " - " + GetModuleName(pCell->Module)); | |
+ } | |
+ else | |
+ { | |
+ Interop.mincore.OutputDebugString("In FixupMethodCell pCell->Target IS NOT IntPtr.Zero"); | |
+ } | |
+ } | |
+ | |
+#if PLATFORM_WINDOWS | |
+ private static unsafe IntPtr GetProcAddress(IntPtr hModule, byte* methodName, CharSet charSetMangling) | |
+ { | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (1)"); | |
+ // First look for the unmangled name. If it is unicode function, we are going | |
+ // to need to check for the 'W' API because it takes precedence over the | |
+ // unmangled one (on NT some APIs have unmangled ANSI exports). | |
+ | |
+ var exactMatch = Interop.mincore.GetProcAddress(hModule, methodName); | |
+ | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (2)"); | |
+ | |
+ if ((charSetMangling == CharSet.Ansi && exactMatch != IntPtr.Zero) || charSetMangling == 0) | |
+ { | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (3)"); | |
+ return exactMatch; | |
+ } | |
+ | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (4)"); | |
+ | |
+ int nameLength = strlen(methodName); | |
+ | |
+ // We need to add an extra byte for the suffix, and an extra byte for the null terminator | |
+ byte* probedMethodName = stackalloc byte[nameLength + 2]; | |
+ | |
+ for (int i = 0; i < nameLength; i++) | |
+ { | |
+ probedMethodName[i] = methodName[i]; | |
+ } | |
+ | |
+ probedMethodName[nameLength + 1] = 0; | |
+ | |
+ probedMethodName[nameLength] = (charSetMangling == CharSet.Ansi) ? (byte)'A' : (byte)'W'; | |
+ | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (5)"); | |
+ | |
+ IntPtr probedMethod = Interop.mincore.GetProcAddress(hModule, probedMethodName); | |
+ Interop.mincore.OutputDebugString("In GetProcAddress (6)"); | |
+ if (probedMethod != IntPtr.Zero) | |
+ { | |
+ return probedMethod; | |
+ } | |
+ | |
+ return exactMatch; | |
+ } | |
+#endif | |
+ | |
+ internal static unsafe int strlen(byte* pString) | |
+ { | |
+ byte* p = pString; | |
+ while (*p != 0) | |
+ p++; | |
+ return checked((int)(p - pString)); | |
+ } | |
+ | |
+ [StructLayout(LayoutKind.Sequential)] | |
+ internal unsafe struct ModuleFixupCell | |
+ { | |
+ public IntPtr Handle; | |
+ public IntPtr ModuleName; | |
+ } | |
+ | |
+ [StructLayout(LayoutKind.Sequential)] | |
+ internal unsafe struct MethodFixupCell | |
+ { | |
+ public IntPtr Target; | |
+ public IntPtr MethodName; | |
+ public ModuleFixupCell* Module; | |
+ public CharSet CharSetMangling; | |
+ } | |
+ } | |
+} | |
+ | |
+namespace System.Reflection | |
+{ | |
+ //[CLSCompliant(false)] | |
+ public sealed unsafe class Pointer //: ISerializable | |
+ { | |
+ // CoreCLR: Do not add or remove fields without updating the ReflectionPointer class in runtimehandles.h | |
+ private readonly void* _ptr; | |
+ private readonly Type _ptrType; | |
+ | |
+ private Pointer(void* ptr, Type ptrType) | |
+ { | |
+ //Debug.Assert(ptrType.IsRuntimeImplemented()); // CoreCLR: For CoreRT's sake, _ptrType has to be declared as "Type", but in fact, it is always a RuntimeType. Code on CoreCLR expects this. | |
+ _ptr = ptr; | |
+ _ptrType = ptrType; | |
+ } | |
+ | |
+ public static object Box(void* ptr, Type type) | |
+ { | |
+ if (type == null) | |
+ throw new ArgumentNullException(); // nameof(type)); | |
+ //if (!type.IsPointer) | |
+ // throw new ArgumentException(SR.Arg_MustBePointer, nameof(ptr)); | |
+ //if (!type.IsRuntimeImplemented()) | |
+ // throw new ArgumentException(SR.Arg_MustBeType, nameof(ptr)); | |
+ | |
+ return new Pointer(ptr, type); | |
+ } | |
+ } | |
+} | |
diff --git a/src/Test.CoreLib/src/Test.CoreLib.csproj b/src/Test.CoreLib/src/Test.CoreLib.csproj | |
index 685a4fd63..2e2087aa3 100644 | |
--- a/src/Test.CoreLib/src/Test.CoreLib.csproj | |
+++ b/src/Test.CoreLib/src/Test.CoreLib.csproj | |
@@ -1,4 +1,4 @@ | |
-<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> | |
<PropertyGroup> | |
<OutputType>Library</OutputType> | |
@@ -7,6 +7,7 @@ | |
<IsCoreAssembly>true</IsCoreAssembly> | |
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> | |
<EnableFxCopAnalyzers>false</EnableFxCopAnalyzers> | |
+ <ProjectGuid>{F32CD720-A195-4407-B8EF-7A82F88F8432}</ProjectGuid> | |
</PropertyGroup> | |
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> | |
<DefineConstants>FEATURE_GC_STRESS;$(DefineConstants)</DefineConstants> | |
@@ -29,6 +30,81 @@ | |
<DefineConstants Condition="'$(Platform)' == 'arm'">FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants> | |
<DefineConstants Condition="'$(Platform)' == 'armel'">FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants> | |
</PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> | |
+ <OutputPath>..\..\..\bin\Windows_NT.x64.Debug\Test.CoreLib\</OutputPath> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>..\..\..\bin\Windows_NT.x64.Release\Test.CoreLib\</OutputPath> | |
+ <DefineConstants>INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_GC_STRESS;AMD64;BIT64;PLATFORM_WINDOWS;CORERT;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>bin\x86\Release\</OutputPath> | |
+ <DefineConstants>INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_GC_STRESS;X86;BIT32;PLATFORM_WINDOWS;CORERT;DEBUG;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|arm'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>bin\arm\Release\</OutputPath> | |
+ <DefineConstants>FEATURE_64BIT_ALIGNMENT;INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_64BIT_ALIGNMENT;FEATURE_GC_STRESS;ARM;BIT32;PLATFORM_WINDOWS;CORERT;DEBUG;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|armel'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>bin\armel\Release\</OutputPath> | |
+ <DefineConstants>FEATURE_64BIT_ALIGNMENT;INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_64BIT_ALIGNMENT;FEATURE_GC_STRESS;ARM;BIT32;PLATFORM_WINDOWS;CORERT;DEBUG;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|arm64'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>bin\arm64\Release\</OutputPath> | |
+ <DefineConstants>INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_GC_STRESS;ARM64;BIT64;PLATFORM_WINDOWS;CORERT;DEBUG;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|wasm'"> | |
+ <DebugSymbols>true</DebugSymbols> | |
+ <OutputPath>bin\wasm\Release\</OutputPath> | |
+ <DefineConstants>INPLACE_RUNTIME;EETYPE_TYPE_MANAGER;FEATURE_GC_STRESS;WASM;BIT32;PLATFORM_WINDOWS;CORERT;DEBUG;TRACE;;DEBUGRESOURCES;SIGNED</DefineConstants> | |
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |
+ <NoStdLib>true</NoStdLib> | |
+ <DebugType>portable</DebugType> | |
+ <PlatformTarget>AnyCPU</PlatformTarget> | |
+ <LangVersion>latest</LangVersion> | |
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | |
+ </PropertyGroup> | |
<ItemGroup Condition="'$(InPlaceRuntime)' == 'true'"> | |
<Compile Include="..\..\Runtime.Base\src\System\Runtime\CachedInterfaceDispatch.cs"> | |
<Link>Runtime.Base\src\System\Runtime\CachedInterfaceDispatch.cs</Link> | |
@@ -56,7 +132,7 @@ | |
</Compile> | |
<Compile Include="..\..\Runtime.Base\src\System\Runtime\CastableObjectSupport.cs"> | |
<Link>Runtime.Base\src\System\Runtime\CastableObjectSupport.cs</Link> | |
- </Compile> | |
+ </Compile> | |
<Compile Include="..\..\Runtime.Base\src\System\Runtime\RuntimeExports.cs"> | |
<Link>Runtime.Base\src\System\Runtime\RuntimeExports.cs</Link> | |
</Compile> | |
@@ -228,9 +304,40 @@ | |
<Compile Include="..\..\Runtime.Base\src\Internal\Runtime\CompilerServices\Unsafe.cs"> | |
<Link>Internal\Runtime\CompilerServices\Unsafe.cs</Link> | |
</Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\IDisposable.cs"> | |
+ <Link>System\IDisposable.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\Runtime\CompilerServices\ExtensionAttribute.cs"> | |
+ <Link>System\Runtime\CompilerServices\ExtensionAttribute.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\Runtime\ConstrainedExecution\CriticalFinalizerObject.cs"> | |
+ <Link>System\Runtime\ConstrainedExecution\CriticalFinalizerObject.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\Runtime\InteropServices\MarshalAsAttribute.cs"> | |
+ <Link>System\Runtime\InteropServices\MarshalAsAttribute.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\Runtime\InteropServices\UnmanagedType.cs"> | |
+ <Link>System\Runtime\InteropServices\UnmanagedType.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\Runtime\InteropServices\VarEnum.cs"> | |
+ <Link>System\Runtime\InteropServices\VarEnum.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\shared\System\ThreadStaticAttribute.cs"> | |
+ <Link>System\ThreadStaticAttribute.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\src\Internal\Runtime\ThreadStatics.cs"> | |
+ <Link>Internal\Runtime\ThreadStatics.cs</Link> | |
+ </Compile> | |
+ <Compile Include="..\..\System.Private.CoreLib\src\System\Runtime\InteropServices\SafeHandle.cs"> | |
+ <Link>System\Runtime\InteropServices\SafeHandle.cs</Link> | |
+ </Compile> | |
+ <Compile Include="System\Console.cs" /> | |
<Compile Include="System\Runtime\CompilerServices\ClassConstructorRunner.cs" /> | |
<Compile Include="System\Runtime\CompilerServices\StaticClassConstructionContext.cs" /> | |
<Compile Include="System\Runtime\RuntimeImports.cs" /> | |
+ <Compile Include="System\String.Test.CoreLib.cs" /> | |
+ <Compile Include="System\Text\Encoding.cs" /> | |
+ <Compile Include="System\Text\UnicodeEncoding.cs" /> | |
<Compile Include="System\Threading\Interlocked.cs" /> | |
<Compile Include="System\Array.cs" /> | |
<Compile Include="System\RuntimeExceptionHelpers.cs" /> | |
@@ -240,11 +347,13 @@ | |
<Compile Include="..\..\Common\src\Internal\Runtime\TypeManagerHandle.cs"> | |
<Link>Internal\Runtime\TypeManagerHandle.cs</Link> | |
</Compile> | |
+ <Compile Include="System\__OtherRequiredCode.cs" /> | |
</ItemGroup> | |
+ <ItemGroup /> | |
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> | |
<PropertyGroup> | |
<!-- Exclude AssemblyInfoPartialFile --> | |
<AssemblyInfoPartialFile> | |
</AssemblyInfoPartialFile> | |
</PropertyGroup> | |
-</Project> | |
+</Project> |
System\String.Test.CoreLib.cs
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
// From corert\src\System.Private.CoreLib\src\System\Buffer.cs
#if BIT64
using nint = System.Int64;
using nuint = System.UInt64;
#else
using nint = System.Int32;
using nuint = System.UInt32;
#endif
namespace System
{
public partial class String
{
// From corert\src\System.Private.CoreLib\src\System\String.CoreRT.cs
internal static String FastAllocateString(int length)
{
// We allocate one extra char as an interop convenience so that our strings are null-
// terminated, however, we don't pass the extra +1 to the string allocation because the base
// size of this object includes the _firstChar field.
string newStr = RuntimeImports.RhNewString(EETypePtr.EETypePtrOf<string>(), length);
//Debug.Assert(newStr._stringLength == length);
return newStr;
}
internal static String FromChar(char c)
{
string result = string.FastAllocateString(1);
result._firstChar = c;
return result;
}
// From corert\src\System.Private.CoreLib\src\System\Buffer.cs
[MethodImplAttribute(MethodImplOptions.NoInlining)]
private static unsafe void _Memmove(byte* dest, byte* src, nuint len)
{
RuntimeImports.memmove(dest, src, len);
}
// From corert\src\System.Private.CoreLib\shared\System\String.cs
internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
{
//Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2);
// For simplicity, I think we can just fall back to the runtime version,
// Buffer.Memmove(..) *seems* to be an optimised version for non-overlapping buffers
_Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2);
}
// From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs
private static unsafe void FillStringChecked(string dest, int destPos, string src)
{
//Debug.Assert(dest != null);
//Debug.Assert(src != null);
if (src.Length > dest.Length - destPos)
{
throw new IndexOutOfRangeException();
}
fixed (char* pDest = &dest._firstChar)
fixed (char* pSrc = &src._firstChar)
{
wstrcpy(pDest + destPos, pSrc, src.Length);
}
}
// From corert\src\System.Private.CoreLib\shared\System\String.cs
public static bool IsNullOrEmpty(string value)
{
// Using 0u >= (uint)value.Length rather than
// value.Length == 0 as it will elide the bounds check to
// the first char: value[0] if that is performed following the test
// for the same test cost.
// Ternary operator returning true/false prevents redundant asm generation:
// https://github.com/dotnet/coreclr/issues/914
return (value == null || 0u >= (uint)value.Length) ? true : false;
}
// From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs
public static string Concat(string str0, string str1)
{
if (IsNullOrEmpty(str0))
{
if (IsNullOrEmpty(str1))
{
return ""; //string.Empty;
}
return str1;
}
if (IsNullOrEmpty(str1))
{
return str0;
}
int str0Length = str0.Length;
string result = FastAllocateString(str0Length + str1.Length);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0Length, str1);
return result;
}
public static string Concat(string str0, int int1)
{
return Concat(str0, UnicodeEncoding.IntToString(int1));
}
// From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs
public static string Concat(string str0, string str1, string str2)
{
if (IsNullOrEmpty(str0))
{
return Concat(str1, str2);
}
if (IsNullOrEmpty(str1))
{
return Concat(str0, str2);
}
if (IsNullOrEmpty(str2))
{
return Concat(str0, str1);
}
int totalLength = str0.Length + str1.Length + str2.Length;
string result = FastAllocateString(totalLength);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0.Length, str1);
FillStringChecked(result, str0.Length + str1.Length, str2);
return result;
}
// From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs
public static string Concat(string str0, string str1, string str2, string str3)
{
if (IsNullOrEmpty(str0))
{
return Concat(str1, str2, str3);
}
if (IsNullOrEmpty(str1))
{
return Concat(str0, str2, str3);
}
if (IsNullOrEmpty(str2))
{
return Concat(str0, str1, str3);
}
if (IsNullOrEmpty(str3))
{
return Concat(str0, str1, str2);
}
int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
string result = FastAllocateString(totalLength);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0.Length, str1);
FillStringChecked(result, str0.Length + str1.Length, str2);
FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
return result;
}
// From corert\src\System.Private.CoreLib\shared\System\String.Manipulation.cs
public static string Concat(params string[] values)
{
if (values == null)
throw new ArgumentNullException(); // nameof(values));
if (values.Length <= 1)
{
return values.Length == 0 ?
"" : //string.Empty :
values[0] ?? ""; // string.Empty;
}
// It's possible that the input values array could be changed concurrently on another
// thread, such that we can't trust that each read of values[i] will be equivalent.
// Worst case, we can make a defensive copy of the array and use that, but we first
// optimistically try the allocation and copies assuming that the array isn't changing,
// which represents the 99.999% case, in particular since string.Concat is used for
// string concatenation by the languages, with the input array being a params array.
// Sum the lengths of all input strings
long totalLengthLong = 0;
for (int i = 0; i < values.Length; i++)
{
string value = values[i];
if (value != null)
{
totalLengthLong += value.Length;
}
}
// If it's too long, fail, or if it's empty, return an empty string.
if (totalLengthLong > int.MaxValue)
{
throw new OutOfMemoryException();
}
int totalLength = (int)totalLengthLong;
if (totalLength == 0)
{
return ""; //string.Empty;
}
// Allocate a new string and copy each input string into it
string result = FastAllocateString(totalLength);
int copiedLength = 0;
for (int i = 0; i < values.Length; i++)
{
string value = values[i];
if (!string.IsNullOrEmpty(value))
{
int valueLen = value.Length;
if (valueLen > totalLength - copiedLength)
{
copiedLength = -1;
break;
}
FillStringChecked(result, copiedLength, value);
copiedLength += valueLen;
}
}
// If we copied exactly the right amount, return the new string. Otherwise,
// something changed concurrently to mutate the input array: fall back to
// doing the concatenation again, but this time with a defensive copy. This
// fall back should be extremely rare.
// TODO MattW Fix This!!
//return copiedLength == totalLength ? result : Concat((string[])values.Clone());
return result;
}
}
}
System\Text\Encoding.cs
using System;
namespace System.Text
{
public class Encoding
{
public static UnicodeEncoding UTF8 = new UnicodeEncoding();
}
}
System\Text\UnicodeEncoding.cs
using System;
namespace System.Text
{
public class UnicodeEncoding //: Encoding
{
public static unsafe string GetString(byte* bytesPtr, int length)
{
Interop.mincore.OutputDebugString("Got here (1)");
bool succeeded = true;
int _index = 0, _currentLenCache = 0;
var _utf8Bytes = new byte[length];
Interop.mincore.OutputDebugString("Got here (2)");
Interop.mincore.OutputDebugString("Got here (3): " + IntToString(length));
for (int i = 0; i < length; ++i)
{
_utf8Bytes[i] = *bytesPtr;
bytesPtr++;
}
string result = "";
while (succeeded)
{
succeeded = Utf8Helper.TryDecodeCodePoint(_utf8Bytes, _index, out uint codePoint, out _currentLenCache);
if (succeeded)
{
var currentChar = String.FromChar((char)codePoint);
Interop.mincore.OutputDebugString(IntToString(_index) + " - SUCCEEDED - " + currentChar); // IntToString((int)codePoint));
result += currentChar;
}
else
Interop.mincore.OutputDebugString(IntToString(_index) + " - FAILED - " + String.FromChar((char)codePoint)); // IntToString((int)codePoint));
_index += _currentLenCache;
}
return result;
}
// From https://stackoverflow.com/questions/17575375/how-do-i-convert-an-int-to-a-string-in-c-sharp-without-using-tostring/17575453#17575453
public static string IntToString(int a)
{
var chars = new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
var str = ""; // string.Empty;
if (a == 0)
{
str = chars[0];
}
else if (a == int.MinValue)
{
str = "-2147483648";
}
else
{
bool isNegative = (a < 0);
if (isNegative)
{
a = -a;
}
while (a > 0)
{
str = chars[a % 10] + str;
a /= 10;
}
if (isNegative)
{
str = "-" + str;
}
}
return str;
}
}
// From https://github.com/dotnet/corefxlab/blob/master/src/System.Text.Utf8String/System/Text/Primitives/Utf8Helper.cs#L30
// Just changed from ReadOnlySpan<byte> -> byte[]
internal static class Utf8Helper
{
#region Constants
// To get this to compile with dotnet cli, we need to temporarily un-binary the magic values
private const byte b0000_0111U = 0x07; //7
private const byte b0000_1111U = 0x0F; //15
private const byte b0001_1111U = 0x1F; //31
private const byte b0011_1111U = 0x3F; //63
private const byte b0111_1111U = 0x7F; //127
private const byte b1000_0000U = 0x80; //128
private const byte b1100_0000U = 0xC0; //192
private const byte b1110_0000U = 0xE0; //224
private const byte b1111_0000U = 0xF0; //240
private const byte b1111_1000U = 0xF8; //248
private const byte NonFirstByteInCodePointValue = 0x80;
private const byte NonFirstByteInCodePointMask = 0xC0;
public const int MaxCodeUnitsPerCodePoint = 4;
#endregion Constants
public static bool TryDecodeCodePoint(byte[] utf8, int index, out uint codePoint, out int bytesConsumed)
{
if (index >= utf8.Length)
{
codePoint = default;
bytesConsumed = 0;
return false;
}
var first = utf8[index];
bytesConsumed = GetEncodedBytes(first);
if (bytesConsumed == 0 || utf8.Length - index < bytesConsumed)
{
bytesConsumed = 0;
codePoint = default;
return false;
}
switch (bytesConsumed)
{
case 1:
codePoint = first;
break;
case 2:
codePoint = (uint)(first & b0001_1111U);
break;
case 3:
codePoint = (uint)(first & b0000_1111U);
break;
case 4:
codePoint = (uint)(first & b0000_0111U);
break;
default:
codePoint = default;
bytesConsumed = 0;
return false;
}
for (var i = 1; i < bytesConsumed; i++)
{
uint current = utf8[index + i];
if ((current & b1100_0000U) != b1000_0000U)
{
bytesConsumed = 0;
codePoint = default;
return false;
}
codePoint = (codePoint << 6) | (b0011_1111U & current);
}
return true;
}
private static int GetEncodedBytes(byte b)
{
if ((b & b1000_0000U) == 0)
return 1;
if ((b & b1110_0000U) == b1100_0000U)
return 2;
if ((b & b1111_0000U) == b1110_0000U)
return 3;
if ((b & b1111_1000U) == b1111_0000U)
return 4;
return 0;
}
public static int GetNumberOfEncodedBytes(uint codePoint)
{
if (codePoint <= 0x7F)
return 1;
if (codePoint <= 0x7FF)
return 2;
if (codePoint <= 0xFFFF)
return 3;
if (codePoint <= 0x10FFFF)
return 4;
return 0;
}
}
}
System__OtherRequiredCode.cs
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Runtime;
using System.Threading;
using System.Text;
using System.Runtime.ConstrainedExecution;
// From corert\src\System.Private.CoreLib\src\System\Buffer.cs
#if BIT64
using nint = System.Int64;
using nuint = System.UInt64;
#else
using nint = System.Int32;
using nuint = System.UInt32;
#endif
internal static partial class Interop
{
// From corert\src\System.Private.CoreLib\shared\Interop\Windows\Interop.Libraries.cs
internal static partial class Libraries
{
internal const string Kernel32 = "kernel32.dll";
}
// From corert\src\System.Private.CoreLib\shared\Interop\Windows\Kernel32\Interop.CloseHandle.cs
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr handle);
}
internal static unsafe partial class mincore
{
// From corert\src\Common\src\Interop\Windows\mincore\Interop.DynamicLoad.cs
[DllImport("api-ms-win-core-libraryloader-l1-2-0.dll")]
internal static extern IntPtr GetProcAddress(IntPtr hModule, byte* lpProcName);
[DllImport("api-ms-win-core-libraryloader-l1-2-0.dll", EntryPoint = "LoadLibraryExW", CharSet = CharSet.Unicode)]
internal static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, int dwFlags);
[DllImport("api-ms-win-core-libraryloader-l1-2-0.dll")]
internal static extern bool FreeLibrary(IntPtr hModule);
// From corert\src\Common\src\Interop\Windows\mincore\Interop.GetLastError.cs
[DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")]
internal extern static int GetLastError();
// From corert\src\Common\src\Interop\Windows\mincore\Interop.SetLastError.cs
[DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")]
internal extern static void SetLastError(uint dwErrCode);
// From corert\src\System.Private.CoreLib\src\Interop\Interop.manual.cs
[DllImport("api-ms-win-core-debug-l1-1-0.dll", EntryPoint = "OutputDebugStringW", CharSet = CharSet.Unicode)]
internal extern static void OutputDebugString(string lpOutputString);
}
}
// From https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/Microsoft/Win32/Win32Native.cs
namespace Microsoft.Win32
{
internal static class Win32Native
{
[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
internal static extern unsafe int WriteFile(SafeFileHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
// Note, these are #defines used to extract handles, and are NOT handles.
internal const int STD_INPUT_HANDLE = -10;
internal const int STD_OUTPUT_HANDLE = -11;
internal const int STD_ERROR_HANDLE = -12;
[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
internal static extern IntPtr GetStdHandle(int nStdHandle); // param is NOT a handle, but it returns one!
}
}
namespace System.Diagnostics.CodeAnalysis
{
public class SuppressMessageAttribute : Attribute
{
public SuppressMessageAttribute(string category, string checkId)
{ }
}
}
namespace Microsoft.Win32.SafeHandles
{
// From corert\src\System.Private.CoreLib\shared\Microsoft\Win32\SafeHandles\SafeHandleZeroOrMinusOneIsInvalid.cs
// Class of safe handle which uses 0 or -1 as an invalid handle.
public abstract class SafeHandleZeroOrMinusOneIsInvalid : SafeHandle
{
protected SafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
{
}
public override bool IsInvalid => handle == IntPtr.Zero || handle == new IntPtr(-1);
}
// From corert\src\System.Private.CoreLib\shared\Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs (cut-down)
public sealed class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeFileHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(preexistingHandle);
}
override protected bool ReleaseHandle()
{
return Interop.Kernel32.CloseHandle(handle);
}
}
}
namespace System
{
// Code from corert\src\System.Private.CoreLib\src\System\GC.cs
public static partial class GC
{
public static void SuppressFinalize(Object obj)
{
if (obj == null)
{
throw new ArgumentNullException(); // nameof(obj));
}
RuntimeImports.RhSuppressFinalize(obj);
}
}
// Code from corert\src\System.Private.CoreLib\src\System\Environment.cs
public static partial class Environment
{
public static String NewLine
{
get
{
#if !PLATFORM_UNIX
return "\r\n";
#else
return "\n";
#endif // !PLATFORM_UNIX
}
}
}
// From corert\src\System.Private.CoreLib\src\System\InvokeUtils.cs
public class InvokeUtils
{
public class ArgSetupState
{
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
internal static void DynamicInvokeArgSetupComplete(ref ArgSetupState argSetupState)
{
//int parametersLength = s_parameters != null ? s_parameters.Length : 0;
//if (s_curIndex != parametersLength)
//{
// throw new System.Reflection.TargetParameterCountException();
//}
//argSetupState.fComplete = true;
//argSetupState.nullableCopyBackObjects = s_nullableCopyBackObjects;
//s_nullableCopyBackObjects = null;
// TODO MattW fix this!!
//Console.WriteLine("## InvalidOperationException - DynamicInvokeArgSetupComplete ##");
throw new InvalidOperationException();
}
//[DebuggerStepThrough]
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
internal static ref IntPtr DynamicInvokeParamHelperIn(RuntimeTypeHandle rth)
{
////
//// Call DynamicInvokeParamHelperCore as an in parameter, and return a managed byref to the interesting bit.
////
//// This function exactly matches DynamicInvokeParamHelperRef except for the value of the enum passed to DynamicInvokeParamHelperCore
////
//int index;
//DynamicInvokeParamLookupType paramLookupType;
//object obj = DynamicInvokeParamHelperCore(rth, out paramLookupType, out index, DynamicInvokeParamType.In);
//if (paramLookupType == DynamicInvokeParamLookupType.ValuetypeObjectReturned)
//{
// return ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData());
//}
//else
//{
// return ref Unsafe.As<object, IntPtr>(ref Unsafe.As<object[]>(obj)[index]);
//}
// TODO MattW fix this!!
//Console.WriteLine("## InvalidOperationException - DynamicInvokeParamHelperIn ##");
throw new InvalidOperationException();
}
//[DebuggerStepThrough]
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
internal static ref IntPtr DynamicInvokeParamHelperRef(RuntimeTypeHandle rth)
{
////
//// Call DynamicInvokeParamHelperCore as a ref parameter, and return a managed byref to the interesting bit. As this can't actually be defined in C# there is an IL transform that fills this in.
////
//// This function exactly matches DynamicInvokeParamHelperIn except for the value of the enum passed to DynamicInvokeParamHelperCore
////
//int index;
//DynamicInvokeParamLookupType paramLookupType;
//object obj = DynamicInvokeParamHelperCore(rth, out paramLookupType, out index, DynamicInvokeParamType.Ref);
//if (paramLookupType == DynamicInvokeParamLookupType.ValuetypeObjectReturned)
//{
// return ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData());
//}
//else
//{
// return ref Unsafe.As<object, IntPtr>(ref Unsafe.As<object[]>(obj)[index]);
//}
// TODO MattW fix this!!
//Console.WriteLine("## InvalidOperationException - DynamicInvokeParamHelperRef ##");
throw new InvalidOperationException();
}
}
}
namespace System.Runtime.InteropServices
{
// From corert\src\System.Private.CoreLib\src\System\Runtime\InteropServices\PInvokeMarshal.Windows.cs
public partial class PInvokeMarshal
{
[ThreadStatic]
internal static int s_lastWin32Error;
public static void SaveLastWin32Error()
{
s_lastWin32Error = Interop.mincore.GetLastError();
}
public static void ClearLastWin32Error()
{
Interop.mincore.SetLastError(0);
}
}
}
namespace System.Runtime.CompilerServices
{
// From corert\src\System.Private.CoreLib\src\System\Runtime\CompilerServices\RuntimeHelpers.cs
public static class RuntimeHelpers
{
public static int OffsetToStringData
{
get
{
// Number of bytes from the address pointed to by a reference to
// a String to the first 16-bit character in the String.
// This property allows C#'s fixed statement to work on Strings.
return String.FIRST_CHAR_OFFSET;
}
}
}
}
// From corert\src\System.Private.CoreLib\src\Internal\Runtime\CompilerHelpers\InteropHelpers.cs
namespace Internal.Runtime.CompilerHelpers
{
internal static class InteropHelpers
{
internal static unsafe IntPtr ResolvePInvoke(MethodFixupCell* pCell)
{
Interop.mincore.OutputDebugString("In ResolvePInvoke");
if (pCell->Target != IntPtr.Zero)
return pCell->Target;
//return ResolvePInvokeSlow(pCell);
IntPtr result = ResolvePInvokeSlow(pCell);
Interop.mincore.OutputDebugString("In ResolvePInvoke (After ResolvePInvokeSlow())");
return result;
}
internal static unsafe IntPtr ResolvePInvokeSlow(MethodFixupCell* pCell)
{
Interop.mincore.OutputDebugString("In ResolvePInvokeSlow");
ModuleFixupCell* pModuleCell = pCell->Module;
IntPtr hModule = pModuleCell->Handle;
if (hModule == IntPtr.Zero)
{
FixupModuleCell(pModuleCell);
hModule = pModuleCell->Handle;
}
FixupMethodCell(hModule, pCell);
return pCell->Target;
}
internal static unsafe IntPtr TryResolveModule(string moduleName)
{
Interop.mincore.OutputDebugString("In TryResolveModule - " + moduleName);
IntPtr hModule = IntPtr.Zero;
// Try original name first
hModule = LoadLibrary(moduleName);
if (hModule != IntPtr.Zero)
return hModule;
#if PLATFORM_UNIX
const string PAL_SHLIB_PREFIX = "lib";
#if PLATFORM_OSX
const string PAL_SHLIB_SUFFIX = ".dylib";
#else
const string PAL_SHLIB_SUFFIX = ".so";
#endif
// Try prefix+name+suffix
hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName + PAL_SHLIB_SUFFIX);
if (hModule != IntPtr.Zero) return hModule;
// Try name+suffix
hModule = LoadLibrary(moduleName + PAL_SHLIB_SUFFIX);
if (hModule != IntPtr.Zero) return hModule;
// Try prefix+name
hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName);
if (hModule != IntPtr.Zero) return hModule;
#endif
return IntPtr.Zero;
}
internal static unsafe IntPtr LoadLibrary(string moduleName)
{
Interop.mincore.OutputDebugString("In LoadLibrary " + moduleName);
IntPtr hModule;
#if !PLATFORM_UNIX
hModule = Interop.mincore.LoadLibraryEx(moduleName, IntPtr.Zero, 0);
#else
hModule = Interop.Sys.LoadLibrary(moduleName);
#endif
return hModule;
}
internal static unsafe void FreeLibrary(IntPtr hModule)
{
Interop.mincore.OutputDebugString("In FreeLibrary");
#if !PLATFORM_UNIX
Interop.mincore.FreeLibrary(hModule);
#else
Interop.Sys.FreeLibrary(hModule);
#endif
}
private static unsafe string GetModuleName(ModuleFixupCell* pCell)
{
byte* pModuleName = (byte*)pCell->ModuleName;
//return Encoding.UTF8.GetString(pModuleName, strlen(pModuleName));
Interop.mincore.OutputDebugString("In GetModuleName (Before strlen())");
var len = strlen(pModuleName);
Interop.mincore.OutputDebugString("In GetModuleName (Before Encoding.UTF8.GetString())");
//var moduleName = Encoding.UTF8.GetString(pModuleName, len); //, strlen(pModuleName));
var moduleName = UnicodeEncoding.GetString(pModuleName, strlen(pModuleName));
Interop.mincore.OutputDebugString("In GetModuleName -> " + moduleName + " (After Encoding.UTF8.GetString())");
return moduleName;
}
internal static unsafe void FixupModuleCell(ModuleFixupCell* pCell)
{
Interop.mincore.OutputDebugString("In FixupModuleCell (1a)");
string moduleName = GetModuleName(pCell);
Interop.mincore.OutputDebugString("In FixupModuleCell (1b)");
IntPtr hModule = TryResolveModule(moduleName);
Interop.mincore.OutputDebugString("In FixupModuleCell (1c)");
if (hModule != IntPtr.Zero)
{
var oldValue = Interlocked.CompareExchange(ref pCell->Handle, hModule, IntPtr.Zero);
if (oldValue != IntPtr.Zero)
{
// Some other thread won the race to fix it up.
FreeLibrary(hModule);
}
}
else
{
//throw new DllNotFoundException(SR.Format(SR.Arg_DllNotFoundExceptionParameterized, moduleName));
throw new DllNotFoundException("DllNotFoundExceptionParameterized - " + moduleName);
}
}
internal static unsafe void FixupMethodCell(IntPtr hModule, MethodFixupCell* pCell)
{
Interop.mincore.OutputDebugString("In FixupModuleCell (2a)");
byte* methodName = (byte*)pCell->MethodName;
Interop.mincore.OutputDebugString("In FixupModuleCell (2a) - " + UnicodeEncoding.GetString(methodName, strlen(methodName)));
#if PLATFORM_WINDOWS
pCell->Target = GetProcAddress(hModule, methodName, pCell->CharSetMangling);
#else
pCell->Target = Interop.Sys.GetProcAddress(hModule, methodName);
#endif
if (pCell->Target == IntPtr.Zero)
{
//string entryPointName = Encoding.UTF8.GetString(methodName, strlen(methodName));
string entryPointName = UnicodeEncoding.GetString(methodName, strlen(methodName));
Interop.mincore.OutputDebugString("In FixupMethodCell -> " + entryPointName);
//throw new EntryPointNotFoundException(SR.Format(SR.Arg_EntryPointNotFoundExceptionParameterized, entryPointName, GetModuleName(pCell->Module)));
throw new EntryPointNotFoundException("EntryPointNotFoundExceptionParameterized - " + entryPointName + " - " + GetModuleName(pCell->Module));
}
else
{
Interop.mincore.OutputDebugString("In FixupMethodCell pCell->Target IS NOT IntPtr.Zero");
}
}
#if PLATFORM_WINDOWS
private static unsafe IntPtr GetProcAddress(IntPtr hModule, byte* methodName, CharSet charSetMangling)
{
Interop.mincore.OutputDebugString("In GetProcAddress (1)");
// First look for the unmangled name. If it is unicode function, we are going
// to need to check for the 'W' API because it takes precedence over the
// unmangled one (on NT some APIs have unmangled ANSI exports).
var exactMatch = Interop.mincore.GetProcAddress(hModule, methodName);
Interop.mincore.OutputDebugString("In GetProcAddress (2)");
if ((charSetMangling == CharSet.Ansi && exactMatch != IntPtr.Zero) || charSetMangling == 0)
{
Interop.mincore.OutputDebugString("In GetProcAddress (3)");
return exactMatch;
}
Interop.mincore.OutputDebugString("In GetProcAddress (4)");
int nameLength = strlen(methodName);
// We need to add an extra byte for the suffix, and an extra byte for the null terminator
byte* probedMethodName = stackalloc byte[nameLength + 2];
for (int i = 0; i < nameLength; i++)
{
probedMethodName[i] = methodName[i];
}
probedMethodName[nameLength + 1] = 0;
probedMethodName[nameLength] = (charSetMangling == CharSet.Ansi) ? (byte)'A' : (byte)'W';
Interop.mincore.OutputDebugString("In GetProcAddress (5)");
IntPtr probedMethod = Interop.mincore.GetProcAddress(hModule, probedMethodName);
Interop.mincore.OutputDebugString("In GetProcAddress (6)");
if (probedMethod != IntPtr.Zero)
{
return probedMethod;
}
return exactMatch;
}
#endif
internal static unsafe int strlen(byte* pString)
{
byte* p = pString;
while (*p != 0)
p++;
return checked((int)(p - pString));
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ModuleFixupCell
{
public IntPtr Handle;
public IntPtr ModuleName;
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct MethodFixupCell
{
public IntPtr Target;
public IntPtr MethodName;
public ModuleFixupCell* Module;
public CharSet CharSetMangling;
}
}
}
namespace System.Reflection
{
//[CLSCompliant(false)]
public sealed unsafe class Pointer //: ISerializable
{
// CoreCLR: Do not add or remove fields without updating the ReflectionPointer class in runtimehandles.h
private readonly void* _ptr;
private readonly Type _ptrType;
private Pointer(void* ptr, Type ptrType)
{
//Debug.Assert(ptrType.IsRuntimeImplemented()); // CoreCLR: For CoreRT's sake, _ptrType has to be declared as "Type", but in fact, it is always a RuntimeType. Code on CoreCLR expects this.
_ptr = ptr;
_ptrType = ptrType;
}
public static object Box(void* ptr, Type type)
{
if (type == null)
throw new ArgumentNullException(); // nameof(type));
//if (!type.IsPointer)
// throw new ArgumentException(SR.Arg_MustBePointer, nameof(ptr));
//if (!type.IsRuntimeImplemented())
// throw new ArgumentException(SR.Arg_MustBeType, nameof(ptr));
return new Pointer(ptr, type);
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
System\Console.cs