فهرست منبع

Refactor codegen

Guo Hui 6 سال پیش
والد
کامیت
8ace9857fb

+ 1 - 1
CMakeLists.txt

@@ -22,7 +22,7 @@ set(CMAKE_CXX_STANDARD 17)
 
 if (MSVC)
     add_definitions(/D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /DNOMINMAX /DUNICODE)
-    add_compile_options(/wd4102)
+    add_compile_options(/wd4102 /wd4200)
     set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
     set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
 else()

+ 2 - 2
src/Native/arch/emulator/schedule.cpp

@@ -105,12 +105,12 @@ void interrupt_sender_main(void *arg)
                 if (g_system_timer_int.exchange(false))
                 {
                     IRQDispatcher::DispatchSystemIRQ(KernelServices::_s_get_IRQDispatcher(),
-                        SystemIRQ::from(SystemIRQ::SystemTick), context);
+                        SystemIRQ::value_of(SystemIRQ::SystemTick), context);
                 }
                 else if (g_core_notifi_int.exchange(false))
                 {
                     IRQDispatcher::DispatchSystemIRQ(KernelServices::_s_get_IRQDispatcher(),
-                        SystemIRQ::from(SystemIRQ::CoreNotification), context);
+                        SystemIRQ::value_of(SystemIRQ::CoreNotification), context);
                 }
             }
         }

+ 0 - 4
src/Native/main.cpp

