Guo Hui 6 yıl önce
ebeveyn
işleme
05442aaef4

+ 164 - 32
src/Native/natsu.fcall.cpp

@@ -1,5 +1,6 @@
 #include "Chino.Kernel.h"
 #include "System.Private.CorLib.h"
+#include <cmath>
 #include <cstring>
 
 #ifdef WIN32
@@ -7,62 +8,56 @@
 #endif
 
 using namespace natsu;
+using namespace System_Private_CorLib;
 using namespace System_Private_CorLib::System;
+using namespace System_Private_CorLib::System::Diagnostics;
+using namespace System_Private_CorLib::System::Runtime::CompilerServices;
 
-namespace System_Private_CorLib
-{
-::natsu::gc_obj_ref<::System_Private_CorLib::System::Type> System::Object::GetType(::natsu::gc_obj_ref<::System_Private_CorLib::System::Object> _this)
-{
-    return ::natsu::null;
-}
-
-::System_Private_CorLib::System::Int32 System::Array::GetLength(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this, ::System_Private_CorLib::System::Int32 dimension)
+Int32 Array::GetLength(gc_obj_ref<Array> _this, Int32 dimension)
 {
     if (dimension != 0)
         throw_exception<IndexOutOfRangeException>();
-    return (intptr_t)_this.cast<System::Runtime::CompilerServices::RawSzArrayData>()->Count;
+    return (intptr_t)_this.cast<RawSzArrayData>()->Count;
 }
 
-::System_Private_CorLib::System::Int32 System::Array::get_Rank(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this)
+Int32 Array::get_Rank(gc_obj_ref<Array> _this)
 {
     return 1;
 }
 
-::System_Private_CorLib::System::Int32 System::Array::get_Length(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this)
+Int32 Array::get_Length(gc_obj_ref<Array> _this)
 {
-    return (intptr_t)_this.cast<System::Runtime::CompilerServices::RawSzArrayData>()->Count;
+    return (intptr_t)_this.cast<RawSzArrayData>()->Count;
 }
 
-::System_Private_CorLib::System::Int64 System::Array::get_LongLength(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this)
+Int64 Array::get_LongLength(gc_obj_ref<Array> _this)
 {
-    return (intptr_t)_this.cast<System::Runtime::CompilerServices::RawSzArrayData>()->Count;
+    return (intptr_t)_this.cast<RawSzArrayData>()->Count;
 }
 
-::System_Private_CorLib::System::Int32 System::Array::GetUpperBound(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this, ::System_Private_CorLib::System::Int32 dimension)
+Int32 Array::GetUpperBound(gc_obj_ref<Array> _this, Int32 dimension)
 {
     return GetLength(_this, dimension);
 }
 
-::System_Private_CorLib::System::Int32 System::Array::GetLowerBound(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> _this, ::System_Private_CorLib::System::Int32 dimension)
+Int32 Array::GetLowerBound(gc_obj_ref<Array> _this, Int32 dimension)
 {
     if (dimension != 0)
         throw_exception<IndexOutOfRangeException>();
     return 0;
 }
 
-void System::Array::_s_Copy(::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> sourceArray, ::System_Private_CorLib::System::Int32 sourceIndex, ::natsu::gc_obj_ref<::System_Private_CorLib::System::Array> destinationArray, ::System_Private_CorLib::System::Int32 destinationIndex, ::System_Private_CorLib::System::Int32 length, ::System_Private_CorLib::System::Boolean reliable)
+void Array::_s_Copy(gc_obj_ref<Array> sourceArray, Int32 sourceIndex, gc_obj_ref<Array> destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
 {
     throw_exception<InvalidOperationException>();
 }
 
-::System_Private_CorLib::System::Char System::String::get_Chars(::natsu::gc_obj_ref<::System_Private_CorLib::System::String> _this, ::System_Private_CorLib::System::Int32 index)
+void Buffer::_s_Memcpy(gc_ptr<Byte> dest, gc_ptr<Byte> src, Int32 len)
 {
-    if ((uint32_t)index >= (uint32_t)_this->_stringLength)
-        throw_exception<IndexOutOfRangeException>();
-    return (&_this->_firstChar)[index];
+    std::memcpy(dest, src, len);
 }
 
-void System::Diagnostics::Debug::_s_WriteCore(::natsu::gc_obj_ref<::System_Private_CorLib::System::String> message)
+void Debug::_s_WriteCore(gc_obj_ref<String> message)
 {
 #ifdef WIN32
     assert(message);
@@ -72,7 +67,7 @@ void System::Diagnostics::Debug::_s_WriteCore(::natsu::gc_obj_ref<::System_Priva
 #endif
 }
 
-void System::Diagnostics::Debug::_s_WriteLineCore(::natsu::gc_obj_ref<::System_Private_CorLib::System::String> message)
+void Debug::_s_WriteLineCore(gc_obj_ref<String> message)
 {
 #ifdef WIN32
     static const char16_t new_line[] = u"\n";
@@ -85,7 +80,7 @@ void System::Diagnostics::Debug::_s_WriteLineCore(::natsu::gc_obj_ref<::System_P
 #endif
 }
 
-void System::Diagnostics::Debug::_s_FailCore(::natsu::gc_obj_ref<::System_Private_CorLib::System::String> message, ::natsu::gc_obj_ref<::System_Private_CorLib::System::String> detailMessage)
+void Debug::_s_FailCore(gc_obj_ref<String> message, gc_obj_ref<String> detailMessage)
 {
 #ifdef WIN32
     assert(message);
@@ -95,27 +90,164 @@ void System::Diagnostics::Debug::_s_FailCore(::natsu::gc_obj_ref<::System_Privat
 #endif
 }
 
-void System::Buffer::_s_Memcpy(::natsu::gc_ptr<::System_Private_CorLib::System::Byte> dest, ::natsu::gc_ptr<::System_Private_CorLib::System::Byte> src, ::System_Private_CorLib::System::Int32 len)
+void Buffer::_s_Memmove(gc_ptr<Byte> dest, gc_ptr<Byte> src, UInt64 len)
 {
-    std::memcpy(dest, src, len);
+    std::memmove(dest, src, len);
 }
 
-void System::Buffer::_s_Memmove(::natsu::gc_ptr<::System_Private_CorLib::System::Byte> dest, ::natsu::gc_ptr<::System_Private_CorLib::System::Byte> src, ::System_Private_CorLib::System::UInt64 len)
+gc_obj_ref<Type> Object::GetType(::natsu::gc_obj_ref<Object> _this)
 {
-    std::memmove(dest, src, len);
+    check_null_obj_ref(_this);
+    return ::natsu::null;
+}
+
+Char String::get_Chars(gc_obj_ref<String> _this, Int32 index)
+{
+    if ((uint32_t)index >= (uint32_t)_this->_stringLength)
+        throw_exception<IndexOutOfRangeException>();
+    return (&_this->_firstChar)[index];
 }
 
-::System_Private_CorLib::System::Int32 System::String::get_Length(::natsu::gc_obj_ref<::System_Private_CorLib::System::String> _this)
+Int32 String::get_Length(gc_obj_ref<String> _this)
 {
     return _this->_stringLength;
 }
 
-::natsu::gc_obj_ref<::System_Private_CorLib::System::String> System::String::_s_FastAllocateString(::System_Private_CorLib::System::Int32 length)
+gc_obj_ref<String> String::_s_FastAllocateString(Int32 length)
 {
-    auto size = sizeof(System::String) + length * sizeof(System::Char);
-    auto obj = natsu::gc_new<System::String>(size);
+    auto size = sizeof(String) + length * sizeof(Char);
+    auto obj = natsu::gc_new<String>(size);
     obj->_stringLength = length;
     (&obj->_firstChar)[length] = 0;
     return obj;
 }
+
+Int32 String::_s_wcslen(gc_ptr<Char> ptr)
+{
+    return (int32_t)wcslen(reinterpret_cast<wchar_t *>(ptr.get()));
+}
+
+Double Math::_s_Abs(Double value)
+{
+    return fabs(value.m_value);
+}
+
+Single Math::_s_Abs(Single value)
+{
+    return fabsf(value.m_value);
+}
+
+Double Math::_s_Acos(Double value)
+{
+    return acos(value.m_value);
+}
+
+Double Math::_s_Acosh(Double value)
+{
+    return acosh(value.m_value);
+}
+
+Double Math::_s_Asin(Double value)
+{
+    return asin(value.m_value);
+}
+
+Double Math::_s_Asinh(Double value)
+{
+    return asinh(value.m_value);
+}
+
+Double Math::_s_Atan(Double value)
+{
+    return atan(value.m_value);
+}
+
+Double Math::_s_Atan2(Double y, Double x)
+{
+    return atan2(y.m_value, x.m_value);
+}
+
+Double Math::_s_Atanh(Double value)
+{
+    return atanh(value.m_value);
+}
+
+Double Math::_s_Cbrt(Double value)
+{
+    return cbrt(value.m_value);
+}
+
+Double Math::_s_Ceiling(Double value)
+{
+    return ceil(value.m_value);
+}
+
+Double Math::_s_Cos(Double value)
+{
+    return cos(value.m_value);
+}
+
+Double Math::_s_Cosh(Double value)
+{
+    return cosh(value.m_value);
+}
+
+Double Math::_s_Exp(Double value)
+{
+    return exp(value.m_value);
+}
+
+Double Math::_s_Floor(Double value)
+{
+    return floor(value.m_value);
+}
+
+Double Math::_s_Log(Double value)
+{
+    return log(value.m_value);
+}
+
+Double Math::_s_Log10(Double value)
+{
+    return log10(value.m_value);
+}
+
+Double Math::_s_Pow(Double x, Double y)
+{
+    return pow(x.m_value, y.m_value);
+}
+
+Double Math::_s_Sin(Double value)
+{
+    return sin(value.m_value);
+}
+
+Double Math::_s_Sinh(Double value)
+{
+    return sinh(value.m_value);
+}
+
+Double Math::_s_Sqrt(Double value)
+{
+    return sqrt(value.m_value);
+}
+
+Double Math::_s_Tan(Double value)
+{
+    return tan(value.m_value);
+}
+
+Double Math::_s_Tanh(Double value)
+{
+    return tanh(value.m_value);
+}
+
+Double Math::_s_FMod(Double x, Double y)
+{
+    return fmod(x.m_value, y.m_value);
+}
+
+Double Math::_s_ModF(Double x, gc_ptr<Double> y)
+{
+    return modf(x.m_value, &y->m_value);
 }

+ 4 - 0
src/Native/natsu.gc.cpp

@@ -185,6 +185,10 @@ void InitializeHeap() noexcept
 
 void *HeapAlloc(size_t wantedSize) noexcept
 {
+#ifdef WIN32
+    InitializeHeap();
+#endif
+
     BlockLink_t *pBlock, *pPreviousBlock, *pNewBlockLink;
     void *pReturn = nullptr;
     uintptr_t alignOffset = 0;

+ 0 - 3
src/Native/natsu.runtime.cpp

@@ -12,9 +12,6 @@ void InitializeHeap() noexcept;
 
 gc_obj_ref<::System_Private_CorLib::System::String> natsu::load_string(std::u16string_view string)
 {
-#ifdef WIN32
-    InitializeHeap();
-#endif
     auto dest = System_Private_CorLib::System::String::_s_FastAllocateString(string.length());
     std::copy(string.begin(), string.end(), &dest->_firstChar);
     (&dest->_firstChar)[string.length()] = 0;

+ 169 - 43
src/Native/natsu.runtime.h

@@ -17,7 +17,7 @@ namespace stack
         constexpr int32(int32_t value)
             : value_(value) {}
 
-        constexpr operator bool() const noexcept
+        constexpr bool istrue() const noexcept
         {
             return value_;
         }
@@ -30,7 +30,7 @@ namespace stack
         constexpr int64(int64_t value)
             : value_(value) {}
 
-        constexpr operator bool() const noexcept
+        constexpr bool istrue() const noexcept
         {
             return value_;
         }
@@ -43,7 +43,7 @@ namespace stack
         constexpr native_int(intptr_t value)
             : value_(value) {}
 
-        constexpr operator bool() const noexcept
+        constexpr bool istrue() const noexcept
         {
             return value_;
         }
@@ -64,7 +64,7 @@ namespace stack
         constexpr Ref(uintptr_t value)
             : value_(value) {}
 
-        constexpr operator bool() const noexcept
+        constexpr bool istrue() const noexcept
         {
             return value_;
         }
@@ -77,7 +77,7 @@ namespace stack
         constexpr O(uintptr_t value)
             : value_(value) {}
 
-        constexpr operator bool() const noexcept
+        constexpr bool istrue() const noexcept
         {
             return value_;
         }
@@ -140,26 +140,28 @@ namespace stack
             }
         };
 
-#define DEFINE_STACK_FROM_CAST(From, To, Med)           \
-    template <>                                         \
-    struct stack_from_impl<From>                        \
-    {                                                   \
-        To operator()(const From &value) const noexcept \
-        {                                               \
-            return static_cast<Med>(value.m_value);     \
-        }                                               \
+#define DEFINE_STACK_FROM_CAST(From, To, Med, Cast)                    \
+    template <>                                                        \
+    struct stack_from_impl<From>                                       \
+    {                                                                  \
+        To operator()(const From &value) const noexcept                \
+        {                                                              \
+            return static_cast<Cast>(static_cast<Med>(value.m_value)); \
+        }                                                              \
     };
 
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Boolean, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::SByte, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Byte, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Char, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int16, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt16, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int32, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt32, int32, int32_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int64, int64, int64_t);
-        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt64, int64, int64_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Boolean, int32, uint32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::SByte, int32, int32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Byte, int32, uint32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Char, int32, uint32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int16, int32, int32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt16, int32, uint32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int32, int32, int32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt32, int32, uint32_t, int32_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Int64, int64, int64_t, int64_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::UInt64, int64, uint64_t, int64_t);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Single, F, float, double);
+        DEFINE_STACK_FROM_CAST(::System_Private_CorLib::System::Double, F, double, double);
 
 #undef DEFINE_STACK_FROM_CAST
 
@@ -180,7 +182,10 @@ namespace stack
         {
             TTo operator()(TFrom value)
             {
-                return static_cast<TTo>(value);
+                if constexpr (natsu::is_enum_v<TTo>)
+                    return static_cast<TTo>(value.value_);
+                else
+                    return value;
             }
         };
 
@@ -202,6 +207,33 @@ namespace stack
             }
         };
 
+        template <class TTo>
+        struct stack_to_impl<Ref, gc_ptr<TTo>>
+        {
+            gc_ptr<TTo> operator()(const Ref &value) const noexcept
+            {
+                return gc_ptr<TTo>(reinterpret_cast<TTo *>(value.value_));
+            }
+        };
+
+        template <class TTo>
+        struct stack_to_impl<native_int, gc_ref<TTo>>
+        {
+            gc_ref<TTo> operator()(const native_int &value) const noexcept
+            {
+                return gc_ref<TTo>(*reinterpret_cast<TTo *>(value.value_));
+            }
+        };
+
+        template <class TTo>
+        struct stack_to_impl<native_int, gc_ptr<TTo>>
+        {
+            gc_ptr<TTo> operator()(const native_int &value) const noexcept
+            {
+                return gc_ptr<TTo>(reinterpret_cast<TTo *>(value.value_));
+            }
+        };
+
 #define DEFINE_STACK_TO_CAST(From, To, Med)             \
     template <>                                         \
     struct stack_to_impl<From, To>                      \
@@ -375,7 +407,7 @@ namespace stack
         {
             O operator()(const O &obj) const noexcept
             {
-                if (obj && obj.header().vtable_as<typename T::VTable>())
+                if (obj.istrue() && obj.header().vtable_as<typename T::VTable>())
                     return obj;
                 return null;
             }
@@ -389,6 +421,36 @@ namespace stack
                 return isinst_impl<T>()(obj);
             }
         };
