Kaynağa Gözat

cache common int to string conversions

Marko Lahma 7 yıl önce
ebeveyn
işleme
4582830317

+ 16 - 13
Jint/Native/Array/ArrayInstance.cs

@@ -1,5 +1,5 @@
 using System.Collections.Generic;
-using System.Linq;
+using System.Threading;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -8,8 +8,11 @@ namespace Jint.Native.Array
 {
     public class ArrayInstance : ObjectInstance
     {
+        // cache key container for array iteration for less allocations
+        private static readonly ThreadLocal<List<uint>> keyCache = new ThreadLocal<List<uint>>(() => new List<uint>());
+
         private readonly Engine _engine;
-        private IDictionary<uint, PropertyDescriptor> _array = new MruPropertyCache2<uint, PropertyDescriptor>();
+        private readonly Dictionary<uint, PropertyDescriptor> _array = new Dictionary<uint, PropertyDescriptor>();
         private PropertyDescriptor _length;
 
         public ArrayInstance(Engine engine) : base(engine)
@@ -17,13 +20,7 @@ namespace Jint.Native.Array
             _engine = engine;
         }
 
-        public override string Class
-        {
-            get
-            {
-                return "Array";
-            }
-        }
+        public override string Class => "Array";
 
         /// Implementation from ObjectInstance official specs as the one
         /// in ObjectInstance is optimized for the general case and wouldn't work
@@ -120,14 +117,16 @@ namespace Jint.Native.Array
 
                 if (_array.Count < oldLen - newLen)
                 {
-                    var keys = _array.Keys.ToArray();
+                    var keys = keyCache.Value;
+                    keys.Clear();
+                    keys.AddRange(_array.Keys);
                     foreach (var key in keys)
                     {
                         uint keyIndex;
                         // is it the index of the array
                         if (IsArrayIndex(key, out keyIndex) && keyIndex >= newLen && keyIndex < oldLen)
                         {
-                            var deleteSucceeded = Delete(key.ToString(), false);
+                            var deleteSucceeded = Delete(TypeConverter.ToString(key), false);
                             if (!deleteSucceeded)
                             {
                                 newLenDesc.Value = new JsValue(keyIndex + 1);
@@ -219,7 +218,7 @@ namespace Jint.Native.Array
         {
             foreach(var entry in _array)
             {
-                yield return new KeyValuePair<string, PropertyDescriptor>(entry.Key.ToString(), entry.Value);
+                yield return new KeyValuePair<string, PropertyDescriptor>(TypeConverter.ToString(entry.Key), entry.Value);
             }
 
             foreach(var entry in base.GetOwnProperties())
@@ -289,8 +288,12 @@ namespace Jint.Native.Array
 
         public static bool IsArrayIndex(JsValue p, out uint index)
         {
-            index = ParseArrayIndex(TypeConverter.ToString(p));
+            return IsArrayIndex(TypeConverter.ToString(p), out index);
+        }
 
+        private static bool IsArrayIndex(string p, out uint index)
+        {
+            index = ParseArrayIndex(p);
             return index != uint.MaxValue;
 
             // 15.4 - Use an optimized version of the specification

+ 39 - 31
Jint/Native/Array/ArrayPrototype.cs

@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -79,7 +78,7 @@ namespace Jint.Native.Array
             var searchElement = arguments.At(0);
             for (; k >= 0; k--)
             {
-                var kString = TypeConverter.ToString(k);
+                var kString = k.ToString();
                 var kPresent = o.HasProperty(kString);
                 if (kPresent)
                 {
@@ -124,7 +123,7 @@ namespace Jint.Native.Array
                 var kPresent = false;
                 while (kPresent == false && k < len)
                 {
-                    var pk = k.ToString();
+                    var pk = TypeConverter.ToString(k);
                     kPresent = o.HasProperty(pk);
                     if (kPresent)
                     {
@@ -140,7 +139,7 @@ namespace Jint.Native.Array
 
             while(k < len)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kPresent = o.HasProperty(pk);
                 if (kPresent)
                 {
@@ -173,7 +172,7 @@ namespace Jint.Native.Array
             var to = 0;
             for (var k = 0; k < len; k++)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kpresent = o.HasProperty(pk);
                 if (kpresent)
                 {
@@ -181,7 +180,7 @@ namespace Jint.Native.Array
                     var selected = callable.Call(thisArg, new [] { kvalue, k, o });
                     if (TypeConverter.ToBoolean(selected))
                     {
-                        a.DefineOwnProperty(to.ToString(), new PropertyDescriptor(kvalue, true, true, true), false);
+                        a.DefineOwnProperty(TypeConverter.ToString(to), new PropertyDescriptor(kvalue, true, true, true), false);
                         to++;
                     }
                 }
@@ -208,7 +207,7 @@ namespace Jint.Native.Array
 
             for (var k = 0; k < len; k++)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kpresent = o.HasProperty(pk);
                 if (kpresent)
                 {
@@ -237,7 +236,7 @@ namespace Jint.Native.Array
 
             for (var k = 0; k < len; k++)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kpresent = o.HasProperty(pk);
                 if (kpresent)
                 {
@@ -265,7 +264,7 @@ namespace Jint.Native.Array
 
             for (var k = 0; k < len; k++)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kpresent = o.HasProperty(pk);
                 if (kpresent)
                 {
@@ -297,7 +296,7 @@ namespace Jint.Native.Array
 
             for (var k = 0; k < len; k++)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kpresent = o.HasProperty(pk);
                 if (kpresent)
                 {
@@ -344,7 +343,7 @@ namespace Jint.Native.Array
             var searchElement = arguments.At(0);
             for (; k < len; k++)
             {
-                var kString = TypeConverter.ToString(k);
+                var kString = k.ToString();
                 var kPresent = o.HasProperty(kString);
                 if (kPresent)
                 {
@@ -383,22 +382,27 @@ namespace Jint.Native.Array
             var actualDeleteCount = System.Math.Min(System.Math.Max(TypeConverter.ToInteger(deleteCount), 0), len - actualStart);
             for (var k = 0; k < actualDeleteCount; k++)
             {
-                var from = (actualStart + k).ToString();
+                var from = TypeConverter.ToString(actualStart + k);
                 var fromPresent = o.HasProperty(from);
                 if (fromPresent)
                 {
                     var fromValue = o.Get(from);
-                    a.DefineOwnProperty(k.ToString(), new PropertyDescriptor(fromValue, true, true, true), false);
+                    a.DefineOwnProperty(TypeConverter.ToString(k), new PropertyDescriptor(fromValue, true, true, true), false);
                 }
             }
 
-            var items = arguments.Skip(2).ToArray();
+            var items = System.Array.Empty<JsValue>();
+            if (arguments.Length > 2)
+            {
+                items = new JsValue[arguments.Length - 2];
+                System.Array.Copy(arguments, 2, items, 0, items.Length);
+            }
             if (items.Length < actualDeleteCount)
             {
                 for (var k = actualStart; k < len - actualDeleteCount; k++)
                 {
-                    var from = (k + actualDeleteCount).ToString();
-                    var to = (k + items.Length).ToString();
+                    var from = TypeConverter.ToString(k + actualDeleteCount);
+                    var to = TypeConverter.ToString(k + items.Length);
                     var fromPresent = o.HasProperty(from);
                     if (fromPresent)
                     {
@@ -412,15 +416,15 @@ namespace Jint.Native.Array
                 }
                 for (var k = len; k > len - actualDeleteCount + items.Length; k-- )
                 {
-                    o.Delete((k - 1).ToString(), true);
+                    o.Delete(TypeConverter.ToString(k - 1), true);
                 }
             }
             else if (items.Length > actualDeleteCount)
             {
                 for (var k = len - actualDeleteCount; k > actualStart; k--)
                 {
-                    var from = (k + actualDeleteCount - 1).ToString();
-                    var to = (k + items.Length - 1).ToString();
+                    var from = TypeConverter.ToString(k + actualDeleteCount - 1);
+                    var to = TypeConverter.ToString(k + items.Length - 1);
                     var fromPresent = o.HasProperty(from);
                     if (fromPresent)
                     {
@@ -437,7 +441,7 @@ namespace Jint.Native.Array
             for(var k = 0; k< items.Length; k++)
             {
                 var e = items[k];
-                o.Put((k+actualStart).ToString(), e, true);
+                o.Put(TypeConverter.ToString(k+actualStart), e, true);
             }
 
             o.Put("length", len - actualDeleteCount + items.Length, true);
@@ -452,8 +456,8 @@ namespace Jint.Native.Array
             var argCount = (uint)arguments.Length;
             for (var k = len; k > 0; k--)
             {
-                var from = (k - 1).ToString();
-                var to = (k + argCount - 1).ToString();
+                var from = TypeConverter.ToString(k - 1);
+                var to = TypeConverter.ToString(k + argCount - 1);
                 var fromPresent = o.HasProperty(from);
                 if (fromPresent)
                 {
@@ -467,7 +471,7 @@ namespace Jint.Native.Array
             }
             for (var j = 0; j < argCount; j++)
             {
-                o.Put(j.ToString(), arguments[j], true);
+                o.Put(TypeConverter.ToString(j), arguments[j], true);
             }
             o.Put("length", len + argCount, true);
             return len + argCount;
@@ -537,7 +541,11 @@ namespace Jint.Native.Array
                     return r;
                 };
 
-            var array = Enumerable.Range(0, lenVal).Select(i => obj.Get(i.ToString())).ToArray();
+            var array = new JsValue[lenVal];
+            for (int i = 0; i < lenVal; ++i)
+            {
+                array[i] = obj.Get(TypeConverter.ToString(i));
+            }
 
             // don't eat inner exceptions
             try
@@ -549,9 +557,9 @@ namespace Jint.Native.Array
                 throw e.InnerException;
             }
 
-            foreach (var i in Enumerable.Range(0, lenVal))
+            for (var i = 0; i < lenVal; ++i)
             {
-                obj.Put(i.ToString(), array[i], false);
+                obj.Put(TypeConverter.ToString(i), array[i], false);
             }
 
             return obj;
@@ -708,7 +716,7 @@ namespace Jint.Native.Array
             for (var k = 1; k < len; k++)
             {
                 var s = r + sep;
-                var element = o.Get(k.ToString());
+                var element = o.Get(TypeConverter.ToString(k));
                 string next = element == Undefined.Instance || element == Null.Instance
                                   ? ""
                                   : TypeConverter.ToString(element);
@@ -746,7 +754,7 @@ namespace Jint.Native.Array
             for (var k = 1; k < len; k++)
             {
                 string s = r + separator;
-                var nextElement = array.Get(k.ToString());
+                var nextElement = array.Get(TypeConverter.ToString(k));
                 if (nextElement == Undefined.Instance || nextElement == Null.Instance)
                 {
                     r = "";
@@ -783,7 +791,7 @@ namespace Jint.Native.Array
                     var len =  TypeConverter.ToUint32(eArray.Get("length"));
                     for (var k = 0; k < len; k++)
                     {
-                        var p = k.ToString();
+                        var p = TypeConverter.ToString(k);
                         var exists = eArray.HasProperty(p);
                         if (exists)
                         {
@@ -852,7 +860,7 @@ namespace Jint.Native.Array
                 var kPresent = false;
                 while (kPresent == false && k >= 0)
                 {
-                    var pk = k.ToString();
+                    var pk = TypeConverter.ToString(k);
                     kPresent = o.HasProperty(pk);
                     if (kPresent)
                     {
@@ -868,7 +876,7 @@ namespace Jint.Native.Array
 
             for (; k >= 0; k--)
             {
-                var pk = k.ToString();
+                var pk = TypeConverter.ToString(k);
                 var kPresent = o.HasProperty(pk);
                 if (kPresent)
                 {

+ 4 - 4
Jint/Native/Function/FunctionConstructor.cs

@@ -167,14 +167,14 @@ namespace Jint.Native.Function
 
             var len = argArrayObj.Get("length");
             var n = TypeConverter.ToUint32(len);
-            var argList = new List<JsValue>();
+            var argList = new JsValue[n];
             for (var index = 0; index < n; index++)
             {
-                var indexName = index.ToString();
+                var indexName = TypeConverter.ToString(index);
                 var nextArg = argArrayObj.Get(indexName);
-                argList.Add(nextArg);
+                argList[index] = nextArg;
             }
-            return func.Call(thisArg, argList.ToArray());
+            return func.Call(thisArg, argList);
         }
     }
 }

+ 9 - 9
Jint/Native/Function/FunctionPrototype.cs

@@ -44,7 +44,7 @@ namespace Jint.Native.Function
             {
                 throw new JavaScriptException(Engine.TypeError);
             });
-            
+
             var thisArg = arguments.At(0);
             var f = new BindFunctionInstance(Engine) {Extensible = true};
             f.TargetFunction = thisObj;
@@ -56,13 +56,13 @@ namespace Jint.Native.Function
             if (o != null)
             {
                 var l = TypeConverter.ToNumber(o.Get("length")) - (arguments.Length - 1);
-                f.FastAddProperty("length", System.Math.Max(l, 0), false, false, false); 
+                f.FastAddProperty("length", System.Math.Max(l, 0), false, false, false);
             }
             else
             {
-                f.FastAddProperty("length", 0, false, false, false); 
+                f.FastAddProperty("length", 0, false, false, false);
             }
-            
+
 
             var thrower = Engine.Function.ThrowTypeError;
             f.DefineOwnProperty("caller", new PropertyDescriptor(thrower, thrower, false, false), false);
@@ -78,7 +78,7 @@ namespace Jint.Native.Function
 
             if (func == null)
             {
-                throw new JavaScriptException(Engine.TypeError, "Function object expected.");       
+                throw new JavaScriptException(Engine.TypeError, "Function object expected.");
             }
 
             return System.String.Format("function() {{ ... }}");
@@ -108,14 +108,14 @@ namespace Jint.Native.Function
 
             var len = argArrayObj.Get("length").AsNumber();
             uint n = TypeConverter.ToUint32(len);
-            var argList = new List<JsValue>();
+            var argList = new JsValue[n];
             for (int index = 0; index < n; index++)
             {
-                string indexName = index.ToString();
+                string indexName = TypeConverter.ToString(index);
                 var nextArg = argArrayObj.Get(indexName);
-                argList.Add(nextArg);
+                argList[index] = nextArg;
             }
-            return func.Call(thisArg, argList.ToArray());
+            return func.Call(thisArg, argList);
         }
 
         public JsValue CallImpl(JsValue thisObject, JsValue[] arguments)

+ 1 - 1
Jint/Native/JsValue.cs

@@ -466,7 +466,7 @@ namespace Jint.Native
                                 var result = new object[len];
                                 for (var k = 0; k < len; k++)
                                 {
-                                    var pk = k.ToString();
+                                    var pk = TypeConverter.ToString(k);
                                     var kpresent = arrayInstance.HasProperty(pk);
                                     if (kpresent)
                                     {

+ 1 - 1
Jint/Native/Json/JsonParser.cs

@@ -146,7 +146,7 @@ namespace Jint.Native.Json
                     return new Token
                         {
                             Type = Tokens.Punctuator,
-                            Value = code.ToString(),
+                            Value = TypeConverter.ToString(code),
                             LineNumber = _lineNumber,
                             LineStart = _lineStart,
                             Range = new[] {start, _index}

+ 6 - 6
Jint/Native/Number/NumberPrototype.cs

@@ -201,7 +201,7 @@ namespace Jint.Native.Number
 
             if (radix == 10)
             {
-                return ToNumberString(x);    
+                return ToNumberString(x);
             }
 
             var integer = (long) x;
@@ -229,7 +229,7 @@ namespace Jint.Native.Number
             {
                 var digit = (int)(n % radix);
                 n = n / radix;
-                result.Insert(0, digits[digit].ToString());
+                result.Insert(0, digits[digit]);
             }
 
             return result.ToString();
@@ -253,13 +253,13 @@ namespace Jint.Native.Number
                 var d = (int) c;
                 n = c - d;
 
-                result.Append(digits[d].ToString());
+                result.Append(digits[d]);
             }
 
             return result.ToString();
         }
 
-        public static string ToNumberString(double m) 
+        public static string ToNumberString(double m)
         {
             if (double.IsNaN(m))
             {
@@ -300,7 +300,7 @@ namespace Jint.Native.Number
             {
                 s = rFormat.Replace(".", "").TrimStart('0').TrimEnd('0');
             }
-        
+
             const string format = "0.00000000000000000e0";
             var parts = m.ToString(format, CultureInfo.InvariantCulture).Split('e');
             if (s == null)
@@ -310,7 +310,7 @@ namespace Jint.Native.Number
 
             var n = int.Parse(parts[1]) + 1;
             var k = s.Length;
-            
+
             if (k <= n && n <= 21)
             {
                 return s + new string('0', n - k);

+ 10 - 10
Jint/Native/Object/ObjectConstructor.cs

@@ -62,8 +62,8 @@ namespace Jint.Native.Object
             if (arguments.Length == 0)
             {
                 return Construct(arguments);
-            } 
-            
+            }
+
             if(arguments[0] == Null.Instance || arguments[0] == Undefined.Instance)
             {
                 return Construct(arguments);
@@ -111,7 +111,7 @@ namespace Jint.Native.Object
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
-            
+
             return o.Prototype ?? Null.Instance;
         }
 
@@ -148,14 +148,14 @@ namespace Jint.Native.Object
             {
                 for (var i = 0; i < s.PrimitiveValue.AsString().Length; i++)
                 {
-                    array.DefineOwnProperty(n.ToString(), new PropertyDescriptor(i.ToString(), true, true, true), false);
+                    array.DefineOwnProperty(TypeConverter.ToString(n), new PropertyDescriptor(TypeConverter.ToString(i), true, true, true), false);
                     n++;
-                }  
+                }
             }
 
             foreach (var p in o.GetOwnProperties())
             {
-                array.DefineOwnProperty(n.ToString(), new PropertyDescriptor(p.Key, true, true, true), false);
+                array.DefineOwnProperty(TypeConverter.ToString(n), new PropertyDescriptor(p.Key, true, true, true), false);
                 n++;
             }
 
@@ -284,9 +284,9 @@ namespace Jint.Native.Object
                 }
                 o.DefineOwnProperty(p, desc, true);
             }
-            
+
             o.Extensible = false;
-         
+
             return o;
         }
 
@@ -393,8 +393,8 @@ namespace Jint.Native.Object
             {
                 var p = prop.Key;
                 array.DefineOwnProperty(
-                    TypeConverter.ToString(index), 
-                    new PropertyDescriptor(p, true, true, true), 
+                    TypeConverter.ToString(index),
+                    new PropertyDescriptor(p, true, true, true),
                     false);
                 index++;
             }

+ 4 - 4
Jint/Native/RegExp/RegExpPrototype.cs

@@ -71,7 +71,7 @@ namespace Jint.Native.RegExp
             var lastIndex = TypeConverter.ToNumber(R.Get("lastIndex"));
             var i = TypeConverter.ToInteger(lastIndex);
             var global = R.Global;
-            
+
             if (!global)
             {
                 i = 0;
@@ -101,7 +101,7 @@ namespace Jint.Native.RegExp
             }
 
             var e = r.Index + r.Length;
-            
+
             if (global)
             {
                 R.Put("lastIndex", (double) e, true);
@@ -110,12 +110,12 @@ namespace Jint.Native.RegExp
             var matchIndex = r.Index;
 
             var a = InitReturnValueArray(Engine.Array.Construct(Arguments.Empty), s, n, matchIndex);
-            
+
             for (var k = 0; k < n; k++)
             {
                 var group = r.Groups[k];
                 var value = group.Success ? group.Value : Undefined.Instance;
-                a.DefineOwnProperty(k.ToString(), new PropertyDescriptor(value, true, true, true), true);            
+                a.DefineOwnProperty(TypeConverter.ToString(k), new PropertyDescriptor(value, true, true, true), true);
             }
 
             return a;

+ 25 - 25
Jint/Native/String/StringPrototype.cs

@@ -30,7 +30,7 @@ namespace Jint.Native.String
             obj.Prototype = engine.Object.PrototypeObject;
             obj.PrimitiveValue = "";
             obj.Extensible = true;
-            obj.FastAddProperty("length", 0, false, false, false); 
+            obj.FastAddProperty("length", 0, false, false, false);
             obj.FastAddProperty("constructor", stringConstructor, true, false, true);
 
             return obj;
@@ -81,8 +81,8 @@ namespace Jint.Native.String
 
         private static bool IsWhiteSpaceEx(char c)
         {
-            return 
-                char.IsWhiteSpace(c) || 
+            return
+                char.IsWhiteSpace(c) ||
                 c == BOM_CHAR ||
                 // In .NET 4.6 this was removed from WS based on Unicode 6.3 changes
                 c == MONGOLIAN_VOWEL_SEPARATOR;
@@ -129,7 +129,7 @@ namespace Jint.Native.String
         public static string TrimEx(string s)
         {
             return TrimEndEx(TrimStartEx(s));
-        } 
+        }
 
         private JsValue Trim(JsValue thisObj, JsValue[] arguments)
         {
@@ -137,7 +137,7 @@ namespace Jint.Native.String
             var s = TypeConverter.ToString(thisObj);
             return TrimEx(s);
         }
-        
+
         private static JsValue ToLocaleUpperCase(JsValue thisObj, JsValue[] arguments)
         {
             var s = TypeConverter.ToString(thisObj);
@@ -209,8 +209,8 @@ namespace Jint.Native.String
         {
             var s = TypeConverter.ToString(thisObj);
             var start = TypeConverter.ToInteger(arguments.At(0));
-            var length = arguments.At(1) == JsValue.Undefined 
-                ? double.PositiveInfinity 
+            var length = arguments.At(1) == JsValue.Undefined
+                ? double.PositiveInfinity
                 : TypeConverter.ToInteger(arguments.At(1));
 
             start = start >= 0 ? start : System.Math.Max(s.Length + start, 0);
@@ -230,12 +230,12 @@ namespace Jint.Native.String
 
             var separator = arguments.At(0);
 
-            // Coerce into a number, true will become 1 
+            // Coerce into a number, true will become 1
             var l = arguments.At(1);
             var a = (ArrayInstance) Engine.Array.Construct(Arguments.Empty);
             var limit = l == Undefined.Instance ? UInt32.MaxValue : TypeConverter.ToUint32(l);
             var len = s.Length;
-            
+
             if (limit == 0)
             {
                 return a;
@@ -262,7 +262,7 @@ namespace Jint.Native.String
             const string regExpForMatchingAllCharactere = "(?:)";
 
             if (rx != null &&
-                rx.Source != regExpForMatchingAllCharactere // We need pattern to be defined -> for s.split(new RegExp) 
+                rx.Source != regExpForMatchingAllCharactere // We need pattern to be defined -> for s.split(new RegExp)
                 )
             {
                 var match = rx.Value.Match(s, 0);
@@ -284,8 +284,8 @@ namespace Jint.Native.String
                     }
 
                     // Add the match results to the array.
-                    a.DefineOwnProperty(index++.ToString(), new PropertyDescriptor(s.Substring(lastIndex, match.Index - lastIndex), true, true, true), false);
-                    
+                    a.DefineOwnProperty(TypeConverter.ToString(index++), new PropertyDescriptor(s.Substring(lastIndex, match.Index - lastIndex), true, true, true), false);
+
                     if (index >= limit)
                     {
                         return a;
@@ -301,7 +301,7 @@ namespace Jint.Native.String
                             item = match.Groups[i].Value;
                         }
 
-                        a.DefineOwnProperty(index++.ToString(), new PropertyDescriptor(item, true, true, true ), false);
+                        a.DefineOwnProperty(TypeConverter.ToString(index++), new PropertyDescriptor(item, true, true, true ), false);
 
                         if (index >= limit)
                         {
@@ -312,7 +312,7 @@ namespace Jint.Native.String
                     match = match.NextMatch();
                     if (!match.Success) // Add the last part of the split
                     {
-                        a.DefineOwnProperty(index++.ToString(), new PropertyDescriptor(s.Substring(lastIndex), true, true, true), false);                        
+                        a.DefineOwnProperty(TypeConverter.ToString(index++), new PropertyDescriptor(s.Substring(lastIndex), true, true, true), false);
                     }
                 }
 
@@ -327,7 +327,7 @@ namespace Jint.Native.String
                 {
                     foreach (var c in s)
                     {
-                        segments.Add(c.ToString());    
+                        segments.Add(c.ToString());
                     }
                 }
                 else
@@ -337,9 +337,9 @@ namespace Jint.Native.String
 
                 for (int i = 0; i < segments.Count && i < limit; i++)
                 {
-                    a.DefineOwnProperty(i.ToString(), new PropertyDescriptor(segments[i], true, true, true), false);
+                    a.DefineOwnProperty(TypeConverter.ToString(i), new PropertyDescriptor(segments[i], true, true, true), false);
                 }
-            
+
                 return a;
             }
         }
@@ -359,7 +359,7 @@ namespace Jint.Native.String
             {
                 return string.Empty;
             }
-            
+
             var end = TypeConverter.ToNumber(arguments.At(1));
             if (double.PositiveInfinity.Equals(end))
             {
@@ -494,7 +494,7 @@ namespace Jint.Native.String
 
             // searchValue is a regular expression
 
-            if (searchValue.IsNull()) 
+            if (searchValue.IsNull())
             {
                 searchValue = new JsValue(Null.Text);
             }
@@ -502,7 +502,7 @@ namespace Jint.Native.String
             {
                 searchValue = new JsValue(Undefined.Text);
             }
-            
+
             var rx = TypeConverter.ToObject(Engine, searchValue) as RegExpInstance;
             if (rx != null)
             {
@@ -510,13 +510,13 @@ namespace Jint.Native.String
                 string result = rx.Value.Replace(thisString, match =>
                 {
                     var args = new List<JsValue>();
-                    
+
                     for (var k = 0; k < match.Groups.Count; k++)
                     {
                         var group = match.Groups[k];
                         args.Add(group.Value);
                     }
-                    
+
                     args.Add(match.Index);
                     args.Add(thisString);
 
@@ -617,7 +617,7 @@ namespace Jint.Native.String
 
             var s = TypeConverter.ToString(thisObj);
             var that = TypeConverter.ToString(arguments.At(0));
-            
+
             return string.CompareOrdinal(s, that);
         }
 
@@ -819,7 +819,7 @@ namespace Jint.Native.String
                     throw new JavaScriptException(Engine.TypeError);
                 }
             }
-            
+
             var searchStr = TypeConverter.ToString(searchString);
 
             var pos = TypeConverter.ToInt32(arguments.At(1));
@@ -831,7 +831,7 @@ namespace Jint.Native.String
             {
                 return false;
             }
-            
+
             for (var i = 0; i < searchLength; i++)
             {
                 if (s[start + i] != searchStr[i])

+ 1 - 1
Jint/Runtime/ExpressionIntepreter.cs

@@ -992,7 +992,7 @@ namespace Jint.Runtime
                 if (expr != null)
                 {
                     var value = _engine.GetValue(EvaluateExpression(expr.As<Expression>()));
-                    a.DefineOwnProperty(n.ToString(),
+                    a.DefineOwnProperty(TypeConverter.ToString(n),
                         new PropertyDescriptor(value, true, true, true), false);
                 }
                 n++;

+ 1 - 1
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -54,7 +54,7 @@ namespace Jint.Runtime.Interop
                         var result = new JsValue[len];
                         for (var k = 0; k < len; k++)
                         {
-                            var pk = k.ToString();
+                            var pk = TypeConverter.ToString(k);
                             result[k] = arrayInstance.HasProperty(pk)
                                 ? arrayInstance.Get(pk)
                                 : JsValue.Undefined;

+ 1 - 1
Jint/Runtime/StatementInterpreter.cs

@@ -234,7 +234,7 @@ namespace Jint.Runtime
 
                 for (var i = 0; i < keys.GetLength(); i++)
                 {
-                    var p = keys.GetOwnProperty(i.ToString()).Value.AsString();
+                    var p = keys.GetOwnProperty(TypeConverter.ToString(i)).Value.AsString();
 
                     if (processedKeys.Contains(p))
                     {

+ 42 - 5
Jint/Runtime/TypeConverter.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Reflection;
+using System.Runtime.CompilerServices;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Number;
@@ -28,6 +29,9 @@ namespace Jint.Runtime
 
     public class TypeConverter
     {
+        private static readonly string[] intToString = new string[1024*10];
+        private static readonly string[] charToString = new string[1024];
+
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.1
         /// </summary>
@@ -226,7 +230,7 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static int ToInt32(JsValue o)
         {
-            return (int)(uint)ToNumber(o);
+            return (int) (uint) ToNumber(o);
         }
 
         /// <summary>
@@ -236,7 +240,7 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static uint ToUint32(JsValue o)
         {
-            return (uint)ToNumber(o);
+            return (uint) ToNumber(o);
         }
 
         /// <summary>
@@ -246,7 +250,40 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static ushort ToUint16(JsValue o)
         {
-            return (ushort)(uint)ToNumber(o);
+            return (ushort) (uint) ToNumber(o);
+        }
+
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static string ToString(long i)
+        {
+            return i >= 0 && i < intToString.Length
+                ? (intToString[i] = intToString[i] ?? i.ToString())
+                : i.ToString();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static string ToString(int i)
+        {
+            return i >= 0 && i < intToString.Length
+                ? (intToString[i] = intToString[i] ?? i.ToString())
+                : i.ToString();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static string ToString(uint i)
+        {
+            return i >= 0 && i < intToString.Length
+                ? (intToString[i] = intToString[i] ?? i.ToString())
+                : i.ToString();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static string ToString(char c)
+        {
+            return c >= 0 && c < charToString.Length
+                ? (charToString[c] = charToString[c] ?? c.ToString())
+                : c.ToString();
         }
 
         /// <summary>
@@ -365,7 +402,7 @@ namespace Jint.Runtime
             if (o != Undefined.Instance && o != Null.Instance)
                 return;
 
-            if (engine.Options._ReferenceResolver != null && 
+            if (engine.Options._ReferenceResolver != null &&
                 engine.Options._ReferenceResolver.CheckCoercible(o))
                 return;
 
@@ -441,4 +478,4 @@ namespace Jint.Runtime
             return !type.IsValueType() || Nullable.GetUnderlyingType(type) != null;
         }
     }
-}
+}