@@ -10,10 +10,6 @@ void InitializeHeap() noexcept;
 
 int main()
 {
-    int32_t followCount = 0, resultCount = 0;
-#line 536 "D:\\Work\\Repository\\corert.git\\src\\System.Private.CoreLib\\src\\System\\Delegate.cs"
-    int32_t _35 = followCount; int32_t _36 = 1 + 1; resultCount = (int32_t)_36;
-
     InitializeHeap();
     Program::_s_Main();
 

+ 6 - 6
src/Native/natsu.fcall.cpp

@@ -63,7 +63,7 @@ gc_ref<uint8_t> Array::_s_GetRawArrayGeometry(gc_obj_ref<Array> array, gc_ref<ui
 
 void Buffer::_s_Memcpy(gc_ptr<uint8_t> dest, gc_ptr<uint8_t> src, int32_t len)
 {
-    std::memcpy(dest, src, len);
+    std::memcpy(dest.get(), src.get(), len);
 }
 
 void Debug::_s_WriteCore(gc_obj_ref<String> message)
@@ -87,13 +87,13 @@ void Debug::_s_FailCore(gc_obj_ref<String> message, gc_obj_ref<String> detailMes
 
 void Buffer::_s_Memmove(gc_ptr<uint8_t> dest, gc_ptr<uint8_t> src, uint64_t len)
 {
-    std::memmove(dest, src, len);
+    std::memmove(dest.get(), src.get(), len);
 }
 
 gc_obj_ref<Type> Object::GetType(::natsu::gc_obj_ref<Object> _this)
 {
     check_null_obj_ref(_this);
-    return ::natsu::null;
+    pure_call();
 }
 
 char16_t String::get_Chars(gc_obj_ref<String> _this, int32_t index)
@@ -119,7 +119,7 @@ gc_obj_ref<String> String::_s_FastAllocateString(int32_t length)
 
 int32_t String::_s_wcslen(gc_ptr<char16_t> ptr)
 {
-    std::u16string_view sv(ptr);
+    std::u16string_view sv(ptr.get());
     return (int32_t)sv.length();
 }
 
@@ -245,7 +245,7 @@ double Math::_s_FMod(double x, double y)
 
 double Math::_s_ModF(double x, gc_ptr<double> y)
 {
-    return modf(x, y);
+    return fmod(x, *y);
 }
 
 gc_obj_ref<MulticastDelegate> MulticastDelegate::_s_CreateDelegateLike(gc_obj_ref<MulticastDelegate> delegate, gc_obj_ref<SZArray_1<Delegate>> invocationList)
@@ -253,7 +253,7 @@ gc_obj_ref<MulticastDelegate> MulticastDelegate::_s_CreateDelegateLike(gc_obj_re
     auto d_len = invocationList->length();
     if (d_len == 0)
     {
-        return null;
+        return nullptr;
     }
     else if (d_len == 1)
     {

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

@@ -51,12 +51,6 @@ void natsu::pure_call()
     throw std::runtime_error("pure call");
 }
 
-native_int ops::ldlen(const O &obj)
-{
-    check_null_obj_ref(obj);
-    return (intptr_t)stack_to<gc_obj_ref<RawSzArrayData>>(obj)->Count;
-}
-
 void ops::throw_(gc_obj_ref<Exception> obj)
 {
     check_null_obj_ref(obj);

+ 186 - 353
src/Native/natsu.runtime.h

@@ -13,6 +13,8 @@
 
 using namespace std::string_view_literals;
 
+#define natsu_alloca(size) reinterpret_cast<uintptr_t>(alloca(size))
+
 namespace natsu
 {
 namespace stack
@@ -123,9 +125,9 @@ template <class T>
 gc_obj_ref<::System_Private_CoreLib::System::SZArray_1<T>> gc_new_array(int32_t length)
 {
     using obj_t = ::System_Private_CoreLib::System::SZArray_1<T>;
-    auto size = sizeof(obj_t) + (size_t)length.value_ * sizeof(T);
+    auto size = sizeof(obj_t) + (size_t)length * sizeof(T);
     auto obj = gc_new<obj_t>(size);
-    obj->Length = length.value_;
+    obj->Length = length;
     return obj;
 }
 
@@ -183,24 +185,6 @@ void check_condition(TCond &&condition, TArgs &&... args)
         throw make_exception(make_object<T>(std::forward<TArgs>(args)...));
 }
 
-inline void check_null_obj_ref(stack::O obj)
-{
-    if (!obj)
-        throw_null_ref_exception();
-}
-
-inline void check_null_obj_ref(stack::native_int addr)
-{
-    if (!addr)
-        throw_null_ref_exception();
-}
-
-inline void check_null_obj_ref(stack::Ref addr)
-{
-    if (!addr)
-        throw_null_ref_exception();
-}
-
 template <class T>
 struct runtime_type_holder
 {
@@ -255,283 +239,134 @@ namespace stack
     namespace details
     {
         template <class T>
-        struct stack_from_impl;
-
-        template <class T>
-        struct stack_from_impl<gc_obj_ref<T>>
-        {
-            O operator()(const gc_obj_ref<T> &value) const noexcept
-            {
-                return { static_cast<uintptr_t>(value) };
-            }
-        };
-
-        template <class T>
-        struct stack_from_impl<gc_ref<T>>
-        {
-            Ref operator()(const gc_ref<T> &value) const noexcept
-            {
-                return { static_cast<uintptr_t>(value) };
-            }
-        };
-
-        template <class T>
-        struct stack_from_impl<gc_ptr<T>>
+        struct box_impl
         {
-            native_int operator()(const gc_ptr<T> &value) const noexcept
+            gc_obj_ref<> operator()(T value)
             {
-                return static_cast<intptr_t>(static_cast<uintptr_t>(value));
+                auto box = gc_new<T>();
+                *box = value;
+                return box;
             }
         };
 
         template <class T>
-        struct stack_from_impl<clr_volatile<T>>
-        {
-            auto operator()(const clr_volatile<T> &value) const noexcept
-            {
-                return stack_from(value.load());
-            }
-        };
-
-        template <>
-        struct stack_from_impl<::System_Private_CoreLib::System::IntPtr>
-        {
-            native_int operator()(const ::System_Private_CoreLib::System::IntPtr &value) const noexcept
-            {
-                return (intptr_t) static_cast<uintptr_t>(value._value);
-            }
-        };
-
-        template <>
-        struct stack_from_impl<::System_Private_CoreLib::System::UIntPtr>
+        struct box_impl<gc_obj_ref<T>>
         {
-            native_int operator()(const ::System_Private_CoreLib::System::UIntPtr &value) const noexcept
+            gc_obj_ref<T> operator()(const gc_obj_ref<T> &value) const noexcept
             {
-                return (intptr_t) static_cast<uintptr_t>(value._value);
+                return 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)); \
-        }                                                      \
-    };
-
-        DEFINE_STACK_FROM_CAST(bool, int32, uint32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(int8_t, int32, int32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(uint8_t, int32, uint32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(char16_t, int32, uint32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(int16_t, int32, int32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(uint16_t, int32, uint32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(int32_t, int32, int32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(uint32_t, int32, uint32_t, int32_t);
-        DEFINE_STACK_FROM_CAST(int64_t, int64, int64_t, int64_t);
-        DEFINE_STACK_FROM_CAST(uint64_t, int64, uint64_t, int64_t);
-        DEFINE_STACK_FROM_CAST(float, F, float, double);
-        DEFINE_STACK_FROM_CAST(double, F, double, double);
-
-#undef DEFINE_STACK_FROM_CAST
-
         template <class T>
-        struct stack_from_impl
+        struct box_impl<::System_Private_CoreLib::System::Nullable_1<T>>
         {
-            auto operator()(T value)
+            gc_obj_ref<> operator()(const ::System_Private_CoreLib::System::Nullable_1<T> &value) const noexcept
             {
-                if constexpr (natsu::is_enum_v<T>)
-                    return stack_from_impl<decltype(value.value__)>()(value.value__);
+                if (value.hasValue)
+                {
+                    auto box = gc_new<T>();
+                    box->value__ = value;
+                    return box;
+                }
                 else
-                    return value;
+                {
+                    return natsu::null;
+                }
             }
         };
 
         template <class TFrom, class TTo>
-        struct stack_to_impl
+        struct cast_impl
         {
-            TTo operator()(TFrom value)
+            TTo operator()(TFrom &&value) const noexcept
             {
-                if constexpr (natsu::is_enum_v<TTo>)
-                    return TTo { static_cast<decltype(TTo::value__)>(value.value_) };
+                if constexpr (is_enum_v<TTo>)
+                {
+                    TTo e;
+                    e.value__ = static_cast<decltype(e.value__)>(value);
+                    return e;
+                }
                 else
+                {
                     return value;
+                }
             }
         };
 
-        template <class TTo>
-        struct stack_to_impl<O, gc_obj_ref<TTo>>
-        {
-            constexpr gc_obj_ref<TTo> operator()(const O &value) const noexcept
-            {
-                return gc_obj_ref<TTo>(reinterpret_cast<TTo *>(value.value_));
-            }
-        };
-
-        template <class TTo>
-        struct stack_to_impl<Ref, TTo>
-        {
-            gc_ref<TTo> operator()(const Ref &value) const noexcept
-            {
-                return gc_ref<TTo>(*reinterpret_cast<TTo *>(value.value_));
-            }
-        };
-
-        template <class TTo>
-        struct stack_to_impl<Ref, gc_ref<TTo>>
-        {
-            gc_ref<TTo> operator()(const Ref &value) const noexcept
-            {
-                return gc_ref<TTo>(*reinterpret_cast<TTo *>(value.value_));
-            }
-        };
-
-        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_));
-            }
-        };
-
+        // ECMA-335 III.4.6
         template <class TFrom, class TTo>
-        struct stack_to_impl<TFrom, clr_volatile<TTo>>
+        struct isinst_impl
         {
-            TTo operator()(const TFrom &value) const noexcept
+            gc_obj_ref<TTo> operator()(const gc_obj_ref<TFrom> &obj) const noexcept
             {
-                return stack_to_impl<TFrom, TTo>()(value);
+                return obj.template as<TTo>();
             }
         };
 
-#define DEFINE_STACK_TO_CAST(From, To, Med)             \
-    template <>                                         \
-    struct stack_to_impl<From, To>                      \
-    {                                                   \
-        To operator()(const From &value) const noexcept \
-        {                                               \
-            return static_cast<Med>(value.value_);      \
-        }                                               \
-    };
-        DEFINE_STACK_TO_CAST(int32, bool, bool);
-        DEFINE_STACK_TO_CAST(int32, int8_t, int8_t);
-        DEFINE_STACK_TO_CAST(int32, uint8_t, uint8_t);
-        DEFINE_STACK_TO_CAST(int32, char16_t, char16_t);
-        DEFINE_STACK_TO_CAST(int32, int16_t, int16_t);
-        DEFINE_STACK_TO_CAST(int32, uint16_t, uint16_t);
-        DEFINE_STACK_TO_CAST(int32, int32_t, int32_t);
-        DEFINE_STACK_TO_CAST(int32, uint32_t, uint32_t);
-        DEFINE_STACK_TO_CAST(int32, ::System_Private_CoreLib::System::IntPtr, intptr_t);
-        DEFINE_STACK_TO_CAST(int32, ::System_Private_CoreLib::System::UIntPtr, uintptr_t);
-
-        DEFINE_STACK_TO_CAST(native_int, bool, bool);
-        DEFINE_STACK_TO_CAST(native_int, int8_t, int8_t);
-        DEFINE_STACK_TO_CAST(native_int, uint8_t, uint8_t);
-        DEFINE_STACK_TO_CAST(native_int, char16_t, char16_t);
-        DEFINE_STACK_TO_CAST(native_int, int16_t, int16_t);
-        DEFINE_STACK_TO_CAST(native_int, uint16_t, uint16_t);
-        DEFINE_STACK_TO_CAST(native_int, int32_t, int32_t);
-        DEFINE_STACK_TO_CAST(native_int, uint32_t, uint32_t);
-        DEFINE_STACK_TO_CAST(native_int, ::System_Private_CoreLib::System::IntPtr, intptr_t);
-        DEFINE_STACK_TO_CAST(native_int, ::System_Private_CoreLib::System::UIntPtr, uintptr_t);
-
-        DEFINE_STACK_TO_CAST(int64, int64_t, int64_t);
-        DEFINE_STACK_TO_CAST(int64, uint64_t, uint64_t);
-
-        DEFINE_STACK_TO_CAST(F, float, float);
-        DEFINE_STACK_TO_CAST(F, double, double);
-
-#undef DEFINE_STACK_TO_CAST
-
-        template <class T>
-        struct box_impl
+        // ECMA-335 III.4.6
+        template <class TFrom, class TTo>
+        struct isinst_impl<TFrom, ::System_Private_CoreLib::System::Nullable_1<TTo>>
         {
-            auto operator()(T value)
+            gc_obj_ref<TTo> operator()(const gc_obj_ref<TFrom> &obj) const noexcept
             {
-                auto box = gc_new<T>();
-                *box = value;
-                return box;
+                return isinst_impl<TFrom, TTo>()(obj);
             }
         };
 
-        template <class T>
-        struct box_impl<gc_obj_ref<T>>
+        // ECMA-335 III.4.3
+        template <class TFrom, class TTo>
+        struct castclass_impl
         {
-            gc_obj_ref<T> operator()(const gc_obj_ref<T> &value) const noexcept
+            gc_obj_ref<TTo> operator()(const gc_obj_ref<TFrom> &obj) const
             {
-                return value;
+                if (!obj)
+                    return nullptr;
+                if (auto new_obj = obj.template as<TTo>())
+                    return new_obj;
+                throw_invalid_cast_exception();
             }
         };
 
-        template <class T>
-        struct box_impl<::System_Private_CoreLib::System::Nullable_1<T>>
+        // ECMA-335 III.4.3
+        // If typeTok is a nullable type, Nullable<T>, it is interpreted as ¡°boxed¡± T.
+        template <class TFrom, class TTo>
+        struct castclass_impl<TFrom, ::System_Private_CoreLib::System::Nullable_1<TTo>>
         {
-            auto operator()(const ::System_Private_CoreLib::System::Nullable_1<T> &value) const noexcept
+            gc_obj_ref<TTo> operator()(const gc_obj_ref<TFrom> &obj) const
             {
-                if (value.hasValue)
-                {
-                    auto box = gc_new<T>();
-                    box->value__ = value;
-                    return box;
-                }
-                else
-                {
-                    return natsu::null;
-                }
+                return castclass_impl<TFrom, TTo>()(obj);
             }
         };
 
-        template <class T>
+        // ECMA-335 III.4.32
+        template <class TFrom, class TTo>
         struct unbox_impl
         {
-            Ref operator()(const O &obj)
+            gc_ref<TTo> operator()(const gc_obj_ref<TFrom> &obj) const
             {
-                using ::System_Private_CoreLib::System::Object;
-
-                // check_null_obj_ref(obj);
-                auto box = stack_to<gc_obj_ref<Object>>(obj).template as<T>();
-                if (box)
-                    return stack_from(gc_ref_from_ref(*box));
+                check_null_obj_ref(obj);
+                if (auto box = obj.template as<TTo>())
+                    return *box;
                 else
                     throw_invalid_cast_exception();
             }
         };
 
-        template <class T>
-        struct unbox_impl<::System_Private_CoreLib::System::Nullable_1<T>>
+        // ECMA-335 III.4.32
+        template <class TFrom, class TTo>
+        struct unbox_impl<TFrom, ::System_Private_CoreLib::System::Nullable_1<TTo>>
         {
-            Ref operator()(const O &obj)
-            {
-                using ::System_Private_CoreLib::System::Nullable_1;
-                using ::System_Private_CoreLib::System::Object;
+            using nullable_t = ::System_Private_CoreLib::System::Nullable_1<TTo>;
 
+            gc_ref<nullable_t> operator()(const gc_obj_ref<TFrom> &obj) const
+            {
                 if (obj)
                 {
-                    auto box = stack_to<gc_obj_ref<Object>>(obj).template as<T>();
-                    if (box)
+                    if (auto box = obj.template as<TTo>(obj))
                     {
-                        auto new_obj = gc_new<Nullable_1<T>>();
-                        new_obj->value = *box;
-                        return stack_from(gc_ref_from_ref(*new_obj));
+                        auto new_nullable = ops::newobj<nullable_t>(*box);
+                        return new_nullable;
                     }
                     else
                     {
@@ -540,111 +375,53 @@ namespace stack
                 }
                 else
                 {
-                    auto new_obj = gc_new<Nullable_1<T>>();
-                    return stack_from(gc_ref_from_ref(*new_obj));
+                    auto new_nullable = gc_new<nullable_t>();
+                    return new_nullable;
                 }
             }
         };
 
-        template <class T>
+        // ECMA-335 III.4.33
+        template <class TFrom, class TTo>
         struct unbox_any_impl
         {
-            auto operator()(const O &obj)
+            auto operator()(const gc_obj_ref<TFrom> &obj)
             {
-                using ::System_Private_CoreLib::System::Object;
-
-                // check_null_obj_ref(obj);
-                auto box = stack_to<gc_obj_ref<Object>>(obj).template as<T>();
-                if (box)
+                if constexpr (is_value_type_v<TTo>)
                 {
-                    if constexpr (natsu::is_value_type_v<T>)
-                    {
-                        return stack_from(*box);
-                    }
+                    // System.NullReferenceException is thrown if obj is null and typeTok is a non-nullable value type (Partition I.8.2.4).
+                    check_null_obj_ref(obj);
+                    if (auto box = obj.template as<TTo>())
+                        return *box;
                     else
-                    {
-                        return obj;
-                    }
-                }
-                else
-                {
-                    throw_invalid_cast_exception();
-                }
-            }
-        };
-
-        template <class T>
-        struct unbox_any_impl<::System_Private_CoreLib::System::Nullable_1<T>>
-        {
-            ::System_Private_CoreLib::System::Nullable_1<T> operator()(const O &obj)
-            {
-                using ::System_Private_CoreLib::System::Nullable_1;
-                using ::System_Private_CoreLib::System::Object;
-
-                if (obj)
-                {
-                    auto box = stack_to<gc_obj_ref<Object>>(obj).template as<T>();
-                    if (box)
-                    {
-                        return stack_from(make_object<Nullable_1<T>>(*box));
-                    }
-                    else
-                    {
                         throw_invalid_cast_exception();
-                    }
                 }
                 else
                 {
-                    return stack_from(Nullable_1<T>());
+                    return castclass_impl<TFrom, TTo>()(obj);
                 }
             }
         };
 
+        // ECMA-335 III.4.33
         template <class TFrom, class TTo>
-        struct isinst_impl
-        {
-            gc_obj_ref<TTo> operator()(gc_obj_ref<TFrom> obj) const noexcept
-            {
-                if (obj && obj.header().vtable_as<typename natsu::to_clr_type_t<T>::VTable>())
-                    return obj;
-                return null;
-            }
-        };
-
-        template <class T>
-        struct isinst_impl<::System_Private_CoreLib::System::Nullable_1<T>>
-        {
-            O operator()(const O &obj) const noexcept
-            {
-                return isinst_impl<T>()(obj);
-            }
-        };
-
-        template <class T>
-        struct castclass_impl
+        struct unbox_any_impl<TFrom, ::System_Private_CoreLib::System::Nullable_1<TTo>>
         {
-            O operator()(const O &obj) const noexcept
-            {
-                // check_null_obj_ref(obj);
-                if (obj.header().vtable_as<typename T::VTable>())
-                    return obj;
-                throw_invalid_cast_exception();
-            }
-        };
+            using nullable_t = ::System_Private_CoreLib::System::Nullable_1<TTo>;
 
-        template <class T>
-        struct castclass_impl<::System_Private_CoreLib::System::Nullable_1<T>>
-        {
-            O operator()(const O &obj) const noexcept
+            nullable_t operator()(const gc_obj_ref<TFrom> &obj)
             {
-                if (obj)
+                if (!obj)
                 {
-                    if (obj.header().vtable_as<typename T::VTable>())
-                        return obj;
-                    throw_invalid_cast_exception();
+                    nullable_t value;
+                    ops::initobj(ops::ref(value));
+                    return value;
                 }
 
-                return null;
+                if (auto box = obj.template as<TTo>())
+                    return ops::newobj<nullable_t>(*box);
+                else
+                    throw_invalid_cast_exception();
             }
         };
 
@@ -678,21 +455,21 @@ namespace stack
             }
         };
 
-        template <class T1, class T2>
-        struct ceq_impl
+        template <class T>
+        struct ref_impl
         {
-            int32_t operator()(const T1 &lhs, const T2 rhs) const noexcept
+            constexpr gc_ref<T> operator()(T &ref) const noexcept
             {
-                return lhs == rhs;
+                return ref;
             }
         };
 
-        template <class T1, class T2>
-        struct cgt_un_impl
+        template <class T>
+        struct ref_impl<clr_volatile<T>>
         {
-            int32_t operator()(const T1 &lhs, const T2 rhs) const noexcept
+            gc_ref<T> operator()(clr_volatile<T> &ref) const noexcept
             {
-                return std::lhs == rhs;
+                return gc_ref<T>(reinterpret_cast<T &>(ref));
             }
         };
     }
@@ -723,33 +500,27 @@ namespace ops
     }
 
     template <class TFrom>
-    auto box(TFrom &&value) noexcept
+    auto box(TFrom value) noexcept
     {
         return stack::details::box_impl<std::decay_t<TFrom>>()(std::forward<TFrom>(value));
     }
 
-    template <class TFrom, class TTo>
-    auto unbox(TFrom &&obj)
-    {
-        return stack::details::unbox_impl<TTo>()(obj);
-    }
-
-    template <class TFrom, class TTo>
-    auto unbox_any(TFrom &&obj)
+    template <class TTo, class TFrom>
+    auto cast(TFrom value) noexcept
     {
-        return stack::details::unbox_any_impl<T>()(obj);
+        return stack::details::cast_impl<std::decay_t<TFrom>, TTo>()(std::forward<TFrom>(value));
     }
 
-    template <class TFrom>
-    natsu::gc_ref<TFrom> ref(TFrom &value) noexcept
+    template <class T>
+    auto ref(T &value) noexcept
     {
-        return natsu::gc_ref_from_ref(&value);
+        return stack::details::ref_impl<T>()(value);
     }
 
     template <class TFrom>
     void initobj(gc_ref<TFrom> addr) noexcept
     {
-        std::memset((void *)addr.value_, 0, sizeof(TFrom));
+        std::memset((void *)addr.ptr_, 0, sizeof(TFrom));
     }
 
     template <class TFrom>
@@ -758,39 +529,101 @@ namespace ops
         std::memset((void *)addr, 0, sizeof(TFrom));
     }
 
-    template <class TFrom, class TTo>
-    auto isinst(gc_obj_ref<TFrom> obj) noexcept
+    // ECMA-335 III.4.3
+    template <class TTo, class TFrom>
+    auto castclass(const gc_obj_ref<TFrom> &obj) noexcept
+    {
+        return stack::details::castclass_impl<TFrom, TTo>()(obj);
+    }
+
+    // ECMA-335 III.4.6
+    template <class TTo, class TFrom>
+    auto isinst(const gc_obj_ref<TFrom> &obj) noexcept
     {
         return stack::details::isinst_impl<TFrom, TTo>()(obj);
     }
 
+    // ECMA-335 III.4.32
+    template <class TTo, class TFrom>
+    auto unbox(const gc_obj_ref<TFrom> &obj)
+    {
+        return stack::details::unbox_impl<TFrom, TTo>()(obj);
+    }
+
+    // ECMA-335 III.4.33
+    template <class TTo, class TFrom>
+    auto unbox_any(const gc_obj_ref<TFrom> &obj)
+    {
+        return stack::details::unbox_any_impl<TFrom, TTo>()(obj);
+    }
+
     template <class T>
-    stack::O castclass(const stack::O &obj) noexcept
+    ::System_Private_CoreLib::System::IntPtr ldftn(T func)
     {
-        return stack::details::castclass_impl<T>()(obj);
+        return reinterpret_cast<intptr_t>(func);
     }
 
     template <class T>
-    constexpr auto unsign(T value) noexcept
+    T ldind(uintptr_t address)
+    {
+        if (!address)
+            throw_null_ref_exception();
+        return *reinterpret_cast<const T *>(address);
+    }
+
+    template <class TTo, class TFrom>
+    TTo ldind(const gc_ptr<TFrom> &address)
     {
-        using unsigned_type = std::make_unsigned<T>::type;
-        return static_cast<unsigned_type>(value);
+        check_null_obj_ref(address);
+        return *reinterpret_cast<const TTo *>(address.get());
+    }
+
+    template <class TTo, class TFrom>
+    TTo ldind(const gc_ref<TFrom> &address)
+    {
+        check_null_obj_ref(address);
+        return *reinterpret_cast<const TTo *>(address.get());
     }
 
     template <class T>
     ::System_Private_CoreLib::System::RuntimeTypeHandle ldtoken_type()
     {
-        return { runtime_type_holder<natsu::to_clr_type_t<T>>::get() };
+        ::System_Private_CoreLib::System::RuntimeTypeHandle handle;
+        handle._runtimeType = runtime_type_holder<natsu::to_clr_type_t<T>>::get();
+        return handle;
     }
 
     [[noreturn]] void throw_(gc_obj_ref<::System_Private_CoreLib::System::Exception> obj);
+
+    template <class T>
+    constexpr auto unsign(T value) noexcept
+    {
+        if constexpr (is_enum_v<T>)
+        {
+            using unsigned_type_e = typename std::make_unsigned<decltype(value.value__)>::type;
+            return static_cast<unsigned_type_e>(value.value__);
+        }
+        else if constexpr (std::is_floating_point_v<T>)
+        {
+            return value;
+        }
+        else if constexpr (std::is_same_v<T, ::System_Private_CoreLib::System::IntPtr>)
+        {
+            return (uintptr_t)value;
+        }
+        else
+        {
+            using unsigned_type = typename std::make_unsigned<T>::type;
+            return static_cast<unsigned_type>(value);
+        }
+    }
 }
 
 template <class T>
 gc_ref<T> unbox_exact(gc_obj_ref<::System_Private_CoreLib::System::Object> value)
 {
     auto box = value.cast<T>();
-    return gc_ref_from_ref(*box);
+    return *box;
 }
 }
 
@@ -799,13 +632,13 @@ namespace System_Private_CoreLib
 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));
+    _this->_value = reinterpret_cast<intptr_t>(value.get());
 }
 
 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)));