+
+        template <class TFrom, class TTo>
+        struct access_impl;
+
+        template <class TFrom, class TTo>
+        struct access_impl<TFrom, gc_ref<TTo>>
+        {
+            gc_ref<TTo> operator()(const TFrom &obj) const noexcept
+            {
+                return gc_ref_from_ref(stack_to<TTo>(obj));
+            }
+        };
+
+        template <class TTo>
+        struct access_impl<Ref, gc_ref<TTo>>
+        {
+            gc_ref<TTo> operator()(const Ref &obj) const noexcept
+            {
+                return stack_to<gc_ref<TTo>>(obj);
+            }
+        };
+
+        template <class TTo>
+        struct access_impl<O, TTo>
+        {
+            TTo operator()(const O &obj) const noexcept
+            {
+                return stack_to<TTo>(obj);
+            }
+        };
     }
 }
 
@@ -406,19 +468,19 @@ auto stack_to(TFrom &&value)
 
 inline void check_null_obj_ref(stack::O obj)
 {
-    if (!obj)
+    if (!obj.istrue())
         throw_null_ref_exception();
 }
 
 inline void check_null_obj_ref(stack::native_int addr)
 {
-    if (!addr)
+    if (!addr.istrue())
         throw_null_ref_exception();
 }
 
 inline void check_null_obj_ref(stack::Ref addr)
 {
-    if (!addr)
+    if (!addr.istrue())
         throw_null_ref_exception();
 }
 
@@ -438,12 +500,12 @@ gc_obj_ref<T> gc_new()
 }
 
 template <class T>
-gc_obj_ref<::System_Private_CorLib::System::SZArray_1<T>> gc_new_array(int32_t length)
+gc_obj_ref<::System_Private_CorLib::System::SZArray_1<T>> gc_new_array(stack::int32 length)
 {
     using obj_t = ::System_Private_CorLib::System::SZArray_1<T>;
-    auto size = sizeof(obj_t) + (size_t)length * sizeof(T);
+    auto size = sizeof(obj_t) + (size_t)length.value_ * sizeof(T);
     auto obj = gc_new<obj_t>(size);
-    obj->Length = length;
+    obj->Length = length.value_;
     return obj;
 }
 
