Guo Hui 6 years ago
parent
commit
74c32b36af

+ 27 - 0
src/Chino.Core/SystemServices.cs

@@ -0,0 +1,27 @@
+using Chino.Threading;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Chino
+{
+    public static class SystemServices
+    {
+        private static ISystemServices _services;
+        public static IScheduler Scheduler => _services.Scheduler;
+
+        static SystemServices()
+        {
+            Initialize();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private extern static void Initialize();
+    }
+
+    internal interface ISystemServices
+    {
+        IScheduler Scheduler { get; }
+    }
+}

+ 1 - 0
src/Chino.Core/Threading/IScheduler.cs

@@ -6,5 +6,6 @@ namespace Chino.Threading
 {
     public interface IScheduler
     {
+        ulong TickCount { get; }
     }
 }

+ 1 - 0
src/Native/CMakeLists.txt

@@ -9,6 +9,7 @@ set(SRCS natsu.fcall.cpp
          natsu.gc.cpp
          natsu.unicode.cpp
          natsu.threading.cpp
+         chino.runtime.cpp
          main.cpp
          Generated/System.Private.CoreLib.cpp
          Generated/System.Collections.cpp

+ 13 - 0
src/Native/chino.runtime.cpp

@@ -0,0 +1,13 @@
+#include "Chino.Kernel.h"
+#include <cmath>
+#include <cstring>
+
+using namespace natsu;
+using namespace Chino_Core::Chino;
+using namespace System_Runtime::System;
+
+void SystemServices::_s_Initialize()
+{
+    auto &s_fields = static_holder<typename SystemServices::Static>::get();
+    //s_fields._scheduler = null;
+}

+ 74 - 0
src/Native/natsu.fcall.cpp

@@ -8,6 +8,7 @@ using namespace System_Private_CoreLib::System;
 using namespace System_Private_CoreLib::System::Diagnostics;
 using namespace System_Private_CoreLib::System::Runtime;
 using namespace System_Private_CoreLib::System::Runtime::CompilerServices;
+using namespace System_Private_CoreLib::System::Threading;
 
 int32_t Array::GetLength(gc_obj_ref<Array> _this, int32_t dimension)
 {
@@ -269,3 +270,76 @@ void Environment::_s__Exit(int32_t exitCode)
 {
     exit(exitCode);
 }
+
+int32_t Environment::_s_get_TickCount()
+{
+    return (int32_t)_s_get_TickCount64();
+}
+
+int64_t Environment::_s_get_TickCount64()
+{
+    using namespace Chino_Core::Chino;
+    using namespace Chino_Core::Chino::Threading;
+
+    auto scheduler = SystemServices::_s_get_Scheduler().cast<Object>();
+    return (int64_t)scheduler.header().vtable_as<typename IScheduler::VTable>()->get_TickCount_(scheduler);
+}
+
+void Monitor::_s_Enter(gc_obj_ref<Object> obj)
+{
+}
+
+void Monitor::_s_ReliableEnter(gc_obj_ref<Object> obj, gc_ref<bool> lockTaken)
+{
+    *lockTaken = true;
+}
+
+void Monitor::_s_Exit(::natsu::gc_obj_ref<Object> obj)
+{
+}
+
+void Monitor::_s_ReliableEnterTimeout(gc_obj_ref<Object> obj, int32_t timeout, gc_ref<bool> lockTaken)
+{
+    *lockTaken = true;
+}
+
+bool Monitor::_s_IsEnteredNative(gc_obj_ref<Object> obj)
+{
+    return true;
+}
+
+bool Monitor::_s_ObjWait(bool exitContext, int32_t millisecondsTimeout, gc_obj_ref<Object> obj)
+{
+    return true;
+}
+
+void Monitor::_s_ObjPulse(gc_obj_ref<Object> obj)
+{
+}
+
+void Monitor::_s_ObjPulseAll(gc_obj_ref<Object> obj)
+{
+}
+
+int64_t Monitor::_s_GetLockContentionCount()
+{
+    return 0;
+}
+
+void Thread::_s_SleepInternal(int32_t millisecondsTimeout)
+{
+}
+
+void Thread::_s_SpinWaitInternal(int32_t iterations)
+{
+}
+
+bool Thread::_s_YieldInternal()
+{
+    return true;
+}
+
+int32_t Thread::_s_GetOptimalMaxSpinWaitsPerSpinIterationInternal()
+{
+    return 1;
+}

+ 25 - 0
src/Native/natsu.runtime.h

@@ -3,6 +3,7 @@
 #include "natsu.typedef.h"
 #include <cmath>
 #include <limits>
+#include <utility>
 #if _MSC_VER
 #include <malloc.h>
 #else
@@ -211,6 +212,30 @@ struct runtime_type_holder
     }
 };
 
+template <class TCall>
+class clr_finally
+{
+public:
+    clr_finally(TCall &&call)
+        : call_(std::forward<TCall>(call))
+    {
+    }
+
+    ~clr_finally()
+    {
+        call_();
+    }
+
+private:
+    TCall call_;
+};
+
+template <class TCall>
+clr_finally<TCall> make_finally(TCall &&call)
+{
+    return { std::forward<TCall>(call) };
+}
+
 template <class TFrom>
 auto stack_from(const TFrom &value);
 

+ 5 - 4
src/Natsu.Compiler/EvaluationStack.cs

@@ -43,16 +43,18 @@ namespace Natsu.Compiler
         private readonly Stack<StackEntry> _stackValues = new Stack<StackEntry>();
         private int _paramIndex = 0;
         private TextWriter _writer;
-        public int Ident { get; }
+        public int Ident { get; set; }
+        public int ParamIndex => _paramIndex;
 
         public ITypeDefOrRef Constrained { get; set; }
 
         public bool Empty => _stackValues.Count == 0;
 
-        public EvaluationStack(TextWriter writer, int ident)
+        public EvaluationStack(TextWriter writer, int ident, int paramIndex)
         {
             _writer = writer;
             Ident = ident;
+            _paramIndex = paramIndex;
         }
 
         public void SetWriter(TextWriter writer)
@@ -96,10 +98,9 @@ namespace Natsu.Compiler
 
         public EvaluationStack Clone(int identInc = 0)
         {
-            var stack = new EvaluationStack(_writer, Ident + identInc);
+            var stack = new EvaluationStack(_writer, Ident + identInc, _paramIndex);
             foreach (var value in _stackValues.Reverse())
                 stack._stackValues.Push(value);
-            stack._paramIndex = _paramIndex;
             return stack;
         }
     }

