Browse Source

Caching JsValue conversions (#325)

* Changing JsValue to a class
Sébastien Ros 9 years ago
parent
commit
94252532f0
2 changed files with 45 additions and 64 deletions
  1. 23 2
      Jint/Engine.cs
  2. 22 62
      Jint/Native/JsValue.cs

+ 23 - 2
Jint/Engine.cs

@@ -18,6 +18,7 @@ using Jint.Native.String;
 using Jint.Parser;
 using Jint.Parser;
 using Jint.Parser.Ast;
 using Jint.Parser.Ast;
 using Jint.Runtime;
 using Jint.Runtime;
+using Jint.Runtime.CallStack;
 using Jint.Runtime.Debugger;
 using Jint.Runtime.Debugger;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Environments;
@@ -26,8 +27,6 @@ using Jint.Runtime.References;
 
 
 namespace Jint
 namespace Jint
 {
 {
-    using Jint.Runtime.CallStack;
-
     public class Engine
     public class Engine
     {
     {
         private readonly ExpressionInterpreter _expressions;
         private readonly ExpressionInterpreter _expressions;
@@ -43,6 +42,28 @@ namespace Jint
         // cache of types used when resolving CLR type names
         // cache of types used when resolving CLR type names
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
 
 
+        internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new Dictionary<Type, Func<Engine, object, JsValue>>()
+        {
+            { typeof(bool), (Engine engine, object v) => new JsValue((bool)v) },
+            { typeof(byte), (Engine engine, object v) => new JsValue((byte)v) },
+            { typeof(char), (Engine engine, object v) => new JsValue((char)v) },
+            { typeof(DateTime), (Engine engine, object v) => engine.Date.Construct((DateTime)v) },
+            { typeof(DateTimeOffset), (Engine engine, object v) => engine.Date.Construct((DateTimeOffset)v) },
+            { typeof(decimal), (Engine engine, object v) => new JsValue((double)(decimal)v) },
+            { typeof(double), (Engine engine, object v) => new JsValue((double)v) },
+            { typeof(Int16), (Engine engine, object v) => new JsValue((Int16)v) },
+            { typeof(Int32), (Engine engine, object v) => new JsValue((Int32)v) },
+            { typeof(Int64), (Engine engine, object v) => new JsValue((Int64)v) },
+            { typeof(SByte), (Engine engine, object v) => new JsValue((SByte)v) },
+            { typeof(Single), (Engine engine, object v) => new JsValue((Single)v) },
+            { typeof(string), (Engine engine, object v) => new JsValue((string)v) },
+            { typeof(UInt16), (Engine engine, object v) => new JsValue((UInt16)v) },
+            { typeof(UInt32), (Engine engine, object v) => new JsValue((UInt32)v) },
+            { typeof(UInt64), (Engine engine, object v) => new JsValue((UInt64)v) },
+            { typeof(JsValue), (Engine engine, object v) => (JsValue)v },
+            { typeof(System.Text.RegularExpressions.Regex), (Engine engine, object v) => engine.RegExp.Construct(((System.Text.RegularExpressions.Regex)v).ToString().Trim('/')) }
+        };
+
         internal JintCallStack CallStack = new JintCallStack();
         internal JintCallStack CallStack = new JintCallStack();
 
 
         public Engine() : this(null)
         public Engine() : this(null)

+ 22 - 62
Jint/Native/JsValue.cs

@@ -303,83 +303,43 @@ namespace Jint.Native
                 }
                 }
             }
             }
 
 
-            var typeCode = System.Type.GetTypeCode(value.GetType());
-            switch (typeCode)
-            {
-                case TypeCode.Boolean:
-                    return new JsValue((bool)value);
-                case TypeCode.Byte:
-                    return new JsValue((byte)value);
-                case TypeCode.Char:
-                    return new JsValue(value.ToString());
-                case TypeCode.DateTime:
-                    return engine.Date.Construct((DateTime)value);
-                case TypeCode.Decimal:
-                    return new JsValue((double)(decimal)value);
-                case TypeCode.Double:
-                    return new JsValue((double)value);
-                case TypeCode.Int16:
-                    return new JsValue((Int16)value);
-                case TypeCode.Int32:
-                    return new JsValue((Int32)value);
-                case TypeCode.Int64:
-                    return new JsValue((Int64)value);
-                case TypeCode.SByte:
-                    return new JsValue((SByte)value);
-                case TypeCode.Single:
-                    return new JsValue((Single)value);
-                case TypeCode.String:
-                    return new JsValue((string)value);
-                case TypeCode.UInt16:
-                    return new JsValue((UInt16)value);
-                case TypeCode.UInt32:
-                    return new JsValue((UInt32)value);
-                case TypeCode.UInt64:
-                    return new JsValue((UInt64)value);
-                case TypeCode.Object:
-                    break;
-                case TypeCode.Empty:
-                    break;
-                default:
-                    throw new ArgumentOutOfRangeException();
-            }
+            var valueType = value.GetType();
 
 
-            if (value is DateTimeOffset)
+            var typeMappers = Engine.TypeMappers;
+
+            Func<Engine, object, JsValue> typeMapper;
+            if (typeMappers.TryGetValue(valueType, out typeMapper))
             {
             {
-                return engine.Date.Construct((DateTimeOffset)value);
+                return typeMapper(engine, value);
             }
             }
 
 
             // if an ObjectInstance is passed directly, use it as is
             // if an ObjectInstance is passed directly, use it as is
             var instance = value as ObjectInstance;
             var instance = value as ObjectInstance;
             if (instance != null)
             if (instance != null)
             {
             {
+                // Learn conversion.
+                typeMappers.Add(valueType, (Engine e, object v) => new JsValue((ObjectInstance)v));
                 return new JsValue(instance);
                 return new JsValue(instance);
             }
             }
 
 
-            // if a JsValue is passed directly, use it as is
-            if (value is JsValue)
+            var a = value as System.Array;
+            if (a != null)
             {
             {
-                return (JsValue)value;
-            }
-
-            var array = value as System.Array;
-            if (array != null)
-            {
-                var jsArray = engine.Array.Construct(Arguments.Empty);
-                foreach (var item in array)
+                Func<Engine, object, JsValue> convert = (Engine e, object v) =>
                 {
                 {
-                    var jsItem = FromObject(engine, item);
-                    engine.Array.PrototypeObject.Push(jsArray, Arguments.From(jsItem));
-                }
+                    var array = (System.Array)v;
 
 
-                return jsArray;
-            }
+                    var jsArray = engine.Array.Construct(Arguments.Empty);
+                    foreach (var item in array)
+                    {
+                        var jsItem = JsValue.FromObject(engine, item);
+                        engine.Array.PrototypeObject.Push(jsArray, Arguments.From(jsItem));
+                    }
 
 
-            var regex = value as System.Text.RegularExpressions.Regex;
-            if (regex != null)
-            {
-                var jsRegex = engine.RegExp.Construct(regex.ToString().Trim('/'));
-                return jsRegex;
+                    return jsArray;
+                };
+                typeMappers.Add(valueType, convert);
+                return convert(engine, a);
             }
             }
 
 
             var d = value as Delegate;
             var d = value as Delegate;