+    return *reinterpret_cast<::natsu::variable_type_t<T> *>(static_cast<intptr_t>(_this->_value));
 }
 
 template <class T>
@@ -829,7 +662,7 @@ template <class T>
 template <class TFrom, class TTo>
 ::natsu::gc_ref<::natsu::variable_type_t<TTo>> Internal::Runtime::CompilerServices::Unsafe::_s_As(::natsu::gc_ref<::natsu::variable_type_t<TFrom>> source)
 {
-    return ::natsu::gc_ref_from_ref(*reinterpret_cast<::natsu::variable_type_t<TTo> *>(source.ptr_));
+    return *reinterpret_cast<::natsu::variable_type_t<TTo> *>(source.ptr_);
 }
 
 template <class T>
@@ -923,6 +756,6 @@ bool System::Runtime::CompilerServices::RuntimeHelpers::_s_IsBitwiseEquatable()
 template <class T>
 ::natsu::gc_obj_ref<System::Collections::Generic::EqualityComparer_1<T>> System::Collections::Generic::ComparerHelpers::_s_CreateDefaultEqualityComparer()
 {
-    return natsu::null;
+    return nullptr;
 }
 }

+ 308 - 130
src/Native/natsu.typedef.h

@@ -49,6 +49,9 @@ struct gc_obj_ref;
 template <class T>
 struct gc_ref;
 
+template <class T>
+struct gc_ptr;
+
 struct clr_exception;
 
 [[noreturn]] void throw_null_ref_exception();
@@ -64,6 +67,13 @@ void check_null_obj_ref(gc_obj_ref<T> obj)
         throw_null_ref_exception();
 }
 
+template <class T>
+void check_null_obj_ref(gc_ptr<T> obj)
+{
+    if (!obj)
+        throw_null_ref_exception();
+}
+
 template <class T>
 void check_null_obj_ref(gc_ref<T> obj)
 {
@@ -189,6 +199,12 @@ using to_clr_type_t = typename to_clr_type<T>::type;
 template <class T>
 constexpr bool is_value_type_v = to_clr_type_t<T>::TypeInfo::IsValueType;
 
+// clang-format off
+template <class TFrom, class TTo>
+constexpr bool is_convertible_v = std::is_convertible_v<to_clr_type_t<TFrom> *, to_clr_type_t<TTo> *>
+|| std::is_convertible_v<typename to_clr_type_t<TFrom>::VTable *, typename to_clr_type_t<TTo>::VTable *>;
+// clang-format on
+
 template <class T>
 constexpr bool is_enum_v = to_clr_type_t<T>::TypeInfo::IsEnum;
 
@@ -210,24 +226,55 @@ struct variable_type<T, false>
 template <class T>
 using variable_type_t = typename variable_type<T, is_value_type_v<T>>::type;
 
-struct null_gc_obj_ref
+template <class T>
+class clr_volatile
 {
-    constexpr null_gc_obj_ref(std::nullptr_t = nullptr) noexcept
+public:
+    using value_type = T;
+
+    clr_volatile() noexcept
     {
     }
 
-    explicit operator uintptr_t() const noexcept
+    clr_volatile(T value) noexcept
+        : value_(value)
     {
-        return 0;
     }
 
-    explicit operator bool() const noexcept
+    clr_volatile(const clr_volatile<T> &other) noexcept
+        : value_(other.value_.load(std::memory_order_acquire))
     {
-        return false;
     }
-};
 
-constexpr null_gc_obj_ref null;
+    clr_volatile &operator=(const T &other) noexcept
+    {
+        value_.store(other, std::memory_order_release);
+        return *this;
+    }
+
+    T load() const noexcept
+    {
+        return value_.load(std::memory_order_acquire);
+    }
+
+    void store(const T &value)
+    {
+        value_.store(value, std::memory_order_release);
+    }
+
+    T &ref() noexcept
+    {
+        return reinterpret_cast<T &>(value_);
+    }
+
+    operator T() const noexcept
+    {
+        return load();
+    }
+
+private:
+    std::atomic<T> value_;
+};
 
 template <class T>
 struct gc_ref
@@ -244,6 +291,11 @@ struct gc_ref
     {
     }
 
+    explicit constexpr gc_ref(uintptr_t ptr) noexcept
+        : ptr_(reinterpret_cast<T *>(ptr))
+    {
+    }
+
     explicit constexpr operator bool() const noexcept
     {
         return true;
@@ -254,6 +306,16 @@ struct gc_ref
         return reinterpret_cast<uintptr_t>(ptr_);
     }
 
+    operator T &() noexcept
+    {
+        return *ptr_;
+    }
+
+    T *get() const noexcept
+    {
+        return ptr_;
+    }
+
     T *operator->() const noexcept
     {
         return ptr_;
@@ -271,16 +333,10 @@ struct gc_ref
     }
 };
 
-template <class T>
-gc_ref<T> gc_ref_from_ref(T &ref)
-{
-    return gc_ref<T>(ref);
-}
-
 template <class T>
 gc_ref<T> gc_ref_from_addr(uintptr_t addr)
 {
-    return gc_ref<T>(*reinterpret_cast<T *>(addr));
+    return *reinterpret_cast<T *>(addr);
 }
 
 template <class T>
@@ -288,7 +344,7 @@ struct gc_ptr
 {
     T *ptr_;
 
-    constexpr gc_ptr() noexcept
+    constexpr gc_ptr(std::nullptr_t = nullptr) noexcept
         : ptr_(nullptr)
     {
     }
@@ -298,7 +354,7 @@ struct gc_ptr
     {
     }
 
-    explicit constexpr gc_ptr(uintptr_t ptr) noexcept
+    constexpr gc_ptr(uintptr_t ptr) noexcept
         : ptr_(reinterpret_cast<T *>(ptr))
     {
     }
@@ -319,11 +375,6 @@ struct gc_ptr
         return ptr_;
     }
 
-    operator T *() const noexcept
-    {
-        return ptr_;
-    }
-
     T *get() const noexcept
     {
         return ptr_;
@@ -339,13 +390,30 @@ struct gc_ptr
         return *ptr_;
     }
 
-    template <class TOffset>
-    gc_ptr operator+(TOffset offset) noexcept
+    gc_ptr &operator=(uintptr_t address) noexcept
+    {
+        ptr_ = reinterpret_cast<T *>(address);
+        return *this;
+    }
+
+    gc_ptr operator+(intptr_t offset) const noexcept
     {
         auto new_ptr = *this;
         new_ptr.ptr_ = reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(new_ptr.ptr_) + offset);
         return new_ptr;
     }
+
+    gc_ptr operator-(intptr_t offset) const noexcept
+    {
+        auto new_ptr = *this;
+        new_ptr.ptr_ = reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(new_ptr.ptr_) - offset);
+        return new_ptr;
+    }
+
+    intptr_t operator-(const gc_ptr &other) const noexcept
+    {
+        return reinterpret_cast<intptr_t>(ptr_) - reinterpret_cast<intptr_t>(other.ptr_);
+    }
 };
 
 template <>
@@ -363,14 +431,20 @@ struct gc_ptr<void>
     {
     }
 
-    explicit gc_ptr(uintptr_t ptr) noexcept
-        : ptr_(reinterpret_cast<void *>(ptr))
+    template <class T>
+    gc_ptr(const gc_ptr<T> &ptr) noexcept
+        : ptr_(ptr.ptr_)
     {
     }
 
-    template <class U>
-    gc_ptr(const gc_ptr<U> &other) noexcept
-        : ptr_(reinterpret_cast<void *>(other.ptr_))
+    template <class T>
+    gc_ptr(const gc_ref<T> &ptr) noexcept
+        : ptr_(ptr.ptr_)
+    {
+    }
+
+    gc_ptr(uintptr_t ptr) noexcept
+        : ptr_(reinterpret_cast<void *>(ptr))
     {
     }
 
@@ -379,6 +453,17 @@ struct gc_ptr<void>
         return reinterpret_cast<uintptr_t>(ptr_);
     }
 
+    template <class U>
+    explicit operator gc_ref<U>() const
+    {
+        return *reinterpret_cast<U *>(ptr_);
+    }
+
+    void *get() const noexcept
+    {
+        return ptr_;
+    }
+
     operator void *() const noexcept
     {
         return ptr_;
@@ -409,7 +494,7 @@ struct gc_obj_ref
 {
     T *ptr_;
 
-    constexpr gc_obj_ref(null_gc_obj_ref = {}) noexcept
+    constexpr gc_obj_ref(std::nullptr_t = nullptr) noexcept
         : ptr_(nullptr)
     {
     }
@@ -419,9 +504,15 @@ struct gc_obj_ref
     {
     }
 
-    template <class U, class = std::enable_if_t<std::is_convertible_v<U *, T *>>>
-    constexpr gc_obj_ref(const gc_obj_ref<U> &other) noexcept
-        : ptr_(static_cast<T *>(other.ptr_))
+    //template <class U, class = std::enable_if_t<is_convertible_v<U, T>>>
+    //constexpr gc_obj_ref(const gc_obj_ref<U> &other) noexcept
+    //    : ptr_(static_cast<T *>(other.ptr_))
+    //{
+    //}
+
+    template <class U>
+    gc_obj_ref(const gc_obj_ref<U> &other) noexcept
+        : ptr_(reinterpret_cast<T *>(other.ptr_))
     {
     }
 
@@ -461,7 +552,7 @@ struct gc_obj_ref
                 return gc_obj_ref<U>(reinterpret_cast<U *>(ptr_));
         }
 
-        return null;
+        return nullptr;
     }
 
     template <class U>
@@ -476,41 +567,6 @@ struct gc_obj_ref
     }
 };
 
-template <class T>
-class clr_volatile
-{
-public:
-    using value_type = T;
-
-    clr_volatile() noexcept
-    {
-    }
-
-    clr_volatile(T value) noexcept
-        : value_(value)
-    {
-    }
-
-    clr_volatile(const clr_volatile<T> &other) noexcept
-        : value_(other.value_.load(std::memory_order_acquire))
-    {
-    }
-
-    clr_volatile &operator=(const T &other) noexcept
-    {
-        value_.store(other, std::memory_order_release);
-        return *this;
-    }
-
-    T load() const noexcept
-    {
-        return value_.load(std::memory_order_acquire);
-    }
-
-private:
-    std::atomic<T> value_;
-};
-
 struct clr_exception
 {
     template <class T>
@@ -534,6 +590,30 @@ constexpr bool operator==(const gc_obj_ref<T> &lhs, U *rhs) noexcept
     return lhs.ptr_ == rhs;
 }
 
+template <class T, class U>
+constexpr bool operator==(const gc_ptr<T> &lhs, const gc_ptr<U> &rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) == reinterpret_cast<uintptr_t>(rhs.ptr_);
+}
+
+template <class T, class U>
+constexpr bool operator!=(const gc_ptr<T> &lhs, const gc_ptr<U> &rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) != reinterpret_cast<uintptr_t>(rhs.ptr_);
+}
+
+template <class T>
+constexpr bool operator==(const gc_ptr<T> &lhs, uintptr_t rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) == rhs;
+}
+
+template <class T>
+constexpr bool operator!=(const gc_ptr<T> &lhs, uintptr_t rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) != rhs;
+}
+
 template <class T, class U>
 constexpr bool operator==(U *lhs, const gc_obj_ref<T> &rhs) noexcept
 {
@@ -547,17 +627,59 @@ constexpr bool operator!=(const gc_obj_ref<T> &lhs, const gc_obj_ref<U> &rhs) no
 }
 
 template <class T>