@@ -481,10 +543,10 @@ template <class T, class... TArgs>
 
 namespace ops
 {
-#define BINARY_OP_IMPL(name, op, A, B, Ret, Med, Cast)                                            \
-    inline Ret name(const A &lhs, const B &rhs) noexcept                                          \
-    {                                                                                             \
-        return static_cast<Cast>(static_cast<Med>(lhs.value_)##op##static_cast<Med>(rhs.value_)); \
+#define BINARY_OP_IMPL(name, op, A, B, Ret, Med, Cast)                                          \
+    inline Ret name(const A &lhs, const B &rhs) noexcept                                        \
+    {                                                                                           \
+        return static_cast<Cast>(static_cast<Med>(lhs.value_) op static_cast<Med>(rhs.value_)); \
     }
 
     BINARY_OP_IMPL(add, +, stack::int32, stack::int32, stack::int32, int32_t, int32_t);
@@ -584,10 +646,10 @@ namespace ops
         return fmod(lhs.value_, rhs.value_);
     }
 
-#define UNARY_OP_IMPL(name, op, A, Med, Cast)                         \
-    inline A name(const A &value) noexcept                            \
-    {                                                                 \
-        return static_cast<Cast>(op##static_cast<Med>(value.value_)); \
+#define UNARY_OP_IMPL(name, op, A, Med, Cast)                        \
+    inline A name(const A &value) noexcept                           \
+    {                                                                \
+        return static_cast<Cast>(op static_cast<Med>(value.value_)); \
     }
 
     UNARY_OP_IMPL(neg, -, stack::int32, int32_t, int32_t);
@@ -597,10 +659,10 @@ namespace ops
 
 #undef UNARY_OP_IMPL
 
-#define COMPARE_OP_IMPL(name, op, A, B, Med)                                           \
-    inline stack::int32 name(const A &lhs, const B &rhs) noexcept                      \
-    {                                                                                  \
-        return static_cast<Med>(lhs.value_)##op##static_cast<Med>(rhs.value_) ? 1 : 0; \
+#define COMPARE_OP_IMPL(name, op, A, B, Med)                                         \
+    inline stack::int32 name(const A &lhs, const B &rhs) noexcept                    \
+    {                                                                                \
+        return static_cast<Med>(lhs.value_) op static_cast<Med>(rhs.value_) ? 1 : 0; \
     }
 
     COMPARE_OP_IMPL(clt, <, stack::int32, stack::int32, int32_t);
@@ -745,6 +807,12 @@ namespace ops
         return reinterpret_cast<uintptr_t>(&value);
     }
 
+    template <class TTo, class TFrom>
+    auto access(TFrom value) noexcept
+    {
+        return stack::details::access_impl<TFrom, TTo>()(std::forward<TFrom>(value));
+    }
+
     template <class TFrom>
     void initobj(const stack::Ref &addr) noexcept
     {
@@ -763,6 +831,37 @@ namespace ops
         return stack::details::isinst_impl<T>()(obj);
     }
 
+#define LDELEM_IMPL(name, type, value_type)                                              \
+    inline value_type ldelem_##name(const stack::O &obj, stack::int32 index)             \
+    {                                                                                    \
+        using ::System_Private_CorLib::System::SZArray_1;                                \
+        check_null_obj_ref(obj);                                                         \
+        return stack_from(stack_to<gc_obj_ref<SZArray_1<type>>>(obj)->at(index.value_)); \
+    }
+
+    LDELEM_IMPL(i1, ::System_Private_CorLib::System::SByte, stack::int32);
+    LDELEM_IMPL(i2, ::System_Private_CorLib::System::Int16, stack::int32);
+    LDELEM_IMPL(i4, ::System_Private_CorLib::System::Int32, stack::int32);
+    LDELEM_IMPL(i8, ::System_Private_CorLib::System::Int64, stack::int64);
+    LDELEM_IMPL(r4, ::System_Private_CorLib::System::Single, stack::F);
+    LDELEM_IMPL(r8, ::System_Private_CorLib::System::Double, stack::F);
+    LDELEM_IMPL(i, ::System_Private_CorLib::System::IntPtr, stack::native_int);
+    LDELEM_IMPL(u1, ::System_Private_CorLib::System::Byte, stack::int32);
+    LDELEM_IMPL(u2, ::System_Private_CorLib::System::UInt16, stack::int32);
+    LDELEM_IMPL(u4, ::System_Private_CorLib::System::UInt32, stack::int32);
+    LDELEM_IMPL(u8, ::System_Private_CorLib::System::UInt64, stack::int64);
+    LDELEM_IMPL(u, ::System_Private_CorLib::System::UIntPtr, stack::native_int);
+
+    inline stack::O ldelem_ref(const stack::O &obj, stack::int32 index)
+    {
+        using ::System_Private_CorLib::System::Object;
+        using ::System_Private_CorLib::System::SZArray_1;
+        check_null_obj_ref(obj);
+        return stack_from(stack_to<gc_obj_ref<SZArray_1<gc_obj_ref<Object>>>>(obj)->at(index.value_));
+    }
+
+#undef LDELEM_IMPL
+
 #define STELEM_IMPL(name, type, value_type, cast)                                                       \
     inline void stelem_##name(const stack::O &obj, stack::int32 index, value_type value)                \
     {                                                                                                   \
@@ -1048,6 +1147,18 @@ namespace ops
         return stack_from(stack_to<gc_obj_ref<SZArray_1<T>>>(obj)->ref_at(index.value_));
     }
 
+    template <class T>
+    auto ldobj(const stack::Ref &addr)
+    {
+        return stack_from(*reinterpret_cast<T *>(addr.value_));
+    }
+
+    template <class T, class TStack>
+    void stobj(const TStack &src, const stack::Ref &dest)
+    {
+        *reinterpret_cast<T *>(dest.value_) = stack_to<T>(src);
+    }
+
     [[noreturn]] void throw_(const stack::O &obj);
 }
 
@@ -1058,3 +1169,18 @@ gc_ref<T> unbox_exact(gc_obj_ref<::System_Private_CorLib::System::Object> value)
     return gc_ref_from_ref(*box);
 }
 }
+
+namespace System_Private_CorLib
+{
+template <class T>
+void System::ByReference_1<T>::_ctor(::natsu::gc_ref<System::ByReference_1<T>> _this, ::natsu::gc_ref<::natsu::variable_type_t<T>> value)
+{
+    _this->_value = static_cast<intptr_t>(static_cast<uintptr_t>(value));
+}
+
+template <class T>
+::natsu::gc_ref<::natsu::variable_type_t<T>> System::ByReference_1<T>::get_Value(::natsu::gc_ref<System::ByReference_1<T>> _this)
+{
+    return ::natsu::gc_ref_from_ref(*reinterpret_cast<::natsu::variable_type_t<T> *>(static_cast<intptr_t>(_this->_value)));
+}
+}

+ 5 - 1
src/Native/natsu.typedef.h

@@ -105,7 +105,6 @@ struct object_header
         return dynamic_cast<const TVTable *>(vtable_);
     }
 };
-
 template <class T>
 constexpr bool is_value_type_v = T::TypeInfo::IsValueType;
 
@@ -243,6 +242,11 @@ struct gc_ptr
         return ptr_;
     }
 
+    T *get() const noexcept
+    {
+        return ptr_;
+    }
+
     T *operator->() const noexcept
     {
         return ptr_;

+ 1 - 1
src/Natsu.Compiler/EvaluationStack.cs

@@ -56,7 +56,7 @@ namespace Natsu.Compiler
             else
             {
                 var id = $"_v{_paramIndex++}";
-                _writer.Ident(Ident).WriteLine($"auto &&{id} = {entry.Expression};");
+                _writer.Ident(Ident).WriteLine($"auto {id} = {entry.Expression};");
                 _stackValues.Push(new StackEntry { Type = entry.Type, Expression = id });
             }
         }

+ 30 - 14
src/Natsu.Compiler/ILImporter.cs

@@ -60,12 +60,26 @@ namespace Natsu.Compiler
                         case Code.Brfalse_S:
                         case Code.Brtrue:
                         case Code.Brtrue_S:
-                        case Code.Bne_Un_S:
-                        case Code.Bge_Un_S:
-                        case Code.Bgt_Un_S:
-                        case Code.Bgt_S:
                         case Code.Blt_S:
+                        case Code.Blt:
                         case Code.Blt_Un_S:
+                        case Code.Blt_Un:
+                        case Code.Ble_S:
+                        case Code.Ble:
+                        case Code.Ble_Un:
+                        case Code.Ble_Un_S:
+                        case Code.Beq_S:
+                        case Code.Beq:
+                        case Code.Bge_S:
+                        case Code.Bge:
+                        case Code.Bge_Un_S:
+                        case Code.Bge_Un:
+                        case Code.Bgt_S:
+                        case Code.Bgt:
+                        case Code.Bgt_Un_S:
+                        case Code.Bgt_Un:
+                        case Code.Bne_Un_S:
+                        case Code.Bne_Un:
                             block.Instructions.Add(inst);
                             AddNext((Instruction)inst.Operand);
                             AddNext(NextInst(inst));
@@ -892,7 +906,7 @@ namespace Natsu.Compiler
             var v2 = Stack.Pop();
             var v1 = Stack.Pop();
             var nextOp = (Instruction)Op.Operand;