+ 114 - 34
src/Natsu.Compiler/ILImporter.cs

@@ -17,6 +17,9 @@ namespace Natsu.Compiler
         private readonly int _ident;
         private readonly MethodDef _method;
         private List<SpillSlot> _spillSlots = new List<SpillSlot>();
+        private Dictionary<ExceptionHandler, ExceptionHandlerContext> _exceptions = new Dictionary<ExceptionHandler, ExceptionHandlerContext>();
+        private int _paramIndex;
+        private int _blockId;
 
         public List<string> UserStrings { get; set; }
         public string ModuleName { get; set; }
@@ -28,9 +31,36 @@ namespace Natsu.Compiler
             _ident = ident;
         }
 
-        public void ImportBlocks(IList<Instruction> instructions)
+        public void ImportNormalBlocks()
+        {
+            _headBlock = ImportBlocks(_method.Body.Instructions, _method.Body.Instructions.FirstOrDefault());
+        }
+
+        public void ImportExceptionBlocks()
+        {
+            foreach (var handler in _method.Body.ExceptionHandlers)
+            {
+                var ctx = new ExceptionHandlerContext
+                {
+                    Handler = handler,
+                    HeadBlock = ImportBlocks(_method.Body.Instructions, handler.HandlerStart)
+                };
+
+                _exceptions.Add(handler, ctx);
+            }
+        }
+
+        Instruction PrevInst(Instruction inst)
+        {
+            var instructions = _method.Body.Instructions;
+            var index = instructions.IndexOf(inst);
+            if (index == 0)
+                return null;
+            return instructions[index - 1];
+        }
+
+        private BasicBlock ImportBlocks(IList<Instruction> instructions, Instruction firstInst)
         {
-            int id = 0;
             Instruction NextInst(Instruction inst)
             {
                 var index = instructions.IndexOf(inst);
@@ -43,9 +73,8 @@ namespace Natsu.Compiler
             {
                 if (inst == null) return null;
 
-                var block = new BasicBlock { Id = id++, Parent = parent };
+                var block = new BasicBlock { Id = _blockId++, Parent = parent };
                 _blockGraph.Blocks.Add(inst, block);
-                Debug.Assert(id < 3000);
                 bool conti = true;
 
                 void AddNext(Instruction next)
@@ -104,6 +133,8 @@ namespace Natsu.Compiler
                             break;
                         case Code.Ret:
                         case Code.Throw:
+                        case Code.Endfinally:
+                        case Code.Endfilter:
                             block.Instructions.Add(inst);
                             conti = false;
                             break;
@@ -127,21 +158,10 @@ namespace Natsu.Compiler
                 return block;
             }
 
-            if (instructions.Count != 0)
-                _headBlock = ImportBlock(null, instructions[0]);
+            if (firstInst != null)
+                return ImportBlock(null, firstInst);
             else
-                _headBlock = new BasicBlock { Id = 0 };
-        }
-
-        public void ImportExceptionHandlers(IReadOnlyCollection<ExceptionHandler> exceptionHandlers)
-        {
-            foreach (var handler in exceptionHandlers)
-            {
-                foreach (var block in _blockGraph.Blocks.Values)
-                {
-                    var idx = block.Instructions.IndexOf(handler.TryStart);
-                }
-            }
+                return new BasicBlock { Id = 0 };
         }
 
         internal void Gencode()
@@ -154,33 +174,40 @@ namespace Natsu.Compiler
                 _writer.Ident(_ident).WriteLine($"{TypeUtils.EscapeStackTypeName(spill.Entry.Type)} {spill.Name};");
 
             visited.Clear();
-            VisitBlockText(_headBlock, visited);
+            VisitBlockText(_headBlock, _writer, visited);
         }
 
 