-constexpr bool operator==(const gc_obj_ref<T> &lhs, null_gc_obj_ref) noexcept
+constexpr bool operator==(const gc_obj_ref<T> &lhs, std::nullptr_t) noexcept
 {
     return !lhs.ptr_;
 }
 
 template <class T>
-constexpr bool operator==(null_gc_obj_ref, const gc_obj_ref<T> &rhs) noexcept
+constexpr bool operator==(std::nullptr_t, const gc_obj_ref<T> &rhs) noexcept
 {
     return !rhs.ptr_;
 }
 
+template <class T>
+constexpr bool operator>(const gc_obj_ref<T> &lhs, std::nullptr_t) noexcept
+{
+    return lhs.ptr_;
+}
+
+template <class T>
+constexpr bool operator<(const gc_ptr<T> &lhs, const gc_ptr<T> &rhs) noexcept
+{
+    return lhs.ptr_ < rhs.ptr_;
+}
+
+template <class T>
+constexpr bool operator<(const gc_ptr<T> &lhs, uintptr_t rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) < rhs;
+}
+
+template <class T>
+constexpr bool operator<(uintptr_t lhs, const gc_ptr<T> &rhs) noexcept
+{
+    return lhs.ptr_ < reinterpret_cast<uintptr_t>(rhs.ptr_);
+}
+
+template <class T>
+constexpr bool operator>(const gc_ptr<T> &lhs, const gc_ptr<T> &rhs) noexcept
+{
+    return lhs.ptr_ > rhs.ptr_;
+}
+
+template <class T>
+constexpr bool operator>(const gc_ptr<T> &lhs, uintptr_t rhs) noexcept
+{
+    return reinterpret_cast<uintptr_t>(lhs.ptr_) > rhs;
+}
+
+template <class T>
+constexpr bool operator>(uintptr_t lhs, const gc_ptr<T> &rhs) noexcept
+{
+    return lhs > reinterpret_cast<uintptr_t>(rhs.ptr_);
+}
+
 template <class TBase, class TIFace, bool>
 struct vtable_impl;
 
@@ -692,80 +814,136 @@ struct static_object
 #define NATSU_PRIMITIVE_IMPL_INTPTR                      \
     IntPtr() = default;                                  \
     IntPtr(intptr_t value) : _value((uintptr_t)value) {} \
+    IntPtr(void *value) : _value((uintptr_t)value) {}    \
     operator intptr_t() const noexcept { return (uintptr_t)_value; }
 
 #define NATSU_PRIMITIVE_IMPL_UINTPTR                       \
     UIntPtr() = default;                                   \
     UIntPtr(uintptr_t value) : _value((uintptr_t)value) {} \
+    UIntPtr(void *value) : _value((uintptr_t)value) {}     \
     operator uintptr_t() const noexcept { return (uintptr_t)_value; }
 
-#define NATSU_ENUM_IMPL_BYTE(name)  \
-    name &operator=(uint8_t value)  \
-    {                               \
-        value__ = value;            \
-        return *this;               \
-    }                               \
-    static name from(uint8_t value) \
-    {                               \
-        return name { value };      \
-    }                               \
+#define NATSU_ENUM_FLAG_OPERATORS(name)                                  \
+    name operator|(name b) const noexcept                                \
+    {                                                                    \
+        name e;                                                          \
+        e.value__ = static_cast<decltype(value__)>(value__ | b.value__); \
+        return e;                                                        \
+    }                                                                    \
+    name &operator|=(name b) noexcept                                    \
+    {                                                                    \
+        value__ = static_cast<decltype(value__)>(value__ | b.value__);   \
+        return *this;                                                    \
+    }                                                                    \
+    name operator&(name b) const noexcept                                \
+    {                                                                    \
+        name e;                                                          \
+        e.value__ = static_cast<decltype(value__)>(value__ & b.value__); \
+        return e;                                                        \
+    }                                                                    \
+    name &operator&=(name b) noexcept                                    \
+    {                                                                    \
+        value__ = static_cast<decltype(value__)>(value__ & b.value__);   \
+        return *this;                                                    \
+    }                                                                    \
+    name operator~() const noexcept                                      \
+    {                                                                    \
+        name e;                                                          \
+        e.value__ = static_cast<decltype(value__)>(~value__);            \
+        return e;                                                        \
+    }                                                                    \
+    name operator^(name b) const noexcept                                \
+    {                                                                    \
+        name e;                                                          \
+        e.value__ = static_cast<decltype(value__)>(value__ ^ b.value__); \
+        return e;                                                        \
+    }                                                                    \
+    name &operator^=(name b) noexcept                                    \
+    {                                                                    \
+        value__ = static_cast<decltype(value__)>(value__ ^ b.value__);   \
+        return *this;                                                    \
+    }
+
+#define NATSU_ENUM_IMPL_BYTE(name)                \
+    name &operator=(decltype(value__) value)      \
+    {                                             \
+        value__ = value;                          \
+        return *this;                             \
+    }                                             \
+    static name value_of(decltype(value__) value) \
+    {                                             \
+        name e;                                   \
+        e.value__ = value;                        \
+        return e;                                 \
+    }                                             \
     constexpr operator uint8_t() const noexcept { return value__; }
 
-#define NATSU_ENUM_IMPL_INT32(name) \
-    name &operator=(int32_t value)  \
-    {                               \
-        value__ = value;            \
-        return *this;               \
-    }                               \
-    static name from(int32_t value) \
-    {                               \
-        return name { value };      \
-    }                               \
+#define NATSU_ENUM_IMPL_INT32(name)               \
+    name &operator=(decltype(value__) value)      \
+    {                                             \
+        value__ = value;                          \
+        return *this;                             \
+    }                                             \
+    static name value_of(decltype(value__) value) \
+    {                                             \
+        name e;                                   \
+        e.value__ = value;                        \
+        return e;                                 \
+    }                                             \
     constexpr operator int32_t() const noexcept { return value__; }
 
-#define NATSU_ENUM_IMPL_UINT32(name) \
-    name &operator=(uint32_t value)  \
-    {                                \
-        value__ = value;             \
-        return *this;                \
-    }                                \
-    static name from(uint32_t value) \
-    {                                \
-        return name { value };       \
-    }                                \
+#define NATSU_ENUM_IMPL_UINT32(name)              \
+    name &operator=(decltype(value__) value)      \
+    {                                             \
+        value__ = value;                          \
+        return *this;                             \
+    }                                             \
+    static name value_of(decltype(value__) value) \
+    {                                             \
+        name e;                                   \
+        e.value__ = value;                        \
+        return e;                                 \
+    }                                             \
     constexpr operator uint32_t() const noexcept { return value__; }
 
 #define NATSU_OBJECT_IMPL
 
+#define NATSU_VALUETYPE_IMPL                                                                                \
+    template <class T>                                                                                      \
+    static ::natsu::gc_obj_ref<::System_Private_CoreLib::System::String> ToString(::natsu::gc_ref<T> _this) \
+    {                                                                                                       \
+        ::natsu::pure_call();                                                                               \
+    }
+
 #define NATSU_PRIMITIVE_OPERATORS_IMPL
 
-#define NATSU_SZARRAY_IMPL                                           \
-    constexpr ::natsu::variable_type_t<T> &at(size_t index)          \
-    {                                                                \
-        return elements_[index];                                     \
-    }                                                                \
-    constexpr ::natsu::variable_type_t<T> *begin()                   \
-    {                                                                \
-        return elements_;                                            \
-    }                                                                \
-    constexpr ::natsu::variable_type_t<T> *end()                     \
-    {                                                                \
-        return elements_ + length();                                 \
-    }                                                                \
-    constexpr auto ref_at(size_t index)                              \
-    {                                                                \
-        return ::natsu::gc_ref_from_ref(elements_[index]);           \
-    }                                                                \
-    constexpr ::natsu::variable_type_t<T> get(int index)             \
-    {                                                                \
-        return at(index);                                            \
-    }                                                                \
-    constexpr void set(int index, ::natsu::variable_type_t<T> value) \
-    {                                                                \
-        at(index) = value;                                           \
-    }                                                                \
-    constexpr uintptr_t length() const noexcept                      \
-    {                                                                \
-        return Length;                                               \
-    }                                                                \
+#define NATSU_SZARRAY_IMPL                                                      \
+    constexpr ::natsu::variable_type_t<T> &at(size_t index)                     \
+    {                                                                           \
+        return elements_[index];                                                \
+    }                                                                           \
+    constexpr ::natsu::variable_type_t<T> *begin()                              \
+    {                                                                           \
+        return elements_;                                                       \
+    }                                                                           \
+    constexpr ::natsu::variable_type_t<T> *end()                                \
+    {                                                                           \
+        return elements_ + length();                                            \
+    }                                                                           \
+    constexpr ::natsu::gc_ref<::natsu::variable_type_t<T>> ref_at(size_t index) \
+    {                                                                           \
+        return elements_[index];                                                \
+    }                                                                           \
+    constexpr ::natsu::variable_type_t<T> get(int index)                        \
+    {                                                                           \
+        return at(index);                                                       \
+    }                                                                           \
+    constexpr void set(int index, ::natsu::variable_type_t<T> value)            \
+    {                                                                           \
+        at(index) = value;                                                      \
+    }                                                                           \
+    constexpr uintptr_t length() const noexcept                                 \
+    {                                                                           \
+        return Length;                                                          \
+    }                                                                           \
     ::natsu::variable_type_t<T> elements_[0];

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

@@ -16,7 +16,8 @@ namespace Natsu.Compiler
         F,
         O,
         Ref,
-        Runtime
+        Runtime,
+        ValueType
     }
 
     public struct StackType
@@ -25,6 +26,8 @@ namespace Natsu.Compiler
 
         public TypeSig TypeSig;
 
+        public IList<TypeSig> GenArgs;
+
         public string Name;
     }
 
@@ -56,6 +59,15 @@ namespace Natsu.Compiler
 
         public int Count => _stackValues.Count;
 
+        public bool Volatile { get; set; }
+
+        public bool PopVolatile()
+        {
+            var value = Volatile;
+            Volatile = false;
+            return value;
+        }
+
         public EvaluationStack(TextWriter writer, int ident, int paramIndex)
         {
             _writer = writer;

+ 271 - 89
src/Natsu.Compiler/ILImporter.cs

@@ -785,7 +785,7 @@ namespace Natsu.Compiler
                         emitter.Ldvirtftn();
                         break;
                     case Code.Pop:
-                        stack.Pop();
+                        emitter.Pop();
                         break;
                     case Code.Sizeof:
                         emitter.Sizeof();
@@ -793,9 +793,10 @@ namespace Natsu.Compiler
                     case Code.Constrained:
                         stack.Constrained = (ITypeDefOrRef)op.Operand;
                         break;
-                    case Code.Readonly:
-                        break;
                     case Code.Volatile:
+                        stack.Volatile = true;
+                        break;
+                    case Code.Readonly:
                         break;
                     default:
                         throw new NotSupportedException(op.OpCode.Code.ToString());
@@ -826,8 +827,8 @@ namespace Natsu.Compiler
 
         // Unary
 
-        public void Neg() => Unary("neg");
-        public void Not() => Unary("not");
+        public void Neg() => Unary("-");
+        public void Not() => Unary("~");
 
         // Binary
 
@@ -843,7 +844,7 @@ namespace Natsu.Compiler
         public void Xor() => Binary("^");
         public void Shl() => Binary("<<");
         public void Shr() => Binary(">>");
-        public void Shr_Un() => Binary_Un("shr_un");
+        public void Shr_Un() => Binary_Un(">>");
         public void Clt() => Compare("<");
         public void Clt_Un() => Compare_Un("<");
         public void Ceq() => Compare("==");
@@ -854,28 +855,17 @@ namespace Natsu.Compiler
 
         public void Brtrue() => BranchIf(string.Empty);
         public void Brfalse() => BranchIf("!");
-        public void Blt() => BranchCompare("clt");
-        public void Blt_Un() => BranchCompare("clt_un");
-        public void Ble() => BranchCompare("cle");
-        public void Ble_Un() => BranchCompare("cle_un");
-
-        public void Beq()
-        {
-            var v2 = Stack.Pop();
-            var v1 = Stack.Pop();
-            var nextOp = (Instruction)Op.Operand;
-            Writer.Ident(Ident).WriteLine($"if ({v1.Expression} == {v2.Expression})");
-            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)};");
-        }
-
-        public void Bge() => BranchCompare("cge");
-        public void Bge_Un() => BranchCompare("cge_un");
-        public void Bgt() => BranchCompare("cgt");
-        public void Bgt_Un() => BranchCompare("cgt_un");
-        public void Bne() => BranchCompare("cne");
-        public void Bne_Un() => BranchCompare("cne_un");
+        public void Blt() => BranchCompare("<");
+        public void Blt_Un() => BranchCompare_Un("<");
+        public void Ble() => BranchCompare("<=");
+        public void Ble_Un() => BranchCompare_Un("<=");
+        public void Beq() => BranchCompare("==");
+        public void Bge() => BranchCompare(">=");
+        public void Bge_Un() => BranchCompare_Un(">=");
+        public void Bgt() => BranchCompare(">");
+        public void Bgt_Un() => BranchCompare_Un(">");
+        public void Bne() => BranchCompare("!=");
+        public void Bne_Un() => BranchCompare_Un("!=");
 
         // Conversion
 