-            Writer.Ident(Ident).WriteLine($"if (::natsu::ops::{op}({v1.Expression}, {v2.Expression}))");
+            Writer.Ident(Ident).WriteLine($"if (::natsu::ops::{op}({v1.Expression}, {v2.Expression}).istrue())");
             Writer.Ident(Ident + 1).WriteLine($"goto {ILUtils.GetLabel(Method, nextOp, Block)};");
             Writer.Ident(Ident).WriteLine("else");
             Writer.Ident(Ident + 1).WriteLine($"goto {ILUtils.GetFallthroughLabel(Method, Op, Block)};");
@@ -902,7 +916,7 @@ namespace Natsu.Compiler
         {
             var v1 = Stack.Pop();
             var nextOp = (Instruction)Op.Operand;
-            Writer.Ident(Ident).WriteLine($"if ({op}{v1.Expression})");
+            Writer.Ident(Ident).WriteLine($"if ({op}{v1.Expression}.istrue())");
             Writer.Ident(Ident + 1).WriteLine($"goto {ILUtils.GetLabel(Method, nextOp, Block)};");
             Writer.Ident(Ident).WriteLine("else");
             Writer.Ident(Ident + 1).WriteLine($"goto {ILUtils.GetFallthroughLabel(Method, Op, Block)};");
@@ -930,7 +944,7 @@ namespace Natsu.Compiler
             var target = Stack.Pop();
             var field = (IField)Op.Operand;
             var thisType = TypeUtils.ThisType(field.DeclaringType);
-            string expr = $"::natsu::stack_to<{TypeUtils.EscapeVariableTypeName(thisType)}>({target.Expression})->" + TypeUtils.EscapeIdentifier(field.Name);
+            string expr = $"::natsu::ops::access<{TypeUtils.EscapeVariableTypeName(thisType)}>({target.Expression})->" + TypeUtils.EscapeIdentifier(field.Name);
             var fieldType = field.FieldSig.Type;
 
             Stack.Push(TypeUtils.GetStackType(fieldType), $"::natsu::stack_from({expr})");
@@ -989,7 +1003,7 @@ namespace Natsu.Compiler
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var addr = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"::natsu::initobj<{TypeUtils.EscapeTypeName(type)}>({addr.Expression});");
+            Writer.Ident(Ident).WriteLine($"::natsu::ops::initobj<{TypeUtils.EscapeVariableTypeName(type)}>({addr.Expression});");
         }
 
         public void Newobj()
@@ -1002,7 +1016,8 @@ namespace Natsu.Compiler
                 para.Add((method.Params[i], Stack.Pop()));
 
             para.Reverse();
-            var expr = $"::natsu::ops::newobj<{TypeUtils.EscapeTypeName(member.DeclaringType)}>({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src)))})";
+            var genSig = member.DeclaringType.TryGetGenericInstSig();
+            var expr = $"::natsu::ops::newobj<{TypeUtils.EscapeTypeName(member.DeclaringType)}>({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, genSig?.GenericArguments)))})";
             Stack.Push(StackType.O, expr);
         }
 
@@ -1010,15 +1025,15 @@ namespace Natsu.Compiler
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var addr = Stack.Pop();
-            Stack.Push(StackType.O, $"::natsu::ops::ldobj<{TypeUtils.EscapeTypeName(type)}>({addr.Expression})");
+            Stack.Push(StackType.O, $"::natsu::ops::ldobj<{TypeUtils.EscapeVariableTypeName(type)}>({addr.Expression})");
         }
 
         public void Stobj()
         {
             var type = (ITypeDefOrRef)Op.Operand;
-            var addr = Stack.Pop();
-            var obj = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"::natsu::ops::stobj<{TypeUtils.EscapeTypeName(type)}>({addr.Expression}, {obj.Expression});");
+            var src = Stack.Pop();
+            var dest = Stack.Pop();
+            Writer.Ident(Ident).WriteLine($"::natsu::ops::stobj<{TypeUtils.EscapeVariableTypeName(type)}>({src.Expression}, {dest.Expression});");
         }
 
         public void Ldtoken()
@@ -1098,8 +1113,9 @@ namespace Natsu.Compiler
 
         public void Box()
         {
+            var type = (ITypeDefOrRef)Op.Operand;
             var value = Stack.Pop();
-            Stack.Push(StackType.O, $"::natsu::ops::box({value.Expression})");
+            Stack.Push(StackType.O, $"::natsu::ops::box({CastExpression(type.ToTypeSig(), value)})");
         }
 
         public void Ldnull()

+ 3 - 3
src/Natsu.Compiler/Program.cs

@@ -78,7 +78,7 @@ namespace Natsu.Compiler
             var outputPath = Path.GetFullPath(@"..\..\..\..\Native\Generated");
             Directory.CreateDirectory(outputPath);
 