-        private void VisitBlockText(BasicBlock block, HashSet<BasicBlock> visited)
+        private void VisitBlockText(BasicBlock block, TextWriter writer, HashSet<BasicBlock> visited)
         {
-            visited.Add(block);
-            _writer.Write(block.Text);
+            var blocks = new List<BasicBlock>();
+            void AddBlock(BasicBlock headBlock)
+            {
+                visited.Add(headBlock);
+                blocks.Add(headBlock);
+                foreach (var next in headBlock.Next)
+                {
+                    if (!visited.Contains(next))
+                        AddBlock(next);
+                }
+            }
 
-            foreach (var next in block.Next)
+            AddBlock(block);
+            foreach (var cntBlock in blocks.Where(x => x.Instructions.Any())
+                .OrderBy(x => x.Instructions[0].Offset))
             {
-                if (!visited.Contains(next))
-                    VisitBlockText(next, visited);
+                writer.Write(cntBlock.Text);
             }
         }
 
-        private void VisitBlock(int ident, BasicBlock block, HashSet<BasicBlock> visited)
+        private void VisitBlock(int ident, BasicBlock block, HashSet<BasicBlock> visited, StringWriter writer = null, EvaluationStack stack = null)
         {
             visited.Add(block);
 
-            var writer = new StringWriter();
-
-            var stack = new EvaluationStack(writer, _ident + 1);
+            writer = writer ?? new StringWriter();
+            stack = stack ?? new EvaluationStack(writer, ident, _paramIndex);
             writer.WriteLine(ILUtils.GetLabel(_method, block.Id) + ":");
 
-            writer.Ident(ident).WriteLine("{");
-
             // import spills
             if (block.Parent != null)
             {
@@ -193,7 +220,52 @@ namespace Natsu.Compiler
             {
                 var instW = new StringWriter();
                 stack.SetWriter(instW);
-                WriteInstruction(instW, op, stack, ident + 1, block);
+
+                var tryEnter = (from e in _exceptions
+                                where !e.Value.EnterProcessed && e.Key.TryStart == op
+                                select e).FirstOrDefault();
+                if (tryEnter.Key != null)
+                {
+                    EvaluationStack tryEnterStack = null;
+                    if (tryEnter.Key.HandlerType == ExceptionHandlerType.Finally)
+                    {
+                        if (_method.FullName.Contains("Concat"))
+                            ;
+                        instW.Ident(ident).WriteLine("{");
+                        ident += 1;
+                        stack.Ident = ident;
+                        instW.Ident(ident).WriteLine("auto _scope_finally = natsu::make_finally([&]{");
+                        VisitBlock(ident + 1, tryEnter.Value.HeadBlock, new HashSet<BasicBlock>(), stack: tryEnterStack);
+                        VisitBlockText(tryEnter.Value.HeadBlock, instW, visited);
+                        instW.Ident(ident).WriteLine("});");
+                        tryEnter.Value.EnterProcessed = true;
+                    }
+                    else if (tryEnter.Key.HandlerType == ExceptionHandlerType.Catch)
+                    {
+
+                    }
+                }
+
+                WriteInstruction(instW, op, stack, ident, block);
+
+                var tryExit = (from e in _exceptions
+                               where !e.Value.ExitProcessed && PrevInst(e.Key.TryEnd) == op
+                               select e).FirstOrDefault();
+                if (tryExit.Key != null)
+                {
+                    if (tryExit.Key.HandlerType == ExceptionHandlerType.Finally)
+                    {
+                        ident -= 1;
+                        stack.Ident = ident;
+                        instW.Ident(ident).WriteLine("}");
+                        tryExit.Value.ExitProcessed = true;
+                    }
+                    else if (tryExit.Key.HandlerType == ExceptionHandlerType.Catch)
+                    {
+
+                    }
+                }
+
                 instLines.Add(instW.ToString());
             }
 
@@ -204,14 +276,14 @@ namespace Natsu.Compiler
             while (block.Next.Count != 0 && !stack.Empty)
             {
                 var spill = AddSpillSlot(stack.Pop());
-                writer.Ident(ident + 1).WriteLine($"{spill.Name} = {spill.Entry.Expression};");
+                writer.Ident(ident).WriteLine($"{spill.Name} = {spill.Entry.Expression};");
                 block.Spills.Add(spill);
             }
 
             writer.Write(instLines.Last());
 
-            writer.Ident(ident).WriteLine("}");
             block.Text = writer.ToString();
+            _paramIndex = stack.ParamIndex;
 
             foreach (var next in block.Next)
             {
@@ -701,6 +773,14 @@ namespace Natsu.Compiler
                 }
             }
         }