@@ -913,22 +903,22 @@ namespace Natsu.Compiler
         public void Conv_Ovf_U_Un() => Conversion(CorLibTypes.UIntPtr, "ovf_u_un");
 
         // Ldind
-        public void Ldind_I1() => Ldind(CorLibTypes.SByte, "i1");
-        public void Ldind_I2() => Ldind(CorLibTypes.Int16, "i2");
-        public void Ldind_I4() => Ldind(CorLibTypes.Int32, "i4");
-        public void Ldind_I8() => Ldind(CorLibTypes.Int64, "i8");
-        public void Ldind_R4() => Ldind(CorLibTypes.Single, "r4");
-        public void Ldind_R8() => Ldind(CorLibTypes.Double, "r8");
-        public void Ldind_I() => Ldind(CorLibTypes.IntPtr, "i");
+        public void Ldind_I1() => Ldind(CorLibTypes.SByte);
+        public void Ldind_I2() => Ldind(CorLibTypes.Int16);
+        public void Ldind_I4() => Ldind(CorLibTypes.Int32);
+        public void Ldind_I8() => Ldind(CorLibTypes.Int64);
+        public void Ldind_R4() => Ldind(CorLibTypes.Single);
+        public void Ldind_R8() => Ldind(CorLibTypes.Double);
+        public void Ldind_I() => Ldind(CorLibTypes.IntPtr);
         public void Ldind_Ref()
         {
             var addr = Stack.Pop();
-            Stack.Push(addr.Type.TypeSig.Next, $"::natsu::ops::ldind_ref({addr.Expression})");
+            Stack.Push(addr.Type.TypeSig.Next, $"(*{addr.Expression})");
         }
 
-        public void Ldind_U1() => Ldind(CorLibTypes.Byte, "u1");
-        public void Ldind_U2() => Ldind(CorLibTypes.UInt16, "u2");
-        public void Ldind_U4() => Ldind(CorLibTypes.UInt32, "u4");
+        public void Ldind_U1() => Ldind(CorLibTypes.Byte);
+        public void Ldind_U2() => Ldind(CorLibTypes.UInt16);
+        public void Ldind_U4() => Ldind(CorLibTypes.UInt32);
 
         // Stind
         public void Stind_I1() => Stind("i1");
@@ -994,29 +984,25 @@ namespace Natsu.Compiler
         public void LdcI4()
         {
             var value = Op.GetLdcI4Value();
-            Stack.Push(new StackType { Code = StackTypeCode.Int32, Name = "int32_t" },
-                $"{TypeUtils.LiteralConstant(value)}", computed: true);
+            Stack.Push(CorLibTypes.Int32, $"{TypeUtils.LiteralConstant(value)}", computed: true);
         }
 
         public void Ldc_I8()
         {
             var value = (long)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.Int64, Name = "int64_t" },
-                $"{TypeUtils.LiteralConstant(value)}", computed: true);
+            Stack.Push(CorLibTypes.Int64, $"{TypeUtils.LiteralConstant(value)}", computed: true);
         }
 
         public void Ldc_R4()
         {
             var value = (float)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.F, Name = "float" },
-                $"{TypeUtils.LiteralConstant(value)}", computed: true);
+            Stack.Push(CorLibTypes.Single, $"{TypeUtils.LiteralConstant(value)}", computed: true);
         }
 
         public void Ldc_R8()
         {
             var value = (double)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.F, Name = "double" },
-                $"{TypeUtils.LiteralConstant(value)}", computed: true);
+            Stack.Push(CorLibTypes.Double, $"{TypeUtils.LiteralConstant(value)}", computed: true);
         }
 
         public void Call()
@@ -1047,7 +1033,7 @@ namespace Natsu.Compiler
                 expr = $"{ TypeUtils.EscapeTypeName(member.DeclaringType)}::{TypeUtils.EscapeMethodName(member, hasParamType: false)}({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, tGen)))})";
             }
 
-            var stackType = TypeUtils.GetStackType(method.RetType);
+            var stackType = TypeUtils.GetStackType(method.RetType, tGen);
             if (stackType.Code == StackTypeCode.Void)
                 Stack.Push(stackType, expr);
             else
@@ -1072,10 +1058,18 @@ namespace Natsu.Compiler
             string expr;
             if (Stack.Constrained != null)
             {
-                Stack.Push(para[0].destType.ToTypeDefOrRef(), $"::natsu::ops::box(*{para[0].src.Expression})");
-                para[0] = (para[0].destType, Stack.Pop());
+                var thisTypeCode = para[0].src.Type.Code;
+                if (thisTypeCode == StackTypeCode.O || thisTypeCode == StackTypeCode.Runtime)
+                {
+                    Stack.Push(para[0].destType.ToTypeDefOrRef(), $"::natsu::ops::box(*{para[0].src.Expression})");
+                    para[0] = (para[0].destType, Stack.Pop());
 
-                expr = $"::natsu::vtable<{TypeUtils.EscapeTypeName(Stack.Constrained)}>().{TypeUtils.EscapeMethodName(member)}({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, tGen)))})";
+                    expr = $"{ TypeUtils.EscapeTypeName(Stack.Constrained)}::{TypeUtils.EscapeMethodName(member, hasParamType: false)}({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, tGen)))})";
+                }
+                else
+                {
+                    expr = $"{ TypeUtils.EscapeTypeName(Stack.Constrained)}::{TypeUtils.EscapeMethodName(member, hasParamType: false)}({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, tGen)))})";
+                }
 
                 Stack.Constrained = null;
             }
@@ -1084,7 +1078,7 @@ namespace Natsu.Compiler
                 expr = $"{para[0].src.Expression}.header().template vtable_as<typename {TypeUtils.EscapeTypeName(member.DeclaringType)}::VTable>()->{TypeUtils.EscapeMethodName(member)}({string.Join(", ", para.Select(x => CastExpression(x.destType, x.src, tGen)))})";
             }
 
-            var stackType = TypeUtils.GetStackType(method.RetType);
+            var stackType = TypeUtils.GetStackType(method.RetType, tGen);
             if (stackType.Code == StackTypeCode.Void)
                 Stack.Push(stackType, expr);
             else
@@ -1093,7 +1087,65 @@ namespace Natsu.Compiler
 
         private static string CastExpression(TypeSig destType, StackEntry src, IList<TypeSig> genArgs = null)
         {
-            return $"{src.Expression}";
+            if (src.Type.Name == "std::nullptr_t")
+            {
+                return $"{TypeUtils.EscapeVariableTypeName(destType, genArgs: genArgs)}(nullptr)";
+            }
+            else if (TypeUtils.IsSameType(destType, src.Type)
+                || destType.ElementType == src.Type.TypeSig.ElementType)
+            {
+                return $"{src.Expression}";
+            }
+            else
+            {
+                if (destType.IsValueType)
+                {
+                    var typeDef = destType.ToTypeDefOrRef().ResolveTypeDef();
+                    if (typeDef != null && typeDef.IsEnum)
+                    {
+                        //if (int.TryParse(src.Expression, out var intValue))
+                        //{
+                        //    var field = typeDef.Fields.FirstOrDefault(x => x.HasConstant && Convert.ToInt32//(x.Constant.Value) == intValue);
+                        //    if (field != null)
+                        //        return $"{TypeUtils.EscapeTypeName(destType)}::{TypeUtils.EscapeIdentifier//(field.Name)}";
+                        //}
+
+                        return $"::natsu::ops::cast<{TypeUtils.EscapeVariableTypeName(destType, genArgs: genArgs)}>({src.Expression})";
+                    }
+                    else
+                    {
+                        return $"static_cast<{TypeUtils.EscapeVariableTypeName(destType, genArgs: genArgs)}>({src.Expression})";
+                    }
+                }
+                else if (src.Type.Code != StackTypeCode.Ref)
+                {
+                    return $"{TypeUtils.EscapeVariableTypeName(destType, genArgs: genArgs)}({src.Expression})";
+                }
+                else
+                {
+                    return src.Expression;
+                }
+            }
+        }
+
+        private static string MakeAccessExpression(StackEntry src)
+        {
+            switch (src.Type.Code)
+            {
+                case StackTypeCode.Int32:
+                case StackTypeCode.Int64:
+                case StackTypeCode.NativeInt:
+                case StackTypeCode.F:
+                case StackTypeCode.ValueType:
+                    return $"{src.Expression}.";
+                case StackTypeCode.O:
+                case StackTypeCode.Ref:
+                    return $"{src.Expression}->";
+                case StackTypeCode.Runtime:
+                    return $"::natsu::ops::access({src.Expression}).";
+                default:
+                    throw new NotSupportedException();
+            }
         }
 
         private static string MakeUnsignedExpression(StackEntry src)
@@ -1110,16 +1162,33 @@ namespace Natsu.Compiler
             }
             else
             {
-                if (src.Type.Code == StackTypeCode.F)
+                if (src.Type.Code == StackTypeCode.O)
                     return src.Expression;
-                else
-                    return $"::natsu::ops::unsign({src.Expression})";
+
+                switch (src.Type.TypeSig.ElementType)
+                {
+                    case ElementType.U:
+                    case ElementType.U1:
+                    case ElementType.U2:
+                    case ElementType.U4:
+                    case ElementType.U8:
+                    case ElementType.Class:
+                    case ElementType.Object:
+                    case ElementType.String:
+                    case ElementType.Array:
+                    case ElementType.SZArray:
+                    case ElementType.Boolean:
+                    case ElementType.Ptr:
+                        return src.Expression;
+                    default:
+                        return $"::natsu::ops::unsign({src.Expression})";
+                }
             }
         }
 
         public void Nop()
         {
-            Writer.Ident(Ident).WriteLine("::natsu::nop();");
+            // Writer.Ident(Ident).WriteLine("::natsu::nop();");
         }
 
         public void Ret()
@@ -1180,21 +1249,51 @@ namespace Natsu.Compiler
         public void Unary(string op)
         {
             var v1 = Stack.Pop();
-            Stack.Push(v1.Type, $"::natsu::ops::{op}_({v1.Expression})");
+            Stack.Push(v1.Type, $"{op}{v1.Expression}");
         }
 
         public void Binary(string op)
         {
             var v2 = Stack.Pop();
             var v1 = Stack.Pop();
-            Stack.Push(v1.Type, $"({v1.Expression} {op} {v2.Expression})");
+            var type = TypeUtils.IsRefOrPtr(v1.Type) && TypeUtils.IsRefOrPtr(v2.Type)
+                ? TypeUtils.GetStackType(CorLibTypes.IntPtr)
+                : v1.Type;
+
+            if (op == "%" && v1.Type.Code == StackTypeCode.F)
+            {
+                if (v1.Type.TypeSig.ElementType == ElementType.R4)
+                    Stack.Push(type, $"fmodf({v1.Expression}, {v2.Expression})");
+                else
+                    Stack.Push(type, $"fmod({v1.Expression}, {v2.Expression})");
+            }
+            else
+            {
+                if (v1.Type.TypeSig.ElementType == ElementType.ValueType)
+                    Stack.Push(v2.Type, $"({v1.Expression} {op} {v2.Expression})");
+                else
+                    Stack.Push(type, $"({v1.Expression} {op} {v2.Expression})");
+            }
         }
 
         public void Binary_Un(string op)
         {
             var v2 = Stack.Pop();
             var v1 = Stack.Pop();
-            Stack.Push(v1.Type, $"({MakeUnsignedExpression(v1)} {op} {MakeUnsignedExpression(v2)})");
+            var type = TypeUtils.IsRefOrPtr(v1.Type) && TypeUtils.IsRefOrPtr(v2.Type)
+                ? TypeUtils.GetStackType(CorLibTypes.UIntPtr)
+                : v1.Type;
+            if (op == "%" && v1.Type.Code == StackTypeCode.F)
+            {
+                if (v1.Type.TypeSig.ElementType == ElementType.R4)
+                    Stack.Push(type, $"fmodf({v1.Expression}, {v2.Expression})");
+                else
+                    Stack.Push(type, $"fmod({v1.Expression}, {v2.Expression})");
+            }
+            else
+            {
+                Stack.Push(type, $"({MakeUnsignedExpression(v1)} {op} {MakeUnsignedExpression(v2)})");
+            }
         }
 
         public void Compare(string op)
@@ -1221,7 +1320,18 @@ 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 ({v1.Expression} {op} {v2.Expression})");
+            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)};");
+        }
+
+        private void BranchCompare_Un(string op)
+        {
+            var v2 = Stack.Pop();
+            var v1 = Stack.Pop();
+            var nextOp = (Instruction)Op.Operand;
+            Writer.Ident(Ident).WriteLine($"if ({MakeUnsignedExpression(v1)} {op} {MakeUnsignedExpression(v2)})");
             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)};");
@@ -1240,8 +1350,7 @@ namespace Natsu.Compiler
         public void Ldstr()
         {
             var value = (string)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.O, Name = "::natsu::gc_obj_ref<::System_Private_CoreLib::System::String>" },
-                $"::{ ModuleName}::user_string_{UserStrings.Count}.get()");
+            Stack.Push(CorLibTypes.String, $"::{ ModuleName}::user_string_{UserStrings.Count}.get()");
             UserStrings.Add(value);
         }
 
