From 7ad8b3ef7556bd5cfc552cad90017ab2247ffa8c Mon Sep 17 00:00:00 2001
From: Chenj168 <62330325+Chenj168@users.noreply.github.com>
Date: Sun, 29 Mar 2020 16:52:56 +0800
Subject: [PATCH] Move the OpActivator to OpCodeTable class for improve
 performance (#1001)

* Move the OpActivator to OpCodeTable class, for reduce the use of ConcurrentDictionary

* Modify code style.
---
 Ryujinx.Graphics.Shader/Decoders/Decoder.cs   | 49 +++----------------
 .../Decoders/OpCodeTable.cs                   | 33 +++++++++++--
 2 files changed, 35 insertions(+), 47 deletions(-)

diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index cda88302a4..3e322e453e 100644
--- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -1,10 +1,8 @@
 using Ryujinx.Graphics.Shader.Instructions;
 using System;
 using System.Buffers.Binary;
-using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
-using System.Reflection.Emit;
 
 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
 
@@ -12,15 +10,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
 {
     static class Decoder
     {
-        private delegate object OpActivator(InstEmitter emitter, ulong address, long opCode);
-
-        private static ConcurrentDictionary<Type, OpActivator> _opActivators;
-
-        static Decoder()
-        {
-            _opActivators = new ConcurrentDictionary<Type, OpActivator>();
-        }
-
         public static Block[] Decode(ReadOnlySpan<byte> code, ulong headerSize)
         {
             List<Block> blocks = new List<Block>();
@@ -245,7 +234,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
 
                 long opCode = word0 | (long)word1 << 32;
 
-                (InstEmitter emitter, Type opCodeType) = OpCodeTable.GetEmitter(opCode);
+                (InstEmitter emitter, OpCodeTable.OpActivator opActivator) = OpCodeTable.GetEmitter(opCode);
 
                 if (emitter == null)
                 {
@@ -256,7 +245,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
                     continue;
                 }
 
-                OpCode op = MakeOpCode(opCodeType, emitter, opAddress, opCode);
+                if (opActivator == null)
+                {
+                    throw new ArgumentNullException(nameof(opActivator));
+                }
+
+                OpCode op = (OpCode)opActivator(emitter, opAddress, opCode);
 
                 block.OpCodes.Add(op);
             }
@@ -295,35 +289,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
             return opCode is OpCodeExit;
         }
 
-        private static OpCode MakeOpCode(Type type, InstEmitter emitter, ulong address, long opCode)
-        {
-            if (type == null)
-            {
-                throw new ArgumentNullException(nameof(type));
-            }
-
-            OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator);
-
-            return (OpCode)createInstance(emitter, address, opCode);
-        }
-
-        private static OpActivator CacheOpActivator(Type type)
-        {
-            Type[] argTypes = new Type[] { typeof(InstEmitter), typeof(ulong), typeof(long) };
-
-            DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes);
-
-            ILGenerator generator = mthd.GetILGenerator();
-
-            generator.Emit(OpCodes.Ldarg_0);
-            generator.Emit(OpCodes.Ldarg_1);
-            generator.Emit(OpCodes.Ldarg_2);
-            generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes));
-            generator.Emit(OpCodes.Ret);
-
-            return (OpActivator)mthd.CreateDelegate(typeof(OpActivator));
-        }
-
         private struct PathBlockState
         {
             public Block Block { get; }
diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index e71c31867e..9835be343c 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -1,10 +1,13 @@
 using Ryujinx.Graphics.Shader.Instructions;
 using System;
+using System.Reflection.Emit;
 
 namespace Ryujinx.Graphics.Shader.Decoders
 {
     static class OpCodeTable
     {
+        public delegate object OpActivator(InstEmitter emitter, ulong address, long opCode);
+
         private const int EncodingBits = 14;
 
         private class TableEntry
@@ -15,11 +18,31 @@ namespace Ryujinx.Graphics.Shader.Decoders
 
             public int XBits { get; }
 
+            public OpActivator OpActivator { get; }
+
             public TableEntry(InstEmitter emitter, Type opCodeType, int xBits)
             {
-                Emitter    = emitter;
-                OpCodeType = opCodeType;
-                XBits      = xBits;
+                Emitter     = emitter;
+                OpCodeType  = opCodeType;
+                XBits       = xBits;
+                OpActivator = CacheOpActivator(opCodeType);
+            }
+
+            private static OpActivator CacheOpActivator(Type type)
+            {
+                Type[] argTypes = new Type[] { typeof(InstEmitter), typeof(ulong), typeof(long) };
+
+                DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes);
+
+                ILGenerator generator = mthd.GetILGenerator();
+
+                generator.Emit(OpCodes.Ldarg_0);
+                generator.Emit(OpCodes.Ldarg_1);
+                generator.Emit(OpCodes.Ldarg_2);
+                generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes));
+                generator.Emit(OpCodes.Ret);
+
+                return (OpActivator)mthd.CreateDelegate(typeof(OpActivator));
             }
         }
 
@@ -266,13 +289,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
             }
         }
 
-        public static (InstEmitter emitter, Type opCodeType) GetEmitter(long opCode)
+        public static (InstEmitter emitter, OpActivator opActivator) GetEmitter(long opCode)
         {
             TableEntry entry = _opCodes[(ulong)opCode >> (64 - EncodingBits)];
 
             if (entry != null)
             {
-                return (entry.Emitter, entry.OpCodeType);
+                return (entry.Emitter, entry.OpActivator);
             }
 
             return (null, null);