Browse Source

Merge pull request #109 from ala53/master

Improve JsValue performance by removing Nullable overhead.
Sébastien Ros 10 years ago
parent
commit
04d08c8e48
4 changed files with 82 additions and 78 deletions
  1. 1 1
      Jint/Jint.csproj
  2. 27 26
      Jint/Native/JsValue.cs
  3. 53 50
      Jint/Runtime/Interop/ObjectWrapper.cs
  4. 1 1
      README.md

+ 1 - 1
Jint/Jint.csproj

@@ -182,7 +182,7 @@
     <Compile Include="Runtime\Interop\MethodInfoFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\MethodInfoFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\ClrFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\ClrFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\NamespaceReference.cs" />
     <Compile Include="Runtime\Interop\NamespaceReference.cs" />
-    <Compile Include="Runtime\Interop\ObjectWrapper .cs" />
+    <Compile Include="Runtime\Interop\ObjectWrapper.cs" />
     <Compile Include="Runtime\Interop\SetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\SetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\GetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\GetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\DelegateWrapper.cs" />
     <Compile Include="Runtime\Interop\DelegateWrapper.cs" />

+ 27 - 26
Jint/Native/JsValue.cs

@@ -14,9 +14,11 @@ using Jint.Native.RegExp;
 using Jint.Native.String;
 using Jint.Native.String;
 using Jint.Runtime;
 using Jint.Runtime;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
+using System.Runtime.InteropServices;
 
 
 namespace Jint.Native
 namespace Jint.Native
 {
 {
+    [StructLayout(LayoutKind.Explicit)]
     [DebuggerTypeProxy(typeof(JsValueDebugView))]
     [DebuggerTypeProxy(typeof(JsValueDebugView))]
     public struct JsValue : IEquatable<JsValue>
     public struct JsValue : IEquatable<JsValue>
     {
     {
@@ -27,57 +29,66 @@ namespace Jint.Native
 
 
         public JsValue(bool value)
         public JsValue(bool value)
         {
         {
-            _bool = value;
-            _double = null;
+            _double = double.NaN;
             _object = null;
             _object = null;
             _string = null;
             _string = null;
             _type = Types.Boolean;
             _type = Types.Boolean;
+
+            _bool = value; //Set value last because of 'FieldOffset' constraints
         }
         }
 
 
         public JsValue(double value)
         public JsValue(double value)
         {
         {
-            _bool = null;
-            _double = value;
+            _bool = false;
             _object = null;
             _object = null;
             _string = null;
             _string = null;
             _type = Types.Number;
             _type = Types.Number;
+
+            _double = value;
         }
         }
 
 
         public JsValue(string value)
         public JsValue(string value)
         {
         {
-            _bool = null;
-            _double = null;
+            _bool = false;
+            _double = double.NaN;
             _object = null;
             _object = null;
-            _string = value;
             _type = Types.String;
             _type = Types.String;
+
+            _string = value;
         }
         }
 
 
         public JsValue(ObjectInstance value)
         public JsValue(ObjectInstance value)
         {
         {
-            _bool = null;
-            _double = null;
-            _object = value;
+            _bool = false;
+            _double = double.NaN;
             _string = null;
             _string = null;
             _type = Types.Object;
             _type = Types.Object;
+
+            _object = value;
         }
         }
 
 
         private JsValue(Types type)
         private JsValue(Types type)
         {
         {
-            _bool = null;
-            _double = null;
+            _bool = false;
+            _double = double.NaN;
             _object = null;
             _object = null;
             _string = null;
             _string = null;
             _type = type;
             _type = type;
         }
         }
 
 
-        private readonly bool? _bool;
+        [FieldOffset(0)]
+        private readonly bool _bool;
 
 
-        private readonly double? _double;
+        [FieldOffset(0)]
+        private readonly double _double;
 
 
+        [FieldOffset(8)]
         private readonly ObjectInstance _object;
         private readonly ObjectInstance _object;
 
 
+        [FieldOffset(8)]
         private readonly string _string;
         private readonly string _string;
 
 
+        [FieldOffset(16)]
         private readonly Types _type;
         private readonly Types _type;
 
 
         [Pure]
         [Pure]
@@ -194,12 +205,7 @@ namespace Jint.Native
                 throw new ArgumentException("The value is not a boolean");
                 throw new ArgumentException("The value is not a boolean");
             }
             }
 
 
-            if (!_bool.HasValue)
-            {
-                throw new ArgumentException("The value is not defined");
-            }
-
-            return _bool.Value;
+            return _bool;
         }
         }
 
 
         [Pure]
         [Pure]
@@ -226,12 +232,7 @@ namespace Jint.Native
                 throw new ArgumentException("The value is not a number");
                 throw new ArgumentException("The value is not a number");
             }
             }
 
 
-            if (!_double.HasValue)
-            {
-                throw new ArgumentException("The value is not defined");
-            }
-
-            return _double.Value;
+            return _double;
         }
         }
 
 
         public bool Equals(JsValue other)
         public bool Equals(JsValue other)

+ 53 - 50
Jint/Runtime/Interop/ObjectWrapper .cs → Jint/Runtime/Interop/ObjectWrapper.cs