@@ -1252,6 +1361,8 @@ namespace Natsu.Compiler
                 ? TypeUtils.EscapeIdentifier(field.Name)
                 : "::natsu::static_holder<typename" + TypeUtils.EscapeTypeName(field.DeclaringType) + "::Static>::get()." + TypeUtils.EscapeIdentifier(field.Name);
             var fieldType = field.FieldSig.Type;
+            if (Stack.PopVolatile())
+                expr += ".load()";
 
             Stack.Push(TypeUtils.GetStackType(fieldType), $"{expr}");
         }
@@ -1261,9 +1372,11 @@ namespace Natsu.Compiler
             var target = Stack.Pop();
             var field = (IField)Op.Operand;
             var thisType = TypeUtils.ThisType(field.DeclaringType);
-            string expr = $"{target.Expression}->" + TypeUtils.EscapeIdentifier(field.Name);
+            string expr = MakeAccessExpression(target) + TypeUtils.EscapeIdentifier(field.Name);
             var fieldType = field.FieldSig.Type;
 
+            if (Stack.PopVolatile())
+                expr += ".load()";
             Stack.Push(TypeUtils.GetStackType(fieldType), $"{expr}");
         }
 
@@ -1275,11 +1388,14 @@ namespace Natsu.Compiler
             var fieldType = field.FieldSig.Type;
             if (TypeUtils.IsCppBasicType(field.DeclaringType))
             {
-                Stack.Push(TypeUtils.GetStackType(new ByRefSig(fieldType)), $"::natsu::ops::ref({target.Expression})", computed: true);
+                if (target.Expression == "_this")
+                    Stack.Push(TypeUtils.GetStackType(new ByRefSig(fieldType)), $"_this", computed: true);
+                else
+                    Stack.Push(TypeUtils.GetStackType(new ByRefSig(fieldType)), $"::natsu::ops::ref({target.Expression})", computed: true);
             }
             else
             {
-                string expr = $"{target.Expression}->" + TypeUtils.EscapeIdentifier(field.Name);
+                string expr = MakeAccessExpression(target) + TypeUtils.EscapeIdentifier(field.Name);
                 Stack.Push(TypeUtils.GetStackType(new ByRefSig(fieldType)), $"::natsu::ops::ref({expr})", computed: true);
             }
         }
@@ -1300,12 +1416,17 @@ namespace Natsu.Compiler
                 ;
             var value = Stack.Pop();
             var field = (IField)Op.Operand;
+            if (Method.IsStaticConstructor && Method.DeclaringType.FullName.Contains("List"))
+                ;
             string expr = Method.IsStaticConstructor && TypeUtils.IsSameType(Method.DeclaringType, field.DeclaringType)
                 ? TypeUtils.EscapeIdentifier(field.Name)
                 : "::natsu::static_holder<typename" + TypeUtils.EscapeTypeName(field.DeclaringType) + "::Static>::get()." + TypeUtils.EscapeIdentifier(field.Name);
             var fieldType = field.FieldSig.Type;
 
-            Writer.Ident(Ident).WriteLine($"{expr} = {value.Expression};");
+            if (Stack.PopVolatile())
+                Writer.Ident(Ident).WriteLine($"{expr}.store({CastExpression(fieldType, value)});");
+            else
+                Writer.Ident(Ident).WriteLine($"{expr} = {CastExpression(fieldType, value)};");
         }
 
         public void Stfld()
@@ -1314,17 +1435,20 @@ namespace Natsu.Compiler
             var target = Stack.Pop();
             var field = (IField)Op.Operand;
             var thisType = TypeUtils.ThisType(field.DeclaringType);
-            string expr = $"{target.Expression}->" + TypeUtils.EscapeIdentifier(field.Name);
+            string expr = MakeAccessExpression(target) + TypeUtils.EscapeIdentifier(field.Name);
             var fieldType = field.FieldSig.Type;
 
-            Writer.Ident(Ident).WriteLine($"{expr} = {value.Expression};");
+            if (Stack.PopVolatile())
+                Writer.Ident(Ident).WriteLine($"{expr}.store({CastExpression(fieldType, value)});");
+            else
+                Writer.Ident(Ident).WriteLine($"{expr} = {CastExpression(fieldType, value)};");
         }
 
         public void Newarr()
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var len = Stack.Pop();
-            Stack.Push(new SZArraySig(type.ToTypeSig()).ToTypeDefOrRef(), $"::natsu::gc_new_array<{TypeUtils.EscapeTypeName(type)}>({len.Expression})");
+            Stack.Push(new SZArraySig(type.ToTypeSig()).ToTypeDefOrRef(), $"::natsu::gc_new_array<{TypeUtils.EscapeTypeName(type, cppBasicType: true)}>({len.Expression})");
         }
 
         public void Initobj()
@@ -1353,7 +1477,7 @@ namespace Natsu.Compiler
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var addr = Stack.Pop();
-            Stack.Push(TypeUtils.GetStackType(type.ToTypeSig()), $"::natsu::ops::ldobj<{TypeUtils.EscapeVariableTypeName(type)}>({addr.Expression})");
+            Stack.Push(TypeUtils.GetStackType(type.ToTypeSig()), $"*{addr.Expression}");
         }
 
         public void Stobj()
@@ -1361,20 +1485,20 @@ namespace Natsu.Compiler
             var type = (ITypeDefOrRef)Op.Operand;
             var src = Stack.Pop();
             var dest = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"::natsu::ops::stobj<{TypeUtils.EscapeVariableTypeName(type)}>({src.Expression}, {dest.Expression});");
+            Writer.Ident(Ident).WriteLine($"*{dest.Expression} = {src.Expression};");
         }
 
         public void Ldtoken()
         {
             var type = (ITypeDefOrRef)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.Runtime, Name = "::System_Private_CoreLib::System::RuntimeTypeHandle" }, $"::natsu::ops::ldtoken_type<{TypeUtils.EscapeTypeName(type)}>()");
+            Stack.Push(CorLibTypes.Object, $"::natsu::ops::ldtoken_type<{TypeUtils.EscapeTypeName(type)}>()");
         }
 
         public void Isinst()
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var obj = Stack.Pop();
-            Stack.Push(TypeUtils.GetStackType(type.ToTypeSig()), $"::natsu::ops::isinst<{TypeUtils.EscapeTypeName(type, cppBasicType: true)}>({obj.Expression})");
+            Stack.Push(TypeUtils.GetStackType(StackTypeCode.O, type.ToTypeSig()), $"::natsu::ops::isinst<{TypeUtils.EscapeTypeName(type, cppBasicType: true)}>({obj.Expression})");
         }
 
         public void Unbox_Any()
@@ -1407,29 +1531,81 @@ namespace Natsu.Compiler
         public void Localloc()
         {
             var size = Stack.Pop();
-            Stack.Push(CorLibTypes.UIntPtr, $"::natsu::ops::localloc({size.Expression})");
+            Stack.Push(CorLibTypes.UIntPtr, $"natsu_alloca({size.Expression})");
         }
 
         private void Conversion(TypeSig stackType, string type)
         {
             var value = Stack.Pop();
             var expr = value.Expression;
-            if (TypeUtils.IsRefOrPtr(value.Type.Code))
+            if (TypeUtils.IsRefOrPtr(value.Type))
                 expr += ".ptr_";
-            Stack.Push(stackType, $"static_cast<{TypeUtils.EscapeVariableTypeName(stackType)}>({expr})");
+
+            string destTypeName = null;
+            if (stackType.ElementType == ElementType.I ||
+                stackType.ElementType == ElementType.U)
+            {
+                if (TypeUtils.IsRefOrPtr(value.Type))
+                {
+                    destTypeName = stackType.ElementType switch
+                    {
+                        ElementType.I => "reinterpret_cast<intptr_t>",
+                        ElementType.U => "reinterpret_cast<uintptr_t>",
+                    };
+                }
+                else
+                {
+                    destTypeName = stackType.ElementType switch
+                    {
+                        ElementType.I => "static_cast<intptr_t>",
+                        ElementType.U => "static_cast<uintptr_t>",
+                    };
+                }
+            }
+            else
+            {
+                switch (stackType.ElementType)
+                {
+                    case ElementType.I1:
+                    case ElementType.I2:
+                    case ElementType.I4:
+                    case ElementType.I8:
+                    case ElementType.U1:
+                    case ElementType.U2:
+                    case ElementType.U4:
+                    case ElementType.U8:
+                        if (TypeUtils.IsRefOrPtr(value.Type))
+                            destTypeName = $"reinterpret_cast<{TypeUtils.EscapeVariableTypeName(stackType)}>";
+                        break;
+                }
+            }
+
+            destTypeName = destTypeName ?? $"static_cast<{TypeUtils.EscapeVariableTypeName(stackType)}>";
+            Stack.Push(stackType, $"{destTypeName}({expr})");
         }
 
-        private void Ldind(TypeSig stackType, string type)
+        private void Ldind(TypeSig stackType)
         {
             var addr = Stack.Pop();
-            Stack.Push(stackType, $"::natsu::ops::ldind_{type}({addr.Expression})");
+            if (addr.Type.TypeSig.ElementType == ElementType.ByRef ||
+                addr.Type.TypeSig.ElementType == ElementType.Ptr)
+            {
+                var actualType = addr.Type.TypeSig.Next;
+                if (TypeUtils.IsSameType(actualType.ToTypeDefOrRef(), stackType.ToTypeDefOrRef()))
+                {
+                    Stack.Push(stackType, $"*{addr.Expression}");
+                    return;
+                }
+            }
+
+            Stack.Push(stackType, $"::natsu::ops::ldind<{TypeUtils.EscapeVariableTypeName(stackType)}>({addr.Expression})");
         }
 
         private void Stind(string type)
         {
             var value = Stack.Pop();
             var addr = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"::natsu::ops::stind_{type}({addr.Expression}, {value.Expression});");
+            Writer.Ident(Ident).WriteLine($"*{addr.Expression} = {value.Expression};");
         }
 
         private void Ldelem(TypeSig stackType, string type)
@@ -1453,7 +1629,7 @@ namespace Natsu.Compiler
             var type = (ITypeDefOrRef)Op.Operand;
             var index = Stack.Pop();
             var array = Stack.Pop();
-            Stack.Push(TypeUtils.GetStackType(type.ToTypeSig()), $"::natsu::ops::ldelem<{TypeUtils.EscapeTypeName(type)}>({array.Expression}, {index.Expression})");
+            Stack.Push(TypeUtils.GetStackType(type.ToTypeSig()), $"{array.Expression}->at({index.Expression})");
         }
 
         public void Stelem()
@@ -1462,7 +1638,7 @@ namespace Natsu.Compiler
             var value = Stack.Pop();
             var index = Stack.Pop();
             var array = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"::natsu::ops::stelem<{TypeUtils.EscapeTypeName(type)}>({array.Expression}, {index.Expression}, {value.Expression});");
+            Writer.Ident(Ident).WriteLine($"{array.Expression}->at({index.Expression}) = {value.Expression};");
         }
 
         public void Ldelema()
@@ -1470,19 +1646,19 @@ namespace Natsu.Compiler
             var type = (ITypeDefOrRef)Op.Operand;
             var index = Stack.Pop();
             var array = Stack.Pop();
-            Stack.Push(TypeUtils.GetStackType(new ByRefSig(type.ToTypeSig())), $"::natsu::ops::ldelema<{TypeUtils.EscapeTypeName(type)}>({array.Expression}, {index.Expression})");
+            Stack.Push(TypeUtils.GetStackType(new ByRefSig(type.ToTypeSig())), $"{array.Expression}->ref_at({index.Expression})");
         }
 
         public void Box()
         {
             var type = (ITypeDefOrRef)Op.Operand;
             var value = Stack.Pop();
-            Stack.Push(new StackType { Code = StackTypeCode.O, Name = "::natsu::gc_obj_ref<>" }, $"::natsu::ops::box({CastExpression(type.ToTypeSig(), value)})");
+            Stack.Push(CorLibTypes.Object, $"::natsu::ops::box({CastExpression(type.ToTypeSig(), value)})");
         }
 
         public void Ldnull()
         {
-            Stack.Push(new StackType { Code = StackTypeCode.O, Name = "::natsu::gc_obj_ref<>" }, $"::natsu::null");
+            Stack.Push(new StackType { Code = StackTypeCode.O, TypeSig = CorLibTypes.Object, Name = "std::nullptr_t" }, "nullptr");
         }
 
         public void Dup()
@@ -1510,7 +1686,7 @@ namespace Natsu.Compiler
                 expr = $"{ TypeUtils.EscapeTypeName(member.DeclaringType)}::{TypeUtils.EscapeMethodName(member, hasParamType: false)}";
             }
 
-            Stack.Push(new StackType { Code = StackTypeCode.NativeInt, Name = "uintptr_t" }, $"::natsu::ops::ldftn({expr})");
+            Stack.Push(CorLibTypes.IntPtr, $"::natsu::ops::ldftn({expr})");
         }
 
         public void Ldvirtftn()
@@ -1532,14 +1708,14 @@ namespace Natsu.Compiler
                 expr = $"{obj.Expression}.header().template vtable_as<typename {TypeUtils.EscapeTypeName(member.DeclaringType)}::VTable>()->{TypeUtils.EscapeMethodName(member)}";
             }
 
