Selaa lähdekoodia

Add string literal

Guo Hui 6 vuotta sitten
vanhempi
sitoutus
9e84613c6e

+ 36 - 16
src/Native/natsu.runtime.h

@@ -302,7 +302,7 @@ namespace stack
         template <class TTo>
         struct stack_to_impl<O, gc_obj_ref<TTo>>
         {
-            gc_obj_ref<TTo> operator()(const O &value) const noexcept
+            constexpr gc_obj_ref<TTo> operator()(const O &value) const noexcept
             {
                 return gc_obj_ref<TTo>(reinterpret_cast<TTo *>(value.value_));
             }
@@ -437,7 +437,7 @@ namespace stack
             {
                 using ::System_Private_CorLib::System::Object;
 
-                check_null_obj_ref(obj);
+                // 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));
@@ -483,7 +483,7 @@ namespace stack
             {
                 using ::System_Private_CorLib::System::Object;
 
-                check_null_obj_ref(obj);
+                // check_null_obj_ref(obj);
                 auto box = stack_to<gc_obj_ref<Object>>(obj).template as<T>();
                 if (box)
                 {
@@ -555,7 +555,7 @@ namespace stack
         {
             O operator()(const O &obj) const noexcept
             {
-                check_null_obj_ref(obj);
+                // check_null_obj_ref(obj);
                 if (obj.header().vtable_as<typename T::VTable>())
                     return obj;
                 throw_invalid_cast_exception();
@@ -931,13 +931,11 @@ namespace ops
     inline value_type ldelem_##name(const stack::O &obj, stack::int32 index)                        \
     {                                                                                               \
         using ::System_Private_CorLib::System::SZArray_1;                                           \
-        check_null_obj_ref(obj);                                                                    \
         return stack_from(stack_to<gc_obj_ref<SZArray_1<type>>>(obj)->at((uint32_t)index.value_));  \
     }                                                                                               \
     inline value_type ldelem_##name(const stack::O &obj, stack::native_int index)                   \
     {                                                                                               \
         using ::System_Private_CorLib::System::SZArray_1;                                           \
-        check_null_obj_ref(obj);                                                                    \
         return stack_from(stack_to<gc_obj_ref<SZArray_1<type>>>(obj)->at((uintptr_t)index.value_)); \
     }
 
@@ -958,7 +956,6 @@ namespace ops
     {
         using ::System_Private_CorLib::System::Object;
         using ::System_Private_CorLib::System::SZArray_1;
-        check_null_obj_ref(obj);
         return stack_from(stack_to<gc_obj_ref<SZArray_1<gc_obj_ref<Object>>>>(obj)->at((uint32_t)index.value_));
     }
 
@@ -966,7 +963,6 @@ namespace ops
     {
         using ::System_Private_CorLib::System::Object;
         using ::System_Private_CorLib::System::SZArray_1;
-        check_null_obj_ref(obj);
         return stack_from(stack_to<gc_obj_ref<SZArray_1<gc_obj_ref<Object>>>>(obj)->at((uintptr_t)index.value_));
     }
 
@@ -975,7 +971,6 @@ namespace ops
     {
         using ::System_Private_CorLib::System::Object;
         using ::System_Private_CorLib::System::SZArray_1;
-        check_null_obj_ref(obj);
         return stack_from(stack_to<gc_obj_ref<SZArray_1<T>>>(obj)->at((uint32_t)index.value_));
     }
 
@@ -984,7 +979,6 @@ namespace ops
     {
         using ::System_Private_CorLib::System::Object;
         using ::System_Private_CorLib::System::SZArray_1;
-        check_null_obj_ref(obj);
         return stack_from(stack_to<gc_obj_ref<SZArray_1<T>>>(obj)->at((uintptr_t)index.value_));
     }
 
@@ -994,7 +988,6 @@ namespace ops
     inline void stelem_##name(const stack::O &obj, stack::int32 index, value_type value)                \
     {                                                                                                   \
         using ::System_Private_CorLib::System::SZArray_1;                                               \
-        check_null_obj_ref(obj);                                                                        \
         stack_to<gc_obj_ref<SZArray_1<type>>>(obj)->at(index.value_) = static_cast<cast>(value.value_); \
     }
 
@@ -1010,7 +1003,6 @@ namespace ops
     {
         using ::System_Private_CorLib::System::Object;
         using ::System_Private_CorLib::System::SZArray_1;
-        check_null_obj_ref(obj);
         stack_to<gc_obj_ref<SZArray_1<gc_obj_ref<Object>>>>(obj)->at(index.value_) = stack_to<gc_obj_ref<Object>>(value);
     }
 
@@ -1019,12 +1011,10 @@ namespace ops
 #define LDIND_IMPL(name, type, ret, cast)                                 \
     inline ret ldind_##name(stack::native_int addr)                       \
     {                                                                     \
-        check_null_obj_ref(addr);                                         \
         return static_cast<cast>(*reinterpret_cast<type *>(addr.value_)); \
     }                                                                     \
     inline ret ldind_##name(stack::Ref addr)                              \
     {                                                                     \
-        check_null_obj_ref(addr);                                         \
         return static_cast<cast>(*reinterpret_cast<type *>(addr.value_)); \
     }
 
@@ -1045,12 +1035,10 @@ namespace ops
 #define STIND_IMPL(name, type, value_type)                                        \
     inline void stind_##name(stack::native_int addr, value_type value)            \
     {                                                                             \
-        check_null_obj_ref(addr);                                                 \
         *reinterpret_cast<type *>(addr.value_) = static_cast<type>(value.value_); \
     }                                                                             \
     inline void stind_##name(stack::Ref addr, value_type value)                   \
     {                                                                             \
-        check_null_obj_ref(addr);                                                 \
         *reinterpret_cast<type *>(addr.value_) = static_cast<type>(value.value_); \
     }
 
@@ -1312,6 +1300,38 @@ gc_ref<T> unbox_exact(gc_obj_ref<::System_Private_CorLib::System::Object> value)
     auto box = value.cast<T>();
     return gc_ref_from_ref(*box);
 }
+
+template <size_t N>
+struct string_literal : public System_Private_CorLib::System::Object
+{
+    ::System_Private_CorLib::System::Int32 _stringLength;
+    ::System_Private_CorLib::System::Char _firstChar[N + 1];
+
+    constexpr string_literal(const char16_t *str)
+        : _stringLength((int32_t)N)
+    {
+        for (size_t i = 0; i < N; i++)
+            _firstChar[i] = str[i];
+        _firstChar[N] = 0;
+    }
+};
+
+template <class TObject, class TValue>
+struct static_object
+{
+    object_header header_;
+    TValue value_;
+
+    constexpr static_object(TValue value)
+        : header_({ OBJ_ATTR_NONE, &vtable_holder<typename TObject::VTable>::get() }), value_(value)
+    {
+    }
+
+    constexpr gc_obj_ref<TObject> get() const noexcept
+    {
+        return gc_obj_ref<TObject>(reinterpret_cast<TObject *>(const_cast<TValue *>(&value_)));
+    }
+};
 }
 
 namespace System_Private_CorLib

+ 23 - 26
src/Native/natsu.typedef.h

@@ -87,7 +87,7 @@ struct vtable_holder
 {
     static const T value;
 
-    static const T &get()
+    static constexpr const T &get()
     {
         return value;
     }
@@ -123,6 +123,7 @@ struct object_header
         return dynamic_cast<const TVTable *>(vtable_);
     }
 };
+
 template <class T>
 constexpr bool is_value_type_v = T::TypeInfo::IsValueType;
 
@@ -569,29 +570,25 @@ struct vtable_class : public TBase, public vtable_impl_t<TBase, TIFaces>...
 
 #define NATSU_PRIMITIVE_OPERATORS_IMPL
 
-#define NATSU_SZARRAY_IMPL                                 \
-    T &at(size_t index)                                    \
-    {                                                      \
-        if (index >= length())                             \
-            ::natsu::throw_index_out_of_range_exception(); \
-        return elements_[index];                           \
-    }                                                      \
-    ::natsu::gc_ref<T> ref_at(size_t index)                \
-    {                                                      \
-        if (index >= length())                             \
-            ::natsu::throw_index_out_of_range_exception(); \
-        return ::natsu::gc_ref_from_ref(elements_[index]); \
-    }                                                      \
-    T get(int index)                                       \
-    {                                                      \
-        return at(index);                                  \
-    }                                                      \
-    void set(int index, T value)                           \
-    {                                                      \
-        at(index) = value;                                 \
-    }                                                      \
-    uintptr_t length() const noexcept                      \
-    {                                                      \
-        return Length.m_value;                             \
-    }                                                      \
+#define NATSU_SZARRAY_IMPL                                                                \
+    constexpr T &at(size_t index)                                                         \
+    {                                                                                     \
+        return elements_[index];                                                          \
+    }                                                                                     \
+    constexpr ::natsu::gc_ref<T> ref_at(size_t index)                                     \
+    {                                                                                     \
+        return ::natsu::gc_ref_from_ref(elements_[index]);                                \
+    }                                                                                     \
+    constexpr T get(int index)                                                            \
+    {                                                                                     \
+        return at(index);                                                                 \
+    }                                                                                     \
+    constexpr void set(int index, T value)                                                \
+    {                                                                                     \
+        at(index) = value;                                                                \
+    }                                                                                     \
+    constexpr uintptr_t length() const noexcept                                           \
+    {                                                                                     \
+        return Length.m_value;                                                            \
+    }                                                                                     \
     T elements_[0];

+ 10 - 4
src/Natsu.Compiler/ILImporter.cs

@@ -13,12 +13,15 @@ namespace Natsu.Compiler
     {
         private BasicBlock _headBlock;
         private BlockGraph _blockGraph = new BlockGraph();
-        private readonly StreamWriter _writer;
+        private readonly TextWriter _writer;
         private readonly int _ident;
         private readonly MethodDef _method;
         private List<SpillSlot> _spillSlots = new List<SpillSlot>();
 
-        public ILImporter(MethodDef method, StreamWriter writer, int ident)
+        public List<string> UserStrings { get; set; }
+        public string ModuleName { get; set; }
+
+        public ILImporter(MethodDef method, TextWriter writer, int ident)
         {
             _method = method;
             _writer = writer;
@@ -215,7 +218,7 @@ namespace Natsu.Compiler
 
         private void WriteInstruction(TextWriter writer, Instruction op, EvaluationStack stack, int ident, BasicBlock block)
         {
-            var emitter = new OpEmitter { Method = _method, Op = op, Stack = stack, Ident = ident, Block = block, Writer = writer };
+            var emitter = new OpEmitter { ModuleName = ModuleName, UserStrings = UserStrings, Method = _method, Op = op, Stack = stack, Ident = ident, Block = block, Writer = writer };
             bool isSpecial = true;
 
             if (op.IsLdarg())
@@ -685,6 +688,8 @@ namespace Natsu.Compiler
         public BasicBlock Block { get; set; }
         public MethodDef Method { get; set; }
         public TextWriter Writer { get; set; }
+        public string ModuleName { get; set; }
+        public List<string> UserStrings { get; set; }
 
         // Unary
 
@@ -1032,7 +1037,8 @@ namespace Natsu.Compiler
         public void Ldstr()
         {
             var value = (string)Op.Operand;
-            Stack.Push(StackTypeCode.O, $"::natsu::stack_from(::natsu::load_string(uR\"NS({value})NS\"sv))");
+            Stack.Push(StackTypeCode.O, $"::natsu::stack_from(::{ModuleName}::user_string_{UserStrings.Count}.get())");
+            UserStrings.Add(value);
         }
 
         public void Ldsfld()

+ 44 - 23
src/Natsu.Compiler/Program.cs

@@ -38,13 +38,14 @@ namespace Natsu.Compiler
 
     class Generator
     {
-        private readonly ModuleDef _module;
+        private readonly ModuleDefMD _module;
         private readonly Dictionary<TypeDef, TypeDesc> _typeDescs = new Dictionary<TypeDef, TypeDesc>();
         private readonly List<TypeDesc> _sortedTypeDescs = new List<TypeDesc>();
         private readonly CorLibTypes _corLibTypes;
         private TypeDesc _szArrayType;
+        private List<string> _userStrings = new List<string>();
 
-        public Generator(ModuleDef module)
+        public Generator(ModuleDefMD module)
         {
             _module = module;
             _corLibTypes = new CorLibTypes(module);
@@ -103,24 +104,44 @@ namespace Natsu.Compiler
                     writer.WriteLine();
                 }
 
+                using (var writerSrc = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.cpp"), false, Encoding.UTF8))
+                {
+                    writerSrc.WriteLine("// Generated by natsu clr compiler.");
+                    writerSrc.WriteLine($"#include \"{_module.Assembly.Name}.h\"");
+                    writerSrc.WriteLine();
+
+                    writerSrc.WriteLine($"namespace {TypeUtils.EscapeModuleName(_module)}");
+                    writerSrc.WriteLine("{");
+                    WriteTypeMethodsBody(writerSrc, false);
+                    WriteConstantStringFields(writerSrc);
+                    writerSrc.WriteLine("}");
+                }
+
+                var hBody = new StringWriter();
+
+                hBody.WriteLine($"namespace {TypeUtils.EscapeModuleName(_module)}");
+                hBody.WriteLine("{");
+                WriteTypeMethodsBody(hBody, true);
+                hBody.WriteLine("}");
+
                 writer.WriteLine($"namespace {TypeUtils.EscapeModuleName(_module)}");
                 writer.WriteLine("{");
-                WriteTypeMethodsBody(writer, true);
+                WriteUserStrings(writer);
                 writer.WriteLine("}");
-            }
 
-            using (var writer = new StreamWriter(Path.Combine(outputPath, $"{_module.Assembly.Name}.cpp"), false, Encoding.UTF8))
-            {
-                writer.WriteLine("// Generated by natsu clr compiler.");
-                writer.WriteLine($"#include \"{_module.Assembly.Name}.h\"");
                 writer.WriteLine();
+                writer.WriteLine(hBody.ToString());
+            }
+        }
 
-                writer.WriteLine($"namespace {TypeUtils.EscapeModuleName(_module)}");
-                writer.WriteLine("{");
-                WriteTypeMethodsBody(writer, false);
-                WriteConstantStringFields(writer);
-                writer.WriteLine("}");
+        private void WriteUserStrings(StreamWriter writer)
+        {
+            for (int i = 0; i < _userStrings.Count; i++)
+            {
+                writer.Ident(1).WriteLine($"static const natsu::static_object<::System_Private_CorLib::System::String, natsu::string_literal<{_userStrings[i].Length}>> user_string_{i}(uR\"NS({_userStrings[i]})NS\");");
             }
+
+            writer.WriteLine();
         }
 
         private void WriteConstantStringFields(StreamWriter writer)
@@ -587,7 +608,7 @@ namespace Natsu.Compiler
             writer.Ident(ident).WriteLine($"{TypeUtils.EscapeVariableTypeName(value.FieldType, value.DeclaringType)} {TypeUtils.EscapeTypeName(value.DeclaringType, hasModuleName: false)}::{TypeUtils.EscapeIdentifier(value.Name)} = ::natsu::load_string(uR\"NS({value.Constant.Value})NS\"sv);");
         }
 
-        private void WriteMethodDeclare(StreamWriter writer, int ident, MethodDef method)
+        private void WriteMethodDeclare(TextWriter writer, int ident, MethodDef method)
         {
             var methodGens = new List<string>();
 
@@ -605,7 +626,7 @@ namespace Natsu.Compiler
             writer.WriteLine($");");
         }
 
-        private void WriteParameterList(StreamWriter writer, ParameterList parameters, bool hasType = true, bool isVTable = false)
+        private void WriteParameterList(TextWriter writer, ParameterList parameters, bool hasType = true, bool isVTable = false)
         {
             var index = 0;
             var method = parameters.Method;
@@ -651,7 +672,7 @@ namespace Natsu.Compiler
         }
         #endregion
 
-        private void WriteTypeMethodsBody(StreamWriter writer, bool inHeader)
+        private void WriteTypeMethodsBody(TextWriter writer, bool inHeader)
         {
             foreach (var type in _sortedTypeDescs)
             {
@@ -659,7 +680,7 @@ namespace Natsu.Compiler
             }
         }
 
-        private void WriteTypeMethodBody(StreamWriter writer, int ident, TypeDesc type, bool inHeader)
+        private void WriteTypeMethodBody(TextWriter writer, int ident, TypeDesc type, bool inHeader)
         {
             foreach (var method in type.TypeDef.Methods)
             {
@@ -681,7 +702,7 @@ namespace Natsu.Compiler
             }
         }
 
-        private void WriteMethodBody(StreamWriter writer, int ident, MethodDef method)
+        private void WriteMethodBody(TextWriter writer, int ident, MethodDef method)
         {
             writer.Ident(ident);
             var typeGens = new List<string>();
@@ -709,7 +730,7 @@ namespace Natsu.Compiler
             writer.Flush();
         }
 
-        private void WriteVTableMethodDeclare(StreamWriter writer, int ident, MethodDef method)
+        private void WriteVTableMethodDeclare(TextWriter writer, int ident, MethodDef method)
         {
             writer.Ident(ident);
 
@@ -752,7 +773,7 @@ namespace Natsu.Compiler
             writer.Flush();
         }
 
-        private void WriteVTableMethodBody(StreamWriter writer, int ident, MethodDef method)
+        private void WriteVTableMethodBody(TextWriter writer, int ident, MethodDef method)
         {
             writer.Ident(ident);
             var typeGens = new List<string>();
@@ -791,7 +812,7 @@ namespace Natsu.Compiler
             writer.Flush();
         }
 
-        private void WriteILBody(StreamWriter writer, int ident, MethodDef method)
+        private void WriteILBody(TextWriter writer, int ident, MethodDef method)
         {
             var body = method.Body;
 
@@ -801,12 +822,12 @@ namespace Natsu.Compiler
             }
 
             //Console.WriteLine(method);
-            var importer = new ILImporter(method, writer, ident);
+            var importer = new ILImporter(method, writer, ident) { UserStrings = _userStrings, ModuleName = TypeUtils.EscapeModuleName(_module.Assembly) };
             importer.ImportBlocks(body.Instructions);
             importer.Gencode();
         }
 
-        private void WriteLocal(Local local, StreamWriter writer, int ident, MethodDef method)
+        private void WriteLocal(Local local, TextWriter writer, int ident, MethodDef method)
         {
             writer.Ident(ident).WriteLine($"{TypeUtils.EscapeVariableTypeName(local.Type)} _l{local.Index};");
         }