+
+        private class ExceptionHandlerContext
+        {
+            public ExceptionHandler Handler;
+            public bool EnterProcessed;
+            public bool ExitProcessed;
+            public BasicBlock HeadBlock;
+        }
     }
 
     class OpEmitter

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

@@ -846,7 +846,7 @@ namespace Natsu.Compiler
                                 writer.WriteLine("_imp_" + TypeUtils.EscapeMethodName(method, hasExplicit: true) + ";");
                             }
                         }
-                        else if (!method.IsNewSlot)
+                        else if (!type.TypeDef.IsInterface)
                         {
                             writer.Ident(ident + 1).Write("base_t::override_vfunc");
                             writer.Write("(R\"NS(" + method.Name + ")NS\", ");
@@ -995,7 +995,8 @@ namespace Natsu.Compiler
             }
 
             var importer = new ILImporter(method, writer, ident) { UserStrings = _userStrings, ModuleName = TypeUtils.EscapeModuleName(_module.Assembly) };
-            importer.ImportBlocks(body.Instructions);
+            importer.ImportNormalBlocks();
+            importer.ImportExceptionBlocks();
             importer.Gencode();
         }
 

+ 1 - 0
src/System.Runtime/TypeForwards.cs

@@ -58,3 +58,4 @@ using System.Text;
 [assembly: TypeForwardedTo(typeof(ValueTuple<,,,,,,,>))]
 [assembly: TypeForwardedTo(typeof(Span<>))]
 [assembly: TypeForwardedTo(typeof(ReadOnlySpan<>))]
+[assembly: TypeForwardedTo(typeof(IDisposable))]