-            Stack.Push(new StackType { Code = StackTypeCode.NativeInt, Name = "uintptr_t" }, $"::natsu::ops::ldftn({expr})");
+            Stack.Push(CorLibTypes.IntPtr, $"::natsu::ops::ldftn({expr})");
         }
 
         public void Switch()
         {
             var instructions = (Instruction[])Op.Operand;
             var v1 = Stack.Pop();
-            Writer.Ident(Ident).WriteLine($"switch ({v1.Expression}.value_)");
+            Writer.Ident(Ident).WriteLine($"switch ({v1.Expression})");
             Writer.Ident(Ident).WriteLine("{");
             for (int i = 0; i < instructions.Length; i++)
             {
@@ -1554,7 +1730,13 @@ namespace Natsu.Compiler
         public void Sizeof()
         {
             var type = (ITypeDefOrRef)Op.Operand;
-            Stack.Push(new StackType { Code = StackTypeCode.Int32, Name = "int32_t" }, $"::natsu::ops::Sizeof<{TypeUtils.EscapeTypeName(type)}>()");
+            Stack.Push(CorLibTypes.Int32, $"sizeof({TypeUtils.EscapeTypeName(type)})");
+        }
+
+        public void Pop()
+        {
+            Stack.Compute();
+            Stack.Pop();
         }
     }
 }

+ 0 - 1
src/Natsu.Compiler/Natsu.Compiler.csproj

@@ -7,7 +7,6 @@
 
   <ItemGroup>
     <PackageReference Include="dnlib" Version="3.2.0" />
-    <PackageReference Include="ICSharpCode.Decompiler" Version="5.0.2.5153" />
     <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
   </ItemGroup>
 

+ 76 - 34
src/Natsu.Compiler/Program.cs

@@ -69,7 +69,7 @@ namespace Natsu.Compiler
             using (var sha256 = SHA256.Create())
             {
                 digest = Convert.ToBase64String(sha256.ComputeHash(File.ReadAllBytes(_module.Location)));
-#if false
+#if true
                 if (HasOutputUptodate(Path.Combine(outputPath, $"{_module.Assembly.Name}.h"), digest))
                     return;
 #endif
@@ -127,7 +127,7 @@ namespace Natsu.Compiler
 
                 using (var writerSrc = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.cpp"), false, Encoding.UTF8))
                 {
-                    writer.WriteLine(DigestHeader + digest);
+                    writerSrc.WriteLine(DigestHeader + digest);
                     writerSrc.WriteLine($"#include \"{_module.Assembly.Name}.h\"");
                     writerSrc.WriteLine();
 
@@ -409,10 +409,7 @@ namespace Natsu.Compiler
                 writer.Ident(ident).Write($"template <{string.Join(", ", typeNames)}> ");
             }
 
-            if (type.TypeDef.IsExplicitLayout)
-                writer.Ident(ident).Write($"union {type.Name};");
-            else
-                writer.Ident(ident).Write($"struct {type.Name};");
+            writer.Ident(ident).Write($"struct {type.Name};");
 
             foreach (var ns in nss)
                 writer.Write(" }");
@@ -450,22 +447,13 @@ namespace Natsu.Compiler
                 writer.Ident(ident).WriteLine($"template <{string.Join(", ", typeNames)}> ");
             }
 
-            if (type.TypeDef.IsExplicitLayout)
-                writer.Ident(ident).Write($"union {type.Name}");
-            else
-                writer.Ident(ident).Write($"struct {type.Name}");
-            if (!type.TypeDef.IsValueType)
-            {
-                var baseType = GetBaseType(type.TypeDef);
-                if (baseType != null)
-                    writer.WriteLine(" : public " + TypeUtils.EscapeTypeName(baseType));
-                else
-                    writer.WriteLine();
-            }
+            writer.Ident(ident).Write($"struct {type.Name}");
+
+            var baseType = GetBaseType(type.TypeDef);
+            if (baseType != null)
+                writer.WriteLine(" : public " + TypeUtils.EscapeTypeName(baseType));
             else
-            {
                 writer.WriteLine();
-            }
 
             writer.Ident(ident).WriteLine("{");
             // ctor
@@ -492,23 +480,69 @@ namespace Natsu.Compiler
             WriteVTableDeclare(writer, ident + 1, type);
             writer.WriteLine();
 
-            var hasSize = type.TypeDef.HasClassLayout && type.TypeDef.ClassLayout.ClassSize != 0;
-            string fieldSize = "0";
-            foreach (var field in type.TypeDef.Fields)
+            if (type.TypeDef.IsEnum)
             {
-                if (field.HasConstant)
-                    WriteConstantField(writer, ident + 1, field);
-                else if (!field.IsStatic)
-                    WriteField(writer, ident + 1, field);
-                else
-                    hasStaticMember = true;
-
-                if (hasSize && !field.IsStatic)
-                    fieldSize += " + " + TypeUtils.GetTypeSize(field.FieldType.ElementType);
+                writer.Ident(ident + 1).WriteLine($"enum : {TypeUtils.EscapeVariableTypeName(type.TypeDef.GetEnumUnderlyingType())}");
+                writer.Ident(ident + 1).WriteLine("{");
+                foreach (var field in type.TypeDef.Fields)
+                {
+                    if (field.HasConstant)
+                    {
+                        writer.Ident(ident + 2).WriteLine($"{TypeUtils.EscapeIdentifier(field.Name)} = {TypeUtils.LiteralConstant(field.Constant.Value)},");
+                    }
+                }
+                writer.Ident(ident + 1).WriteLine("} value__;");
             }
+            else
+            {
+                var hasSize = type.TypeDef.HasClassLayout && type.TypeDef.ClassLayout.ClassSize != 0;
+                var fieldSize = new List<string> { "0" };
+                if (type.TypeDef.IsExplicitLayout)
+                {
+                    ident += 1;
+                    writer.Ident(ident).WriteLine($"union");
+                    writer.Ident(ident).WriteLine("{");
+                }
+                foreach (var field in type.TypeDef.Fields)
+                {
+                    if (field.HasConstant)
+                        WriteConstantField(writer, ident + 1, field);
+                    else if (!field.IsStatic)
+                        WriteField(writer, ident + 1, field);
+                    else
+                        hasStaticMember = true;
+
+                    if (hasSize && !field.IsStatic)
+                    {
+                        if (field.FieldOffset.HasValue)
+                        {
+                            fieldSize.Add($"({field.FieldOffset.Value} + {TypeUtils.GetTypeSize(field.FieldType.ElementType)})");
+                        }
+                        else
+                        {
+                            fieldSize.Add(TypeUtils.GetTypeSize(field.FieldType.ElementType));
+                        }
+                    }
+                }
+
+                if (hasSize)
+                {
+                    if (type.TypeDef.IsExplicitLayout)
+                    {
+                        writer.Ident(ident + 1).WriteLine($"uint8_t padding_[{type.TypeDef.ClassLayout.ClassSize} - std::max({{{string.Join(", ", fieldSize)}}})];");
+                    }
+                    else
+                    {
+                        writer.Ident(ident + 1).WriteLine($"uint8_t padding_[{type.TypeDef.ClassLayout.ClassSize} - ({string.Join(" + ", fieldSize)})];");
+                    }
+                }
 
-            if (hasSize)
-                writer.Ident(ident + 1).WriteLine($"uint8_t padding_[{type.TypeDef.ClassLayout.ClassSize} - ({fieldSize})];");
+                if (type.TypeDef.IsExplicitLayout)
+                {
+                    writer.Ident(ident).WriteLine("};");
+                    ident -= 1;
+                }
+            }
 
             writer.WriteLine();
 
@@ -534,6 +568,8 @@ namespace Natsu.Compiler
             {
                 writer.WriteLine();
                 writer.Ident(ident + 1).WriteLine($"NATSU_ENUM_IMPL_{type.TypeDef.GetEnumUnderlyingType().TypeName.ToUpperInvariant()}({type.Name})");
+                if (type.TypeDef.CustomAttributes.Any(x => x.TypeFullName == "System.FlagsAttribute"))
+                    writer.Ident(ident + 1).WriteLine($"NATSU_ENUM_FLAG_OPERATORS({type.Name})");
             }
 
             if (type.TypeDef.ToTypeSig().ElementType == ElementType.Object)
@@ -542,6 +578,12 @@ namespace Natsu.Compiler
                 writer.Ident(ident + 1).WriteLine($"NATSU_OBJECT_IMPL");
             }
 
+            if (type.TypeDef.FullName == "System.ValueType")
+            {
+                writer.WriteLine();
+                writer.Ident(ident + 1).WriteLine($"NATSU_VALUETYPE_IMPL");
+            }
+
             if (type.TypeDef == _szArrayType?.TypeDef)
             {
                 writer.WriteLine();

+ 76 - 26
src/Natsu.Compiler/TypeUtils.cs

@@ -11,7 +11,12 @@ namespace Natsu.Compiler
 {
     static class TypeUtils
     {
-        public static StackType GetStackType(TypeSig type)
+        public static StackType GetStackType(StackTypeCode code, TypeSig type, IList<TypeSig> genArgs = null)
+        {
+            return new StackType { Code = code, Name = EscapeVariableTypeName(type, genArgs: genArgs), TypeSig = type, GenArgs = genArgs };
+        }
+
+        public static StackType GetStackType(TypeSig type, IList<TypeSig> genArgs = null)
         {
             StackTypeCode code;
             switch (type.ElementType)
@@ -65,19 +70,16 @@ namespace Natsu.Compiler
                     code = StackTypeCode.Ref;
                     break;
                 case ElementType.ValueType:
-                    code = StackTypeCode.Runtime;
+                    code = StackTypeCode.ValueType;
                     break;
                 case ElementType.Class:
                     code = StackTypeCode.O;
                     break;
-                case ElementType.Var:
-                    code = StackTypeCode.Runtime;
-                    break;
                 case ElementType.Array:
                     code = StackTypeCode.O;
                     break;
                 case ElementType.TypedByRef:
-                    code = StackTypeCode.Runtime;
+                    code = StackTypeCode.ValueType;
                     break;
                 case ElementType.I:
                     code = StackTypeCode.NativeInt;
@@ -94,24 +96,47 @@ namespace Natsu.Compiler
                 case ElementType.SZArray:
                     code = StackTypeCode.O;
                     break;
+                case ElementType.Var:
+                    {
+                        var var = type.ToGenericVar();
+                        if (genArgs != null)
+                        {
+                            var sig = genArgs.OfType<GenericSig>().FirstOrDefault(x => x.Number == var.Number);
+                            if (sig != null)
+                                code = GetStackType(sig).Code;
+                            else
+                                code = GetStackType(genArgs[(int)var.Number]).Code;
+                        }
+                        else
+                        {
+                            code = StackTypeCode.Runtime;
+                        }
+                    }
+                    break;
                 case ElementType.MVar:
-                    code = StackTypeCode.Runtime;
+                    {
+                        var mvar = type.ToGenericMVar();
+                        if (genArgs != null)
+                            code = GetStackType(genArgs[(int)mvar.Number]).Code;
+                        else
+                            code = StackTypeCode.Runtime;
+                    }
                     break;
                 case ElementType.GenericInst:
                     {
                         var gen = type.ToGenericInstSig();
-                        code = GetStackType(gen.GenericType).Code;
+                        code = GetStackType(gen.GenericType, genArgs).Code;
                         break;
                     }
                 case ElementType.CModReqd:
                 case ElementType.CModOpt:
                 case ElementType.Pinned:
-                    return GetStackType(type.Next);
+                    return GetStackType(type.Next, genArgs);
                 default:
                     throw new NotSupportedException();
             }
 
-            return new StackType { Code = code, Name = EscapeVariableTypeName(type), TypeSig = type };
+            return new StackType { Code = code, Name = EscapeVariableTypeName(type, genArgs: genArgs), TypeSig = type, GenArgs = genArgs };
         }
 
         public static TypeSig ThisType(ITypeDefOrRef type)
@@ -226,7 +251,10 @@ namespace Natsu.Compiler
                         }
                         else
                         {
-                            sb.Append(var.GetName());
+                            if (cppBasicType)
+                                sb.Append(var.GetName());
+                            else
+                                sb.Append($"::natsu::to_clr_type_t<{var.GetName()}>");
                         }
                     }
                     break;
@@ -236,7 +264,12 @@ namespace Natsu.Compiler
                         if (genArgs != null)
                             EscapeTypeName(sb, genArgs[(int)mvar.Number], cppBasicType: true);
                         else
-                            sb.Append(mvar.GetName());
+                        {
+                            if (cppBasicType)
+                                sb.Append(mvar.GetName());
+                            else
+                                sb.Append($"::natsu::to_clr_type_t<{mvar.GetName()}>");
+                        }
                     }
                     break;
                 case ElementType.GenericInst:
@@ -300,11 +333,11 @@ namespace Natsu.Compiler
         {
             var sig = type.ToTypeSig();
             if (type.IsValueType || IsValueType(sig))
-                return EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs);
+                return EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs, cppBasicType: true);
             else if (type.ToTypeSig().IsGenericParameter)
-                return $"::natsu::variable_type_t<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs)}>";
+                return $"::natsu::variable_type_t<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs, cppBasicType: true)}>";
             else