@@ -4,19 +4,20 @@ using System.Reflection;
 using Jint.Native;
 using Jint.Native;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors.Specialized;
 using System.Collections;
 using System.Collections;
 
 
 namespace Jint.Runtime.Interop
 namespace Jint.Runtime.Interop
 {
 {
     /// <summary>
     /// <summary>
-    /// Wrapps a CLR instance
+    /// Wraps a CLR instance
     /// </summary>
     /// </summary>
     public sealed class ObjectWrapper : ObjectInstance, IObjectWrapper
     public sealed class ObjectWrapper : ObjectInstance, IObjectWrapper
     {
     {
         public Object Target { get; set; }
         public Object Target { get; set; }
 
 
-        public ObjectWrapper(Engine engine, Object obj): base(engine)
+        public ObjectWrapper(Engine engine, Object obj)
+            : base(engine)
         {
         {
             Target = obj;
             Target = obj;
         }
         }
@@ -54,9 +55,7 @@ namespace Jint.Runtime.Interop
         {
         {
             PropertyDescriptor x;
             PropertyDescriptor x;
             if (Properties.TryGetValue(propertyName, out x))
             if (Properties.TryGetValue(propertyName, out x))
-            {
                 return x;
                 return x;
-            }
 
 
             var type = Target.GetType();
             var type = Target.GetType();
 
 
@@ -87,51 +86,55 @@ namespace Jint.Runtime.Interop
 
 
             if (methods.Any())
             if (methods.Any())
             {
             {
-                return new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, methods), false, true, false);
-            }
-
-            // if no methods are found check if target implemented indexing
-            if (type.GetProperties().Where(p => p.GetIndexParameters().Length != 0).FirstOrDefault() != null)
-            {
-                return new IndexDescriptor(Engine, propertyName, Target);
-            }
-
-            var interfaces = type.GetInterfaces();
-
-            // try to find a single explicit property implementation
-            var explicitProperties = (from iface in interfaces
-                                      from iprop in iface.GetProperties()
-                                      where propertyName.Equals(iprop.Name)
-                                      select iprop).ToList();
-
-            if (explicitProperties.Count == 1)
-            {
-                var descriptor = new PropertyInfoDescriptor(Engine, explicitProperties[0], Target);
-                Properties.Add(propertyName, descriptor);
-                return descriptor;
-            }
-
-            // try to find explicit method implementations
-            var explicitMethods = (from iface in interfaces
-                                   from imethod in iface.GetMethods()
-                                   where propertyName.Equals(imethod.Name)
-                                   select imethod).ToList();
-
-            if (explicitMethods.Count > 0)
-            {
-                return new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods.ToArray()), false, true, false);
-            }
-
-            // try to find explicit indexer implementations
-            var explicitIndexers =
-                (from iface in interfaces
-                 from iprop in iface.GetProperties()
-                 where iprop.GetIndexParameters().Length != 0
-                 select iprop).ToList();
-
-            if (explicitIndexers.Count == 1)
-            {
-                return new IndexDescriptor(Engine, explicitIndexers[0].DeclaringType, propertyName, Target);
+                var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, methods), false, true, false);
+                Properties.Add(propertyName, descriptor);
+                return descriptor;
+            }
+
+            // if no methods are found check if target implemented indexing
+            if (type.GetProperties().Where(p => p.GetIndexParameters().Length != 0).FirstOrDefault() != null)
+            {
+                return new IndexDescriptor(Engine, propertyName, Target);
+            }
+
+            var interfaces = type.GetInterfaces();
+
+            // try to find a single explicit property implementation
+            var explicitProperties = (from iface in interfaces
+                                      from iprop in iface.GetProperties()
+                                      where propertyName.Equals(iprop.Name)
+                                      select iprop).ToArray();
+
+            if (explicitProperties.Length == 1)
+            {
+                var descriptor = new PropertyInfoDescriptor(Engine, explicitProperties[0], Target);
+                Properties.Add(propertyName, descriptor);
+                return descriptor;
+            }
+
+            // try to find explicit method implementations
+            var explicitMethods = (from iface in interfaces
+                                   from imethod in iface.GetMethods()
+                                   where propertyName.Equals(imethod.Name)
+                                   select imethod).ToArray();
+
+            if (explicitMethods.Length > 0)
+            {
+                var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods), false, true, false);
+                Properties.Add(propertyName, descriptor);
+                return descriptor;
+            }
+
+            // try to find explicit indexer implementations
+            var explicitIndexers =
+                (from iface in interfaces
+                 from iprop in iface.GetProperties()
+                 where iprop.GetIndexParameters().Length != 0
+                 select iprop).ToArray();
+
+            if (explicitIndexers.Length == 1)
+            {
+                return new IndexDescriptor(Engine, explicitIndexers[0].DeclaringType, propertyName, Target);
             }
             }
 
 
             return PropertyDescriptor.Undefined;
             return PropertyDescriptor.Undefined;

+ 1 - 1
README.md

@@ -44,7 +44,7 @@ You can also directly pass POCOs or anonymous objects and use them from JavaScri
 
 
     var engine = new Engine()
     var engine = new Engine()
         .SetValue("p", p)
         .SetValue("p", p)
-        .Execute("p.Name === 'Mickey Mouse')
+        .Execute("p.Name === 'Mickey Mouse'")
         ;
         ;
 ```
 ```
 You can invoke JavaScript function reference
 You can invoke JavaScript function reference