-            using (var writer = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.h")))
+            using (var writer = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.h"), false, Encoding.UTF8))
             {
                 writer.WriteLine("// Generated by natsu clr compiler.");
                 writer.WriteLine("#pragma once");
@@ -116,7 +116,7 @@ namespace Natsu.Compiler
                 writer.WriteLine("}");
             }
 
-            using (var writer = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.cpp")))
+            using (var writer = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.cpp"), false, Encoding.UTF8))
             {
                 writer.WriteLine("// Generated by natsu clr compiler.");
                 writer.WriteLine($"#include \"{_module.Assembly.Name}.h\"");
@@ -777,7 +777,7 @@ namespace Natsu.Compiler
 
         private string ArithmeticExpression((TypeSig type, string expression) v1, (TypeSig type, string expression) v2, string op)
         {
-            var e1 = v1.type.ElementType;uint i = 99; var s = i - 100;
+            var e1 = v1.type.ElementType; uint i = 99; var s = i - 100;
             var e2 = v2.type.ElementType;
             if (e1 == ElementType.U4 && e2 == ElementType.I4)
                 return $"::natsu::integral_cast<::System_Private_CorLib::System::Int32>({v1.expression}) {op} {v2.expression}";

+ 9 - 3
src/Natsu.Compiler/TypeUtils.cs

@@ -170,7 +170,13 @@ namespace Natsu.Compiler
                     sb.Append(">");
                     break;
                 case ElementType.Var:
-                    sb.Append(cntSig.ToGenericVar().GetName());
+                    {
+                        var var = cntSig.ToGenericVar();
+                        if (genArgs != null)
+                            EscapeTypeName(sb, genArgs[(int)var.Number]);
+                        else
+                            sb.Append(var.GetName());
+                    }
                     break;
                 case ElementType.MVar:
                     {
@@ -178,7 +184,7 @@ namespace Natsu.Compiler
                         if (genArgs != null)
                             EscapeTypeName(sb, genArgs[(int)mvar.Number]);
                         else
-                            sb.Append(cntSig.ToGenericMVar().GetName());
+                            sb.Append(mvar.GetName());
                     }
                     break;
                 case ElementType.GenericInst:
@@ -226,7 +232,7 @@ namespace Natsu.Compiler
             var sig = type.ToTypeSig();
             if (type.IsValueType || IsValueType(sig))
                 return EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs);
-            else if (type.IsGenericParam)
+            else if (type.ToTypeSig().IsGenericParameter)
                 return $"::natsu::variable_type_t<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs)}>";
             else
                 return $"::natsu::gc_obj_ref<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs)}>";

+ 3 - 0
src/System.Private.CorLib/Properties/AssemblyInfo.cs

@@ -0,0 +1,3 @@
+using System;
+
+[assembly: CLSCompliant(true)]

+ 412 - 0
src/System.Private.CorLib/System/BitConverter.cs

@@ -0,0 +1,412 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+    // The BitConverter class contains methods for
+    // converting an array of bytes to one of the base data 
+    // types, as well as for converting a base data type to an
+    // array of bytes.
+    public static class BitConverter
+    {
+        // This field indicates the "endianess" of the architecture.
+        // The value is set to true if the architecture is
+        // little endian; false if it is big endian.
+#if BIGENDIAN
+        public static readonly bool IsLittleEndian /* = false */;
+#else
+        public static readonly bool IsLittleEndian = true;
+#endif
+
+        // Converts a Boolean into an array of bytes with length one.
+        public static byte[] GetBytes(bool value)
+        {
+            byte[] r = new byte[1];
+            r[0] = (value ? (byte)1 : (byte)0);
+            return r;
+        }
+
+        // Converts a Boolean into a Span of bytes with length one.
+        public static bool TryWriteBytes(Span<byte> destination, bool value)
+        {
+            if (destination.Length < sizeof(byte))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value ? (byte)1 : (byte)0);
+            return true;
+        }
+
+        // Converts a char into an array of bytes with length two.
+        public static byte[] GetBytes(char value)
+        {
+            byte[] bytes = new byte[sizeof(char)];
+            Unsafe.As<byte, char>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a char into a Span
+        public static bool TryWriteBytes(Span<byte> destination, char value)
+        {
+            if (destination.Length < sizeof(char))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts a short into an array of bytes with length
+        // two.
+        public static byte[] GetBytes(short value)
+        {
+            byte[] bytes = new byte[sizeof(short)];
+            Unsafe.As<byte, short>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a short into a Span
+        public static bool TryWriteBytes(Span<byte> destination, short value)
+        {
+            if (destination.Length < sizeof(short))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts an int into an array of bytes with length 
+        // four.
+        public static byte[] GetBytes(int value)
+        {
+            byte[] bytes = new byte[sizeof(int)];
+            Unsafe.As<byte, int>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts an int into a Span
+        public static bool TryWriteBytes(Span<byte> destination, int value)
+        {
+            if (destination.Length < sizeof(int))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts a long into an array of bytes with length 
+        // eight.
+        public static byte[] GetBytes(long value)
+        {
+            byte[] bytes = new byte[sizeof(long)];
+            Unsafe.As<byte, long>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a long into a Span
+        public static bool TryWriteBytes(Span<byte> destination, long value)
+        {
+            if (destination.Length < sizeof(long))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts an ushort into an array of bytes with
+        // length two.
+        [CLSCompliant(false)]
+        public static byte[] GetBytes(ushort value)
+        {
+            byte[] bytes = new byte[sizeof(ushort)];
+            Unsafe.As<byte, ushort>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a ushort into a Span
+        [CLSCompliant(false)]
+        public static bool TryWriteBytes(Span<byte> destination, ushort value)
+        {
+            if (destination.Length < sizeof(ushort))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts an uint into an array of bytes with
+        // length four.
+        [CLSCompliant(false)]
+        public static byte[] GetBytes(uint value)
+        {
+            byte[] bytes = new byte[sizeof(uint)];
+            Unsafe.As<byte, uint>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a uint into a Span
+        [CLSCompliant(false)]
+        public static bool TryWriteBytes(Span<byte> destination, uint value)
+        {
+            if (destination.Length < sizeof(uint))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts an unsigned long into an array of bytes with
+        // length eight.
+        [CLSCompliant(false)]
+        public static byte[] GetBytes(ulong value)
+        {
+            byte[] bytes = new byte[sizeof(ulong)];
+            Unsafe.As<byte, ulong>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a ulong into a Span
+        [CLSCompliant(false)]
+        public static bool TryWriteBytes(Span<byte> destination, ulong value)
+        {
+            if (destination.Length < sizeof(ulong))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts a float into an array of bytes with length 
+        // four.
+        public static byte[] GetBytes(float value)
+        {
+            byte[] bytes = new byte[sizeof(float)];
+            Unsafe.As<byte, float>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a float into a Span
+        public static bool TryWriteBytes(Span<byte> destination, float value)
+        {
+            if (destination.Length < sizeof(float))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts a double into an array of bytes with length 
+        // eight.
+        public static byte[] GetBytes(double value)
+        {
+            byte[] bytes = new byte[sizeof(double)];
+            Unsafe.As<byte, double>(ref bytes[0]) = value;
+            return bytes;
+        }
+
+        // Converts a double into a Span
+        public static bool TryWriteBytes(Span<byte> destination, double value)
+        {
+            if (destination.Length < sizeof(double))
+                return false;
+
+            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value);
+            return true;
+        }
+
+        // Converts an array of bytes into a char.  
+        public static char ToChar(byte[] value, int startIndex) => unchecked((char)ToInt16(value, startIndex));
+
+        // Converts a Span into a char
+        public static char ToChar(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(char))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<char>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into a short.  
+        public static short ToInt16(byte[] value, int startIndex)
+        {
+            if (value == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+            if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
+            if (startIndex > value.Length - sizeof(short))
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
+
+            return Unsafe.ReadUnaligned<short>(ref value[startIndex]);
+        }
+
+        // Converts a Span into a short
+        public static short ToInt16(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(short))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<short>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into an int.  
+        public static int ToInt32(byte[] value, int startIndex)
+        {
+            if (value == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+            if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
+            if (startIndex > value.Length - sizeof(int))
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
+
+            return Unsafe.ReadUnaligned<int>(ref value[startIndex]);
+        }
+
+        // Converts a Span into an int
+        public static int ToInt32(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(int))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<int>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into a long.  
+        public static long ToInt64(byte[] value, int startIndex)
+        {
+            if (value == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+            if (unchecked((uint)startIndex) >= unchecked((uint)value.Length))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
+            if (startIndex > value.Length - sizeof(long))
+                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
+
+            return Unsafe.ReadUnaligned<long>(ref value[startIndex]);
+        }
+
+        // Converts a Span into a long
+        public static long ToInt64(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(long))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<long>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into an ushort.
+        // 
+        [CLSCompliant(false)]
+        public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ToInt16(value, startIndex));
+
+        // Converts a Span into a ushort
+        [CLSCompliant(false)]
+        public static ushort ToUInt16(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(ushort))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<ushort>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into an uint.
+        // 
+        [CLSCompliant(false)]
+        public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ToInt32(value, startIndex));
+
+        // Convert a Span into a uint
+        [CLSCompliant(false)]
+        public static uint ToUInt32(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(uint))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into an unsigned long.
+        // 
+        [CLSCompliant(false)]
+        public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ToInt64(value, startIndex));
+
+        // Converts a Span into an unsigned long
+        [CLSCompliant(false)]
+        public static ulong ToUInt64(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(ulong))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into a float.  
+        public static float ToSingle(byte[] value, int startIndex) => Int32BitsToSingle(ToInt32(value, startIndex));
+
+        // Converts a Span into a float
+        public static float ToSingle(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(float))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<float>(ref MemoryMarshal.GetReference(value));
+        }
+
+        // Converts an array of bytes into a double.  
+        public static double ToDouble(byte[] value, int startIndex) => Int64BitsToDouble(ToInt64(value, startIndex));
+
+        // Converts a Span into a double
+        public static double ToDouble(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(double))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<double>(ref MemoryMarshal.GetReference(value));
+        }
+
+        /*==================================ToBoolean===================================
+        **Action:  Convert an array of bytes to a boolean value.  We treat this array 
+        **         as if the first 4 bytes were an Int4 an operate on this value.
+        **Returns: True if the Int4 value of the first 4 bytes is non-zero.
+        **Arguments: value -- The byte array
+        **           startIndex -- The position within the array.
+        **Exceptions: See ToInt4.
+        ==============================================================================*/
+        // Converts an array of bytes into a boolean.  
+        public static bool ToBoolean(byte[] value, int startIndex)
+        {
+            if (value == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+            if (startIndex < 0)
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
+            if (startIndex > value.Length - 1)
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); // differs from other overloads, which throw base ArgumentException
+
+            return value[startIndex] != 0;
+        }
+
+        public static bool ToBoolean(ReadOnlySpan<byte> value)
+        {
+            if (value.Length < sizeof(byte))
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value);
+            return Unsafe.ReadUnaligned<byte>(ref MemoryMarshal.GetReference(value)) != 0;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe long DoubleToInt64Bits(double value)
+        {
+            return *((long*)&value);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe double Int64BitsToDouble(long value)
+        {
+            return *((double*)&value);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe int SingleToInt32Bits(float value)
+        {
+            return *((int*)&value);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe float Int32BitsToSingle(int value)
+        {
+            return *((float*)&value);
+        }
+    }
+}

+ 2 - 4
src/System.Private.CorLib/System/ByReference.cs

@@ -21,17 +21,15 @@ namespace System
 #pragma warning restore 169
 
         [Intrinsic]
+        [MethodImpl(MethodImplOptions.InternalCall)]
         public ByReference(ref T value)
         {
-            // Implemented as a JIT intrinsic - This default implementation is for
-            // completeness and to provide a concrete error if called via reflection
-            // or if intrinsic is missed.
             throw new PlatformNotSupportedException();
         }
 
         public ref T Value
         {
-            [Intrinsic]
+            [MethodImpl(MethodImplOptions.InternalCall)]
             get
             {
                 // Implemented as a JIT intrinsic - This default implementation is for

+ 30 - 0
src/System.Private.CorLib/System/Delegate.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace System
+{
+    public abstract class Delegate
+    {
+        // _target is the object we will invoke on
+        internal object _target;
+
+        // MethodBase, either cached after first request or assigned from a DynamicMethod
+        // For open delegates to collectible types, this may be a LoaderAllocator object
+        internal object _methodBase;
+
+        // _methodPtr is a pointer to the method we will invoke
+        // It could be a small thunk if this is a static or UM call
+        internal IntPtr _methodPtr;
+
+        // In the case of a static method passed to a delegate, this field stores
+        // whatever _methodPtr would have stored: and _methodPtr points to a
+        // small thunk which removes the "this" pointer before going on
+        // to _methodPtrAux.
+        internal IntPtr _methodPtrAux;
+
+        // Protect the default constructor so you can't build a delegate
+        private Delegate()
+        {
+        }
+    }
+}

+ 195 - 0
src/System.Private.CorLib/System/Double.cs

@@ -13,6 +13,8 @@
 ===========================================================*/
 
 using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
 
 namespace System
 {
@@ -35,5 +37,198 @@ namespace System
 
         // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
         internal const double NegativeZero = -0.0;
+
+        /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsFinite(double d)
+        {
+            var bits = BitConverter.DoubleToInt64Bits(d);
+            return (bits & 0x7FFFFFFFFFFFFFFF) < 0x7FF0000000000000;
+        }
+
+        /// <summary>Determines whether the specified value is infinite.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsInfinity(double d)
+        {
+            var bits = BitConverter.DoubleToInt64Bits(d);
+            return (bits & 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000;
+        }
+
+        /// <summary>Determines whether the specified value is NaN.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsNaN(double d)
+        {
+            var bits = BitConverter.DoubleToInt64Bits(d);
+            return (bits & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000;
+        }
+
+        /// <summary>Determines whether the specified value is negative.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsNegative(double d)
+        {
+            return BitConverter.DoubleToInt64Bits(d) < 0;
+        }
+
+        /// <summary>Determines whether the specified value is negative infinity.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool IsNegativeInfinity(double d)
+        {
+            return (d == double.NegativeInfinity);
+        }
+
+        /// <summary>Determines whether the specified value is normal.</summary>
+        [NonVersionable]
+        // This is probably not worth inlining, it has branches and should be rarely called
+        public static unsafe bool IsNormal(double d)
+        {
+            var bits = BitConverter.DoubleToInt64Bits(d);
+            bits &= 0x7FFFFFFFFFFFFFFF;
+            return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) != 0);
+        }
+
+        /// <summary>Determines whether the specified value is positive infinity.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool IsPositiveInfinity(double d)
+        {
+            return (d == double.PositiveInfinity);
+        }
+
+        /// <summary>Determines whether the specified value is subnormal.</summary>
+        [NonVersionable]
+        // This is probably not worth inlining, it has branches and should be rarely called
+        public static unsafe bool IsSubnormal(double d)
+        {
+            var bits = BitConverter.DoubleToInt64Bits(d);
+            bits &= 0x7FFFFFFFFFFFFFFF;
+            return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) == 0);
+        }
+
+        // Compares this object to another object, returning an instance of System.Relation.
+        // Null is considered less than any instance.
+        //
+        // If object is not of type Double, this method throws an ArgumentException.
+        //
+        // Returns a value less than zero if this  object
+        //
+        public int CompareTo(object value)
+        {
+            if (value == null)
+            {
+                return 1;
+            }
+            if (value is double)
+            {
+                double d = (double)value;
+                if (m_value < d) return -1;
+                if (m_value > d) return 1;
+                if (m_value == d) return 0;
+
+                // At least one of the values is NaN.
+                if (IsNaN(m_value))
+                    return (IsNaN(d) ? 0 : -1);
+                else
+                    return 1;
+            }
+            throw new ArgumentException(SR.Arg_MustBeDouble);
+        }
+
+        public int CompareTo(double value)
+        {
+            if (m_value < value) return -1;
+            if (m_value > value) return 1;
+            if (m_value == value) return 0;
+
+            // At least one of the values is NaN.
+            if (IsNaN(m_value))
+                return (IsNaN(value) ? 0 : -1);
+            else
+                return 1;
+        }
+
+        // True if obj is another Double with the same value as the current instance.  This is
+        // a method of object equality, that only returns true if obj is also a double.
+        public override bool Equals(object obj)
+        {
+            if (!(obj is double))
+            {
+                return false;
+            }
+            double temp = ((double)obj).m_value;
+            // This code below is written this way for performance reasons i.e the != and == check is intentional.
+            if (temp == m_value)
+            {
+                return true;
+            }
+            return IsNaN(temp) && IsNaN(m_value);
+        }
+
+        [NonVersionable]
+        public static bool operator ==(double left, double right)
+        {
+            return left == right;
+        }
+
+        [NonVersionable]
+        public static bool operator !=(double left, double right)
+        {
+            return left != right;
+        }
+
+        [NonVersionable]
+        public static bool operator <(double left, double right)
+        {
+            return left < right;
+        }
+
+        [NonVersionable]
+        public static bool operator >(double left, double right)
+        {
+            return left > right;
+        }
+
+        [NonVersionable]
+        public static bool operator <=(double left, double right)
+        {
+            return left <= right;
+        }
+
+        [NonVersionable]
+        public static bool operator >=(double left, double right)
+        {
+            return left >= right;
+        }
+
+        public bool Equals(double obj)
+        {
+            if (obj == m_value)
+            {
+                return true;
+            }
+            return IsNaN(obj) && IsNaN(m_value);
+        }
+
+        //The hashcode for a double is the absolute value of the integer representation
+        //of that double.
+        //
+        [MethodImpl(MethodImplOptions.AggressiveInlining)] // 64-bit constants make the IL unusually large that makes the inliner to reject the method
+        public override int GetHashCode()
+        {
+            var bits = Unsafe.As<double, long>(ref Unsafe.AsRef(in m_value));
+
+            // Optimized check for IsNan() || IsZero()
+            if (((bits - 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000)
+            {
+                // Ensure that all NaNs and both zeros have the same hash code
+                bits &= 0x7FF0000000000000;
+            }
+
+            return unchecked((int)bits) ^ ((int)(bits >> 32));
+        }
     }
 }

+ 97 - 0
src/System.Private.CorLib/System/Math.NatsuCLR.cs

@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+**
+**
+** Purpose: Some floating-point math operations
+**
+** 
+===========================================================*/
+
+//This class contains only static members and doesn't require serialization.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    public static partial class Math
+    {
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Abs(double value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern float Abs(float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Acos(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Acosh(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Asin(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Asinh(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Atan(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Atan2(double y, double x);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Atanh(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Cbrt(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Ceiling(double a);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Cos(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Cosh(double value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Exp(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Floor(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Log(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Log10(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Pow(double x, double y);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sin(double a);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sinh(double value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Sqrt(double d);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Tan(double a);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        public static extern double Tanh(double value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern double FMod(double x, double y);
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern unsafe double ModF(double x, double* intptr);
+    }
+}

+ 749 - 0
src/System.Private.CorLib/System/Math.cs

@@ -0,0 +1,749 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+**
+**
+** Purpose: Some floating-point math operations
+**
+** 
+===========================================================*/
+
+//This class contains only static members and doesn't require serialization.
+
+using System.Diagnostics;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+
+namespace System
+{
+    public static partial class Math
+    {
+        public const double E = 2.7182818284590452354;
+
+        public const double PI = 3.14159265358979323846;
+
+        private const int maxRoundingDigits = 15;
+
+        private const double doubleRoundLimit = 1e16d;
+
+        // This table is required for the Round function which can specify the number of digits to round to
+        private static double[] roundPower10Double = new double[] {
+          1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8,
+          1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15
+        };
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short Abs(short value)
+        {
+            if (value < 0)
+            {
+                value = (short)-value;
+                if (value < 0)
+                {
+                    ThrowAbsOverflow();
+                }
+            }
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Abs(int value)
+        {
+            if (value < 0)
+            {
+                value = -value;
+                if (value < 0)
+                {
+                    ThrowAbsOverflow();
+                }
+            }
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long Abs(long value)
+        {
+            if (value < 0)
+            {
+                value = -value;
+                if (value < 0)
+                {
+                    ThrowAbsOverflow();
+                }
+            }
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static sbyte Abs(sbyte value)
+        {
+            if (value < 0)
+            {
+                value = (sbyte)-value;
+                if (value < 0)
+                {
+                    ThrowAbsOverflow();
+                }
+            }
+            return value;
+        }
+
+        [StackTraceHidden]
+        private static void ThrowAbsOverflow()
+        {
+            throw new OverflowException(SR.Overflow_NegateTwosCompNum);
+        }
+
+        public static long BigMul(int a, int b)
+        {
+            return ((long)a) * b;
+        }
+
+        public static int DivRem(int a, int b, out int result)
+        {
+            // TODO https://github.com/dotnet/coreclr/issues/3439:
+            // Restore to using % and / when the JIT is able to eliminate one of the idivs.
+            // In the meantime, a * and - is measurably faster than an extra /.
+
+            int div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        public static long DivRem(long a, long b, out long result)
+        {
+            long div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        internal static uint DivRem(uint a, uint b, out uint result)
+        {
+            uint div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        internal static ulong DivRem(ulong a, ulong b, out ulong result)
+        {
+            ulong div = a / b;
+            result = a - (div * b);
+            return div;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static byte Clamp(byte value, byte min, byte max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Clamp(double value, double min, double max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static short Clamp(short value, short min, short max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Clamp(int value, int min, int max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+            
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static long Clamp(long value, long min, long max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static sbyte Clamp(sbyte value, sbyte min, sbyte max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static float Clamp(float value, float min, float max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ushort Clamp(ushort value, ushort min, ushort max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static uint Clamp(uint value, uint min, uint max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [CLSCompliant(false)]
+        public static ulong Clamp(ulong value, ulong min, ulong max)
+        {
+            if (min > max)
+            {
+                ThrowMinMaxException(min, max);
+            }
+
+            if (value < min)
+            {
+                return min;
+            }
+            else if (value > max)
+            {
+                return max;
+            }
+
+            return value;
+        }
+
+        public static double IEEERemainder(double x, double y)
+        {
+            if (double.IsNaN(x))
+            {
+                return x; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (double.IsNaN(y))
+            {
+                return y; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            var regularMod = x % y;
+
+            if (double.IsNaN(regularMod))
+            {
+                return double.NaN;
+            }
+
+            if ((regularMod == 0) && double.IsNegative(x))
+            {
+                return double.NegativeZero;
+            }
+
+            var alternativeResult = (regularMod - (Abs(y) * Sign(x)));
+
+            if (Abs(alternativeResult) == Abs(regularMod))
+            {
+                var divisionResult = x / y;
+                var roundedResult = Round(divisionResult);
+
+                if (Abs(roundedResult) > Abs(divisionResult))
+                {
+                    return alternativeResult;
+                }
+                else
+                {
+                    return regularMod;
+                }
+            }
+
+            if (Abs(alternativeResult) < Abs(regularMod))
+            {
+                return alternativeResult;
+            }
+            else
+            {
+                return regularMod;
+            }
+        }
+
+        public static double Log(double a, double newBase)
+        {
+            if (double.IsNaN(a))
+            {
+                return a; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (double.IsNaN(newBase))
+            {
+                return newBase; // IEEE 754-2008: NaN payload must be preserved
+            }
+
+            if (newBase == 1)
+            {
+                return double.NaN;
+            }
+
+            if ((a != 1) && ((newBase == 0) || double.IsPositiveInfinity(newBase)))
+            {
+                return double.NaN;
+            }
+
+            return (Log(a) / Log(newBase));
+        }
+
+        [NonVersionable]
+        public static byte Max(byte val1, byte val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        public static double Max(double val1, double val2)
+        {
+            if (val1 > val2)
+            {
+                return val1;
+            }
+
+            if (double.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [NonVersionable]
+        public static short Max(short val1, short val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static int Max(int val1, int val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static long Max(long val1, long val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static sbyte Max(sbyte val1, sbyte val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+        
+        public static float Max(float val1, float val2)
+        {
+            if (val1 > val2)
+            {
+                return val1;
+            }
+
+            if (float.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ushort Max(ushort val1, ushort val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static uint Max(uint val1, uint val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ulong Max(ulong val1, ulong val2)
+        {
+            return (val1 >= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static byte Min(byte val1, byte val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        public static double Min(double val1, double val2)
+        {
+            if (val1 < val2)
+            {
+                return val1;
+            }
+
+            if (double.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [NonVersionable]
+        public static short Min(short val1, short val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static int Min(int val1, int val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [NonVersionable]
+        public static long Min(long val1, long val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static sbyte Min(sbyte val1, sbyte val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        public static float Min(float val1, float val2)
+        {
+            if (val1 < val2)
+            {
+                return val1;
+            }
+
+            if (float.IsNaN(val1))
+            {
+                return val1;
+            }
+
+            return val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ushort Min(ushort val1, ushort val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static uint Min(uint val1, uint val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [CLSCompliant(false)]
+        [NonVersionable]
+        public static ulong Min(ulong val1, ulong val2)
+        {
+            return (val1 <= val2) ? val1 : val2;
+        }
+
+        [Intrinsic]
+        public static double Round(double a)
+        {
+            // ************************************************************************************
+            // IMPORTANT: Do not change this implementation without also updating Math.Round(double),
+            //            FloatingPointUtils::round(double), and FloatingPointUtils::round(float)
+            // ************************************************************************************
+
+            // If the number has no fractional part do nothing
+            // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
+
+            if (a == (double)((long)a))
+            {
+                return a;
+            }
+
+            // We had a number that was equally close to 2 integers.
+            // We need to return the even one.
+
+            double flrTempVal = Floor(a + 0.5);
+
+            if ((a == (Floor(a) + 0.5)) && (FMod(flrTempVal, 2.0) != 0))
+            {
+                flrTempVal -= 1.0;
+            }
+
+            return copysign(flrTempVal, a);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Round(double value, int digits)
+        {
+            return Round(value, digits, MidpointRounding.ToEven);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static double Round(double value, MidpointRounding mode)
+        {
+            return Round(value, 0, mode);
+        }
+
+        public static unsafe double Round(double value, int digits, MidpointRounding mode)
+        {
+            if ((digits < 0) || (digits > maxRoundingDigits))
+            {
+                throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits);
+            }
+
+            if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero)
+            {
+                throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
+            }
+
+            if (Abs(value) < doubleRoundLimit)
+            {
+                var power10 = roundPower10Double[digits];
+
+                value *= power10;
+
+                if (mode == MidpointRounding.AwayFromZero)
+                {
+                    var fraction = ModF(value, &value);
+
+                    if (Abs(fraction) >= 0.5)
+                    {
+                        value += Sign(fraction);
+                    }
+                }
+                else
+                {
+                    value = Round(value);
+                }
+
+                value /= power10;
+            }
+
+            return value;
+        }
+
+        public static int Sign(double value)
+        {
+            if (value < 0)
+            {
+                return -1;
+            }
+            else if (value > 0)
+            {
+                return 1;
+            }
+            else if (value == 0)
+            {
+                return 0;
+            }
+
+            throw new ArithmeticException(SR.Arithmetic_NaN);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(short value)
+        {
+            return Sign((int)value);
+        }
+
+        public static int Sign(int value)
+        {
+            return unchecked(value >> 31 | (int)((uint)-value >> 31));
+        }
+
+        public static int Sign(long value)
+        {
+            return unchecked((int)(value >> 63 | (long)((ulong)-value >> 63)));
+        }
+
+        [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int Sign(sbyte value)
+        {
+            return Sign((int)value);
+        }
+
+        public static int Sign(float value)
+        {
+            if (value < 0)
+            {
+                return -1;
+            }
+            else if (value > 0)
+            {
+                return 1;
+            }
+            else if (value == 0)
+            {
+                return 0;
+            }
+
+            throw new ArithmeticException(SR.Arithmetic_NaN);
+        }
+
+        public static unsafe double Truncate(double d)
+        {
+            ModF(d, &d);
+            return d;
+        }
+
+        private static unsafe double copysign(double x, double y)
+        {
+            var xbits = BitConverter.DoubleToInt64Bits(x);
+            var ybits = BitConverter.DoubleToInt64Bits(y);
+
+            // If the sign bits of x and y are not the same,
+            // flip the sign bit of x and return the new value;
+            // otherwise, just return x
+
+            if (((xbits ^ ybits) >> 63) != 0)
+            {
+                return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue);
+            }
+
+            return x;
+        }
+
+        private static void ThrowMinMaxException<T>(T min, T max)
+        {
+            throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max));
+        }
+    }
+}

+ 12 - 0
src/System.Private.CorLib/System/MidpointRounding.cs

@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System
+{
+    public enum MidpointRounding
+    {
+        ToEven = 0,
+        AwayFromZero = 1,
+    }
+}

+ 1 - 1
src/System.Private.CorLib/System/RuntimeHandles.cs

@@ -12,6 +12,6 @@ namespace System
 {
     public unsafe struct RuntimeTypeHandle
     {
-
+        internal RuntimeType _runtimeType;
     }
 }

+ 9 - 0
src/System.Private.CorLib/System/RuntimeType.cs

@@ -0,0 +1,9 @@
+using System;
+using System.Collections.Generic;
+
+namespace System
+{
+    internal class RuntimeType : Type
+    {
+    }
+}

+ 191 - 0
src/System.Private.CorLib/System/Single.cs

@@ -12,6 +12,8 @@
 ===========================================================*/
 
 using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
 
 namespace System
 {
@@ -31,5 +33,194 @@ namespace System
 
         // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
         internal const float NegativeZero = (float)-0.0;
+
+
+        /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool IsFinite(float f)
+        {
+            var bits = BitConverter.SingleToInt32Bits(f);
+            return (bits & 0x7FFFFFFF) < 0x7F800000;
+        }
+
+        /// <summary>Determines whether the specified value is infinite.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsInfinity(float f)
+        {
+            var bits = BitConverter.SingleToInt32Bits(f);
+            return (bits & 0x7FFFFFFF) == 0x7F800000;
+        }
+
+        /// <summary>Determines whether the specified value is NaN.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsNaN(float f)
+        {
+            var bits = BitConverter.SingleToInt32Bits(f);
+            return (bits & 0x7FFFFFFF) > 0x7F800000;
+        }
+
+        /// <summary>Determines whether the specified value is negative.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsNegative(float f)
+        {
+            return BitConverter.SingleToInt32Bits(f) < 0;
+        }
+
+        /// <summary>Determines whether the specified value is negative infinity.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsNegativeInfinity(float f)
+        {
+            return (f == float.NegativeInfinity);
+        }
+
+        /// <summary>Determines whether the specified value is normal.</summary>
+        [NonVersionable]
+        // This is probably not worth inlining, it has branches and should be rarely called
+        public static unsafe bool IsNormal(float f)
+        {
+            var bits = BitConverter.SingleToInt32Bits(f);
+            bits &= 0x7FFFFFFF;
+            return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) != 0);
+        }
+
+        /// <summary>Determines whether the specified value is positive infinity.</summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static unsafe bool IsPositiveInfinity(float f)
+        {
+            return (f == float.PositiveInfinity);
+        }
+
+        /// <summary>Determines whether the specified value is subnormal.</summary>
+        [NonVersionable]
+        // This is probably not worth inlining, it has branches and should be rarely called
+        public static unsafe bool IsSubnormal(float f)
+        {
+            var bits = BitConverter.SingleToInt32Bits(f);
+            bits &= 0x7FFFFFFF;
+            return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) == 0);
+        }
+
+        // Compares this object to another object, returning an integer that
+        // indicates the relationship.
+        // Returns a value less than zero if this  object
+        // null is considered to be less than any instance.
+        // If object is not of type Single, this method throws an ArgumentException.
+        //
+        public int CompareTo(object value)
+        {
+            if (value == null)
+            {
+                return 1;
+            }
+            if (value is float)
+            {
+                float f = (float)value;
+                if (m_value < f) return -1;
+                if (m_value > f) return 1;
+                if (m_value == f) return 0;
+
+                // At least one of the values is NaN.
+                if (IsNaN(m_value))
+                    return (IsNaN(f) ? 0 : -1);
+                else // f is NaN.
+                    return 1;
+            }
+            throw new ArgumentException(SR.Arg_MustBeSingle);
+        }
+
+
+        public int CompareTo(float value)
+        {
+            if (m_value < value) return -1;
+            if (m_value > value) return 1;
+            if (m_value == value) return 0;
+
+            // At least one of the values is NaN.
+            if (IsNaN(m_value))
+                return (IsNaN(value) ? 0 : -1);
+            else // f is NaN.
+                return 1;
+        }
+
+        [NonVersionable]
+        public static bool operator ==(float left, float right)
+        {
+            return left == right;
+        }
+
+        [NonVersionable]
+        public static bool operator !=(float left, float right)
+        {
+            return left != right;
+        }
+
+        [NonVersionable]
+        public static bool operator <(float left, float right)
+        {
+            return left < right;
+        }
+
+        [NonVersionable]
+        public static bool operator >(float left, float right)
+        {
+            return left > right;
+        }
+
+        [NonVersionable]
+        public static bool operator <=(float left, float right)
+        {
+            return left <= right;
+        }
+
+        [NonVersionable]
+        public static bool operator >=(float left, float right)
+        {
+            return left >= right;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is float))
+            {
+                return false;
+            }
+            float temp = ((float)obj).m_value;
+            if (temp == m_value)
+            {
+                return true;
+            }
+
+            return IsNaN(temp) && IsNaN(m_value);
+        }
+
+        public bool Equals(float obj)
+        {
+            if (obj == m_value)
+            {
+                return true;
+            }
+
+            return IsNaN(obj) && IsNaN(m_value);
+        }
+
+        public override int GetHashCode()
+        {
+            var bits = Unsafe.As<float, int>(ref Unsafe.AsRef(in m_value));
+
+            // Optimized check for IsNan() || IsZero()
+            if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
+            {
+                // Ensure that all NaNs and both zeros have the same hash code
+                bits &= 0x7F800000;
+            }
+
+            return bits;
+        }
     }
 }

+ 239 - 3
src/System.Private.CorLib/System/String.cs

@@ -1,5 +1,7 @@
 using System;
+using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Versioning;
 
 namespace System
@@ -49,16 +51,241 @@ namespace System
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern string FastAllocateString(int length);
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
+        // String constructors
+        // These are special. The implementation methods for these have a different signature from the
+        // declared constructors.
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(char[] value);
+
+        private static string Ctor(char[] value)
+        {
+            if (value == null || value.Length == 0)
+                return Empty;
+
+            string result = FastAllocateString(value.Length);
+            unsafe
+            {
+                fixed (char* dest = &result._firstChar, source = value)
+                    wstrcpy(dest, source, value.Length);
+            }
+            return result;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(char[] value, int startIndex, int length);
+
+        private static string Ctor(char[] value, int startIndex, int length)
+        {
+            if (value == null)
+                throw new ArgumentNullException(nameof(value));
+
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+            if (length < 0)
+                throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+
+            if (startIndex > value.Length - length)
+                throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
+
+            if (length == 0)
+                return Empty;
+
+            string result = FastAllocateString(length);
+            unsafe
+            {
+                fixed (char* dest = &result._firstChar, source = value)
+                    wstrcpy(dest, source + startIndex, length);
+            }
+            return result;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern unsafe String(char* value);
+
+        private unsafe string Ctor(char* ptr)
+        {
+            if (ptr == null)
+                return Empty;
+
+            int count = wcslen(ptr);
+            if (count == 0)
+                return Empty;
+
+            string result = FastAllocateString(count);
+            fixed (char* dest = &result._firstChar)
+                wstrcpy(dest, ptr, count);
+            return result;
+        }
+
+        [CLSCompliant(false)]
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern unsafe String(char* value, int startIndex, int length);
+
+        private static unsafe string Ctor(char* ptr, int startIndex, int length)
+        {
+            if (length < 0)
+                throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+            char* pStart = ptr + startIndex;
+
+            // overflow check
+            if (pStart < ptr)
+                throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_PartialWCHAR);
+
+            if (length == 0)
+                return Empty;
+
+            if (ptr == null)
+                throw new ArgumentOutOfRangeException(nameof(ptr), SR.ArgumentOutOfRange_PartialWCHAR);
+
+            string result = FastAllocateString(length);
+            fixed (char* dest = &result._firstChar)
+                wstrcpy(dest, pStart, length);
+            return result;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
         public extern String(char c, int count);
 
+        private static string Ctor(char c, int count)
+        {
+            if (count <= 0)
+            {
+                if (count == 0)
+                    return Empty;
+                throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+            }
 
-        // Returns this string.
-        public override string ToString()
+            string result = FastAllocateString(count);
+
+            if (c != '\0') // Fast path null char string
+            {
+                unsafe
+                {
+                    fixed (char* dest = &result._firstChar)
+                    {
+                        uint cc = (uint)((c << 16) | c);
+                        uint* dmem = (uint*)dest;
+                        if (count >= 4)
+                        {
+                            count -= 4;
+                            do
+                            {
+                                dmem[0] = cc;
+                                dmem[1] = cc;
+                                dmem += 2;
+                                count -= 4;
+                            } while (count >= 0);
+                        }
+                        if ((count & 2) != 0)
+                        {
+                            *dmem = cc;
+                            dmem++;
+                        }
+                        if ((count & 1) != 0)
+                            ((char*)dmem)[0] = c;
+                    }
+                }
+            }
+            return result;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(ReadOnlySpan<char> value);
+
+        private static unsafe string Ctor(ReadOnlySpan<char> value)
+        {
+            if (value.Length == 0)
+                return Empty;
+
+            string result = FastAllocateString(value.Length);
+            fixed (char* dest = &result._firstChar, src = &MemoryMarshal.GetReference(value))
+                wstrcpy(dest, src, value.Length);
+            return result;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static implicit operator ReadOnlySpan<char>(string value) =>
+            value != null ? new ReadOnlySpan<char>(ref value.GetRawStringData(), value.Length) : default;
+
+        public object Clone()
         {
             return this;
         }
 
+        public static unsafe string Copy(string str)
+        {
+            if (str == null)
+                throw new ArgumentNullException(nameof(str));
+
+            string result = FastAllocateString(str.Length);
+            fixed (char* dest = &result._firstChar, src = &str._firstChar)
+                wstrcpy(dest, src, str.Length);
+            return result;
+        }
+
+
+        // Converts a substring of this string to an array of characters.  Copies the
+        // characters of this string beginning at position sourceIndex and ending at
+        // sourceIndex + count - 1 to the character array buffer, beginning
+        // at destinationIndex.
+        //
+        public unsafe void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
+        {
+            if (destination == null)
+                throw new ArgumentNullException(nameof(destination));
+            if (count < 0)
+                throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+            if (sourceIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_Index);
+            if (count > Length - sourceIndex)
+                throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_IndexCount);
+            if (destinationIndex > destination.Length - count || destinationIndex < 0)
+                throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_IndexCount);
+
+            fixed (char* src = &_firstChar, dest = destination)
+                wstrcpy(dest + destinationIndex, src + sourceIndex, count);
+        }
+
+        // Returns the entire string as an array of characters.
+        public unsafe char[] ToCharArray()
+        {
+            if (Length == 0)
+                return Array.Empty<char>();
+
+            char[] chars = new char[Length];
+            fixed (char* src = &_firstChar, dest = &chars[0])
+                wstrcpy(dest, src, Length);
+            return chars;
+        }
+
+        // Returns a substring of this string as an array of characters.
+        //
+        public unsafe char[] ToCharArray(int startIndex, int length)
+        {
+            // Range check everything.
+            if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
+                throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
+
+            if (length <= 0)
+            {
+                if (length == 0)
+                    return Array.Empty<char>();
+                throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_Index);
+            }
+
+            char[] chars = new char[length];
+            fixed (char* src = &_firstChar, dest = &chars[0])
+                wstrcpy(dest, src + startIndex, length);
+            return chars;
+        }
+
         [NonVersionable]
         public static bool IsNullOrEmpty(string value)
         {
@@ -71,6 +298,15 @@ namespace System
             return (value == null || 0u >= (uint)value.Length) ? true : false;
         }
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static unsafe extern int wcslen(char* ptr);
+
+        // Returns this string.
+        public override string ToString()
+        {
+            return this;
+        }
+
         internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
         {
             Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2);