-                return $"::natsu::gc_obj_ref<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs)}>";
+                return $"::natsu::gc_obj_ref<{EscapeTypeNameImpl(type, hasGen, hasModuleName, genArgs, cppBasicType: true)}>";
         }
 
         public static string EscapeTypeName(string name)
@@ -863,7 +896,7 @@ namespace Natsu.Compiler
 
         public static bool IsSameType(ITypeDefOrRef type1, ITypeDefOrRef type2)
         {
-            return type1 == type2 || type1 == type2.Scope;
+            return type1 == type2 || type1 == type2.ScopeType;
         }
 
         public static string GetLocalName(Local local, MethodDef method)
@@ -880,21 +913,38 @@ namespace Natsu.Compiler
             return localName ?? $"_l{local.Index}";
         }
 
-        public static bool IsRefOrPtr(StackTypeCode type)
+        public static bool IsRefOrPtr(StackType type)
         {
-            switch (type)
+            if (type.Code == StackTypeCode.O)
+                return true;
+
+            switch (type.TypeSig.ElementType)
             {
-                case StackTypeCode.Int32:
-                case StackTypeCode.Int64:
-                case StackTypeCode.NativeInt:
-                case StackTypeCode.F:
-                    return false;
-                case StackTypeCode.O:
-                case StackTypeCode.Ref:
+                case ElementType.Object:
+                case ElementType.SZArray:
+                case ElementType.Array:
+                case ElementType.String:
+                case ElementType.ByRef:
+                case ElementType.Ptr:
                     return true;
                 default:
-                    throw new NotSupportedException();
+                    return false;
             }
         }
+
+        public static bool IsSameType(TypeSig destType, StackType type, IList<TypeSig> genArgs = null)
+        {
+            if (destType != type.TypeSig)
+            {
+                if (EscapeVariableTypeName(destType, genArgs: genArgs) != type.Name)
+                {
+                    if (EscapeVariableTypeName(destType, genArgs: genArgs) !=
+                        EscapeVariableTypeName(type.TypeSig, genArgs: genArgs))
+                        return false;
+                }
+            }
+
+            return true;
+        }
     }
 }

+ 226 - 2
src/System.Private.CoreLib/System/Int16.cs

@@ -2,13 +2,237 @@
 // 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.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
 namespace System
 {
-    public struct Int16
+    [Serializable]
+    [StructLayout(LayoutKind.Sequential)]
+    [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public readonly struct Int16 : IComparable, IFormattable, IComparable<short>, IEquatable<short>, ISpanFormattable
     {
-        private short m_value; // Do not rename (binary serialization)
+        private readonly short m_value; // Do not rename (binary serialization)
 
         public const short MaxValue = (short)0x7FFF;
         public const short MinValue = unchecked((short)0x8000);
+
+        // 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 Int16, this method throws an ArgumentException.
+        // 
+        public int CompareTo(object value)
+        {
+            if (value == null)
+            {
+                return 1;
+            }
+
+            if (value is short)
+            {
+                return m_value - ((short)value).m_value;
+            }
+
+            throw new ArgumentException(SR.Arg_MustBeInt16);
+        }
+
+        public int CompareTo(short value)
+        {
+            return m_value - value;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is short))
+            {
+                return false;
+            }
+            return m_value == ((short)obj).m_value;
+        }
+
+        [NonVersionable]
+        public bool Equals(short obj)
+        {
+            return m_value == obj;
+        }
+
+        // Returns a HashCode for the Int16
+        public override int GetHashCode()
+        {
+            return ((int)((ushort)m_value) | (((int)m_value) << 16));
+        }
+
+
+        public override string ToString()
+        {
+            return Number.FormatInt32(m_value, null, null);
+        }
+
+        public string ToString(IFormatProvider provider)
+        {
+            return Number.FormatInt32(m_value, null, provider);
+        }
+
+        public string ToString(string format)
+        {
+            return ToString(format, null);
+        }
+
+        public string ToString(string format, IFormatProvider provider)
+        {
+            if (m_value < 0 && format != null && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            {
+                uint temp = (uint)(m_value & 0x0000FFFF);
+                return Number.FormatUInt32(temp, format, provider);
+            }
+
+            return Number.FormatInt32(m_value, format, provider);
+        }
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
+        {
+            if (m_value < 0 && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            {
+                uint temp = (uint)(m_value & 0x0000FFFF);
+                return Number.TryFormatUInt32(temp, format, provider, destination, out charsWritten);
+            }
+            return Number.TryFormatInt32(m_value, format, provider, destination, out charsWritten);
+        }
+
+        public static short Parse(string s)
+        {
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+        }
+
+        public static short Parse(string s, NumberStyles style)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
+        }
+
+        public static short Parse(string s, IFormatProvider provider)
+        {
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+        }
+
+        public static short Parse(string s, NumberStyles style, IFormatProvider provider)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
+        }
+
+        public static short Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            return Parse(s, style, NumberFormatInfo.GetInstance(provider));
+        }
+
+        private static short Parse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
+        {
+            int i = 0;
+            try
+            {
+                i = Number.ParseInt32(s, style, info);
+            }
+            catch (OverflowException e)
+            {
+                throw new OverflowException(SR.Overflow_Int16, e);
+            }
+
+            // We need this check here since we don't allow signs to specified in hex numbers. So we fixup the result
+            // for negative numbers
+            if ((style & NumberStyles.AllowHexSpecifier) != 0)
+            { // We are parsing a hexadecimal number
+                if ((i < 0) || (i > ushort.MaxValue))
+                {
+                    throw new OverflowException(SR.Overflow_Int16);
+                }
+                return (short)i;
+            }
+
+            if (i < MinValue || i > MaxValue) throw new OverflowException(SR.Overflow_Int16);
+            return (short)i;
+        }
+
+        public static bool TryParse(string s, out short result)
+        {
+            if (s == null)
+            {
+                result = 0;
+                return false;
+            }
+
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+        }
+
+        public static bool TryParse(ReadOnlySpan<char> s, out short result)
+        {
+            return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+        }
+
+        public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out short result)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+
+            if (s == null)
+            {
+                result = 0;
+                return false;
+            }
+
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
+        }
+
+        public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out short result)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
+        }
+
+        private static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out short result)
+        {
+            result = 0;
+            int i;
+            if (!Number.TryParseInt32(s, style, info, out i))
+            {
+                return false;
+            }
+
+            // We need this check here since we don't allow signs to specified in hex numbers. So we fixup the result
+            // for negative numbers
+            if ((style & NumberStyles.AllowHexSpecifier) != 0)
+            { // We are parsing a hexadecimal number
+                if ((i < 0) || i > ushort.MaxValue)
+                {
+                    return false;
+                }
+                result = (short)i;
+                return true;
+            }
+
+            if (i < MinValue || i > MaxValue)
+            {
+                return false;
+            }
+            result = (short)i;
+            return true;
+        }
+
+        //
+        // IConvertible implementation
+        // 
+
+        public TypeCode GetTypeCode()
+        {
+            return TypeCode.Int16;
+        }
     }
 }

+ 245 - 2
src/System.Private.CoreLib/System/SByte.cs

@@ -2,13 +2,256 @@
 // 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.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
 namespace System
 {
-    public struct SByte
+    [Serializable]
+    [CLSCompliant(false)]
+    [StructLayout(LayoutKind.Sequential)]
+    [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    public readonly struct SByte : IComparable, IFormattable, IComparable<sbyte>, IEquatable<sbyte>, ISpanFormattable
     {
-        private sbyte m_value; // Do not rename (binary serialization)
+        private readonly sbyte m_value; // Do not rename (binary serialization)
 
+        // The maximum value that a Byte may represent: 127.
         public const sbyte MaxValue = (sbyte)0x7F;
+
+        // The minimum value that a Byte may represent: -128.
         public const sbyte MinValue = unchecked((sbyte)0x80);
+
+
+        // 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 SByte, this method throws an ArgumentException.
+        // 
+        public int CompareTo(object obj)
+        {
+            if (obj == null)
+            {
+                return 1;
+            }
+            if (!(obj is sbyte))
+            {
+                throw new ArgumentException(SR.Arg_MustBeSByte);
+            }
+            return m_value - ((sbyte)obj).m_value;
+        }
+
+        public int CompareTo(sbyte value)
+        {
+            return m_value - value;
+        }
+
+        // Determines whether two Byte objects are equal.
+        public override bool Equals(object obj)
+        {
+            if (!(obj is sbyte))
+            {
+                return false;
+            }
+            return m_value == ((sbyte)obj).m_value;
+        }
+
+        [NonVersionable]
+        public bool Equals(sbyte obj)
+        {
+            return m_value == obj;
+        }
+
+        // Gets a hash code for this instance.
+        public override int GetHashCode()
+        {
+            return ((int)m_value ^ (int)m_value << 8);
+        }
+
+
+        // Provides a string representation of a byte.
+        public override string ToString()
+        {
+            return Number.FormatInt32(m_value, null, null);
+        }
+
+        public string ToString(IFormatProvider provider)
+        {
+            return Number.FormatInt32(m_value, null, provider);
+        }
+
+        public string ToString(string format)
+        {
+            return ToString(format, null);
+        }
+
+        public string ToString(string format, IFormatProvider provider)
+        {
+            if (m_value < 0 && format != null && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            {
+                uint temp = (uint)(m_value & 0x000000FF);
+                return Number.FormatUInt32(temp, format, provider);
+            }
+            return Number.FormatInt32(m_value, format, provider);
+        }
+
+        public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
+        {
+            if (m_value < 0 && format.Length > 0 && (format[0] == 'X' || format[0] == 'x'))
+            {
+                uint temp = (uint)(m_value & 0x000000FF);
+                return Number.TryFormatUInt32(temp, format, provider, destination, out charsWritten);
+            }
+            return Number.TryFormatInt32(m_value, format, provider, destination, out charsWritten);
+        }
+
+        [CLSCompliant(false)]
+        public static sbyte Parse(string s)
+        {
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+        }
+
+        [CLSCompliant(false)]
+        public static sbyte Parse(string s, NumberStyles style)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.CurrentInfo);
+        }
+
+        [CLSCompliant(false)]
+        public static sbyte Parse(string s, IFormatProvider provider)
+        {
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+        }
+
+        // Parses a signed byte from a String in the given style.  If
+        // a NumberFormatInfo isn't specified, the current culture's 
+        // NumberFormatInfo is assumed.
+        // 
+        [CLSCompliant(false)]
+        public static sbyte Parse(string s, NumberStyles style, IFormatProvider provider)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider));
+        }
+
+        [CLSCompliant(false)]
+        public static sbyte Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            return Parse(s, style, NumberFormatInfo.GetInstance(provider));
+        }
+
+        private static sbyte Parse(string s, NumberStyles style, NumberFormatInfo info)
+        {
+            if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+            return Parse((ReadOnlySpan<char>)s, style, info);
+        }
+
+        private static sbyte Parse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
+        {
+            int i = 0;
+            try
+            {
+                i = Number.ParseInt32(s, style, info);
+            }
+            catch (OverflowException e)
+            {
+                throw new OverflowException(SR.Overflow_SByte, e);
+            }
+
+            if ((style & NumberStyles.AllowHexSpecifier) != 0)
+            { // We are parsing a hexadecimal number
+                if ((i < 0) || i > byte.MaxValue)
+                {
+                    throw new OverflowException(SR.Overflow_SByte);
+                }
+                return (sbyte)i;
+            }
+
+            if (i < MinValue || i > MaxValue) throw new OverflowException(SR.Overflow_SByte);
+            return (sbyte)i;
+        }
+
+        [CLSCompliant(false)]
+        public static bool TryParse(string s, out sbyte result)
+        {
+            if (s == null)
+            {
+                result = 0;
+                return false;
+            }
+
+            return TryParse((ReadOnlySpan<char>)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+        }
+
+        [CLSCompliant(false)]
+        public static bool TryParse(ReadOnlySpan<char> s, out sbyte result)
+        {
+            return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+        }
+
+        [CLSCompliant(false)]
+        public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out sbyte result)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+
+            if (s == null)
+            {
+                result = 0;
+                return false;
+            }
+
+            return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
+        }
+
+        [CLSCompliant(false)]
+        public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out sbyte result)
+        {
+            NumberFormatInfo.ValidateParseStyleInteger(style);
+            return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
+        }
+
+        private static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out sbyte result)
+        {
+            result = 0;
+            int i;
+            if (!Number.TryParseInt32(s, style, info, out i))
+            {
+                return false;
+            }
+
+            if ((style & NumberStyles.AllowHexSpecifier) != 0)
+            { // We are parsing a hexadecimal number
+                if ((i < 0) || i > byte.MaxValue)
+                {
+                    return false;
+                }
+                result = (sbyte)i;
+                return true;
+            }
+
+            if (i < MinValue || i > MaxValue)
+            {
+                return false;
+            }
+            result = (sbyte)i;
+            return true;
+        }
+
+        //
+        // IConvertible implementation
+        // 
+
+        public TypeCode GetTypeCode()
+        {
+            return TypeCode.SByte;
+        }
     }
 }

+ 4 - 0
src/System.Private.CoreLib/System/ValueType.cs

@@ -18,5 +18,9 @@ namespace System
 {
     public abstract class ValueType
     {
+        public override string ToString()
+        {
+            return base.ToString();
+        }
     }
 }