فهرست منبع

Optimize declarative environment record handling for functions (#517)

* #451 optimize declarative environment record handling for functions

* use explicit type field checks as small methods won't inline to small methods
* seal some classes

* #451 inline more hot paths

* #451 use == instead of Equals for doubles as strings, less IL code

* #451 minimize work done in hot paths

* #451 use Dictionary directly in ObjectInstance as it caters better performance

* #451 tweak property setting via direct field

* #451 more tweaks

* #451 use ArrayPrototype.ConstructFast when possible

* #451 improve bounds check performance for .NET Core 2.1
Marko Lahma 7 سال پیش
والد
کامیت
b5c4b570ce

+ 0 - 1
Jint.Benchmark/Properties/AssemblyInfo.cs

@@ -1,5 +1,4 @@
 using System.Reflection;
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 
 
 // General Information about an assembly is controlled through the following 
 // General Information about an assembly is controlled through the following 

+ 83 - 94
Jint/Engine.cs

@@ -28,7 +28,7 @@ using Jint.Runtime.References;
 
 
 namespace Jint
 namespace Jint
 {
 {
-    public class Engine
+    public sealed class Engine
     {
     {
         private static readonly ParserOptions DefaultParserOptions = new ParserOptions
         private static readonly ParserOptions DefaultParserOptions = new ParserOptions
         {
         {
@@ -50,6 +50,8 @@ namespace Jint
         private readonly bool _isDebugMode;
         private readonly bool _isDebugMode;
         private readonly bool _isStrict;
         private readonly bool _isStrict;
         private readonly int _maxStatements;
         private readonly int _maxStatements;
+        private readonly long _memoryLimit;
+        private readonly bool _runBeforeStatementChecks;
         private readonly IReferenceResolver _referenceResolver;
         private readonly IReferenceResolver _referenceResolver;
         
         
         public ITypeConverter ClrTypeConverter;
         public ITypeConverter ClrTypeConverter;
@@ -176,6 +178,11 @@ namespace Jint
             _isStrict = Options.IsStrict;
             _isStrict = Options.IsStrict;
             _maxStatements = Options._MaxStatements;
             _maxStatements = Options._MaxStatements;
             _referenceResolver = Options.ReferenceResolver;
             _referenceResolver = Options.ReferenceResolver;
+            _memoryLimit = Options._MemoryLimit;
+            _runBeforeStatementChecks = (_maxStatements > 0 &&_maxStatements < int.MaxValue) 
+                                        || Options._TimeoutInterval.Ticks > 0
+                                        || _memoryLimit > 0 
+                                        || _isDebugMode;
 
 
             ReferencePool = new ReferencePool();
             ReferencePool = new ReferencePool();
             ArgumentsInstancePool = new ArgumentsInstancePool(this);
             ArgumentsInstancePool = new ArgumentsInstancePool(this);
@@ -364,7 +371,7 @@ namespace Jint
         {
         {
             ResetStatementsCount();
             ResetStatementsCount();
             
             
-            if (Options._MemoryLimit > 0)
+            if (_memoryLimit > 0)
             {
             {
                 ResetMemoryUsage();
                 ResetMemoryUsage();
             }
             }
@@ -405,15 +412,24 @@ namespace Jint
 
 
         public Completion ExecuteStatement(Statement statement)
         public Completion ExecuteStatement(Statement statement)
         {
         {
-            BeforeExecuteStatement(statement);
+            _lastSyntaxNode = statement;
+
+            if (_runBeforeStatementChecks)
+            {
+                BeforeExecuteStatement(statement);
+            }
 
 
             switch (statement.Type)
             switch (statement.Type)
             {
             {
                 case Nodes.BlockStatement:
                 case Nodes.BlockStatement:
-                    return _statements.ExecuteBlockStatement((BlockStatement) statement);
+                    return _statements.ExecuteStatementList(((BlockStatement) statement).Body);
 
 
                 case Nodes.ReturnStatement:
                 case Nodes.ReturnStatement:
-                    return _statements.ExecuteReturnStatement((ReturnStatement) statement);
+                    var jsValue = ((ReturnStatement) statement).Argument == null
+                        ? Undefined.Instance
+                        : GetValue(EvaluateExpression(((ReturnStatement) statement).Argument), true);
+
+                    return new Completion(CompletionType.Return, jsValue, null);
 
 
                 case Nodes.VariableDeclaration:
                 case Nodes.VariableDeclaration:
                     return _statements.ExecuteVariableDeclaration((VariableDeclaration) statement);
                     return _statements.ExecuteVariableDeclaration((VariableDeclaration) statement);
@@ -428,10 +444,13 @@ namespace Jint
                     return _statements.ExecuteDoWhileStatement((DoWhileStatement) statement);
                     return _statements.ExecuteDoWhileStatement((DoWhileStatement) statement);
 
 
                 case Nodes.EmptyStatement:
                 case Nodes.EmptyStatement:
-                    return _statements.ExecuteEmptyStatement((EmptyStatement) statement);
+                    return new Completion(CompletionType.Normal, null, null);
 
 
                 case Nodes.ExpressionStatement:
                 case Nodes.ExpressionStatement:
-                    return _statements.ExecuteExpressionStatement((ExpressionStatement) statement);
+                    return new Completion(
+                        CompletionType.Normal, 
+                        GetValue(EvaluateExpression(((ExpressionStatement) statement).Expression), true),
+                        null);
 
 
                 case Nodes.ForStatement:
                 case Nodes.ForStatement:
                     return _statements.ExecuteForStatement((ForStatement) statement);
                     return _statements.ExecuteForStatement((ForStatement) statement);
@@ -487,14 +506,14 @@ namespace Jint
                 ExceptionHelper.ThrowTimeoutException();
                 ExceptionHelper.ThrowTimeoutException();
             }
             }
 
 
-            if (Options._MemoryLimit > 0)
+            if (_memoryLimit > 0)
             {
             {
                 if (GetAllocatedBytesForCurrentThread != null)
                 if (GetAllocatedBytesForCurrentThread != null)
                 {
                 {
                     var memoryUsage = GetAllocatedBytesForCurrentThread() - _initialMemoryUsage;
                     var memoryUsage = GetAllocatedBytesForCurrentThread() - _initialMemoryUsage;
-                    if (memoryUsage > Options._MemoryLimit)
+                    if (memoryUsage > _memoryLimit)
                     {
                     {
-                        ExceptionHelper.ThrowMemoryLimitExceededException($"Script has allocated {memoryUsage} but is limited to {Options._MemoryLimit}");
+                        ExceptionHelper.ThrowMemoryLimitExceededException($"Script has allocated {memoryUsage} but is limited to {_memoryLimit}");
                     }
                     }
                 }
                 }
                 else
                 else
@@ -503,8 +522,6 @@ namespace Jint
                 }
                 }
             }
             }
 
 
-            _lastSyntaxNode = statement;
-
             if (_isDebugMode)
             if (_isDebugMode)
             {
             {
                 DebugHandler.OnStep(statement);
                 DebugHandler.OnStep(statement);
@@ -577,27 +594,9 @@ namespace Jint
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public JsValue GetValue(object value)
         public JsValue GetValue(object value)
         {
         {
-            if (value is JsValue jsValue)
-            {
-                return jsValue;
-            }
-
-            return GetValueFromReference(value, false);
+            return GetValue(value, false);
         }
         }
         
         
-        
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal JsValue GetValue(in Completion completion)
-        {
-            var value = completion.Value;
-            if (value is JsValue jsValue)
-            {
-                return jsValue;
-            }
-            return GetValueFromReference(completion.Value, false);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal JsValue GetValue(object value, bool returnReferenceToPool)
         internal JsValue GetValue(object value, bool returnReferenceToPool)
         {
         {
             if (value is JsValue jsValue)
             if (value is JsValue jsValue)
@@ -605,21 +604,12 @@ namespace Jint
                 return jsValue;
                 return jsValue;
             }
             }
 
 
-            return GetValueFromReference(value, returnReferenceToPool);
-        }
-       
-        internal JsValue GetValueFromReference(object value, bool returnReferenceToPool)
-        {
-            var reference = value as Reference;
-            if (reference == null)
+            if (!(value is Reference reference))
             {
             {
-                if (value is Completion completion)
-                {
-                    return GetValue(completion.Value, returnReferenceToPool);
-                }
+                return ((Completion) value).Value;
             }
             }
 
 
-            if (reference.IsUnresolvableReference())
+            if (reference._baseValue._type == Types.Undefined)
             {
             {
                 if (_referenceResolver != null &&
                 if (_referenceResolver != null &&
                     _referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
                     _referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
@@ -629,7 +619,7 @@ namespace Jint
                 ExceptionHelper.ThrowReferenceError(this, reference.GetReferencedName() + " is not defined");
                 ExceptionHelper.ThrowReferenceError(this, reference.GetReferencedName() + " is not defined");
             }
             }
 
 
-            var baseValue = reference.GetBase();
+            var baseValue = reference._baseValue;
 
 
             if (reference.IsPropertyReference())
             if (reference.IsPropertyReference())
             {
             {
@@ -639,12 +629,12 @@ namespace Jint
                     return baseValue;
                     return baseValue;
                 }
                 }
 
 
-                var referencedName = reference.GetReferencedName();
+                var referencedName = reference._name;
                 if (returnReferenceToPool)
                 if (returnReferenceToPool)
                 {
                 {
                     ReferencePool.Return(reference);
                     ReferencePool.Return(reference);
                 }
                 }
-                if (reference.HasPrimitiveBase() == false)
+                if (!(reference._baseValue._type != Types.Object && reference._baseValue._type != Types.None))
                 {
                 {
                     var o = TypeConverter.ToObject(this, baseValue);
                     var o = TypeConverter.ToObject(this, baseValue);
                     var v = o.Get(referencedName);
                     var v = o.Get(referencedName);
@@ -681,7 +671,7 @@ namespace Jint
                 ExceptionHelper.ThrowArgumentException();
                 ExceptionHelper.ThrowArgumentException();
             }
             }
 
 
-            var bindingValue = record.GetBindingValue(reference.GetReferencedName(), reference.IsStrict());
+            var bindingValue = record.GetBindingValue(reference._name, reference._strict);
 
 
             if (returnReferenceToPool)
             if (returnReferenceToPool)
             {
             {
@@ -700,7 +690,7 @@ namespace Jint
         {
         {
             if (reference.IsUnresolvableReference())
             if (reference.IsUnresolvableReference())
             {
             {
-                if (reference.IsStrict())
+                if (reference._strict)
                 {
                 {
                     ExceptionHelper.ThrowReferenceError(this);
                     ExceptionHelper.ThrowReferenceError(this);
                 }
                 }
@@ -709,20 +699,20 @@ namespace Jint
             }
             }
             else if (reference.IsPropertyReference())
             else if (reference.IsPropertyReference())
             {
             {
-                var baseValue = reference.GetBase();
+                var baseValue = reference._baseValue;
                 if (!reference.HasPrimitiveBase())
                 if (!reference.HasPrimitiveBase())
                 {
                 {
-                    baseValue.AsObject().Put(reference.GetReferencedName(), value, reference.IsStrict());
+                    baseValue.AsObject().Put(reference._name, value, reference._strict);
                 }
                 }
                 else
                 else
                 {
                 {
-                    PutPrimitiveBase(baseValue, reference.GetReferencedName(), value, reference.IsStrict());
+                    PutPrimitiveBase(baseValue, reference._name, value, reference._strict);
                 }
                 }
             }
             }
             else
             else
             {
             {
-                var baseValue = reference.GetBase();
-                ((EnvironmentRecord) baseValue).SetMutableBinding(reference.GetReferencedName(), value, reference.IsStrict());
+                var baseValue = reference._baseValue;
+                ((EnvironmentRecord) baseValue).SetMutableBinding(reference.GetReferencedName(), value, reference._strict);
             }
             }
         }
         }
 
 
@@ -871,20 +861,34 @@ namespace Jint
             bool configurableBindings = declarationBindingType == DeclarationBindingType.EvalCode;
             bool configurableBindings = declarationBindingType == DeclarationBindingType.EvalCode;
             var strict = StrictModeScope.IsStrictModeCode;
             var strict = StrictModeScope.IsStrictModeCode;
 
 
+            var der = env as DeclarativeEnvironmentRecord;
+            bool canReleaseArgumentsInstance = false;
             if (declarationBindingType == DeclarationBindingType.FunctionCode)
             if (declarationBindingType == DeclarationBindingType.FunctionCode)
             {
             {
-                var parameters = functionInstance.FormalParameters;
-                for (var i = 0; i < parameters.Length; i++)
+                var argsObj = ArgumentsInstancePool.Rent(functionInstance, functionInstance.FormalParameters, arguments, env, strict);
+                canReleaseArgumentsInstance = true;
+
+                if (!ReferenceEquals(der, null))
+                {
+                    der.AddFunctionParameters(functionInstance, arguments, argsObj);
+                }
+                else
                 {
                 {
-                    var argName = parameters[i];
-                    var v = i + 1 > arguments.Length ? Undefined.Instance : arguments[i];
-                    var argAlreadyDeclared = env.HasBinding(argName);
-                    if (!argAlreadyDeclared)
+                    // slow path
+                    var parameters = functionInstance.FormalParameters;
+                    for (var i = 0; i < parameters.Length; i++)
                     {
                     {
-                        env.CreateMutableBinding(argName, v);
-                    }
+                        var argName = parameters[i];
+                        var v = i + 1 > arguments.Length ? Undefined.Instance : arguments[i];
+                        var argAlreadyDeclared = env.HasBinding(argName);
+                        if (!argAlreadyDeclared)
+                        {
+                            env.CreateMutableBinding(argName, v);
+                        }
 
 
-                    env.SetMutableBinding(argName, v, strict);
+                        env.SetMutableBinding(argName, v, strict);
+                    }
+                    env.CreateMutableBinding("arguments", argsObj);
                 }
                 }
             }
             }
 
 
@@ -929,43 +933,28 @@ namespace Jint
                 env.SetMutableBinding(fn, fo, strict);
                 env.SetMutableBinding(fn, fo, strict);
             }
             }
 
 
-            bool canReleaseArgumentsInstance = false;
-            if (declarationBindingType == DeclarationBindingType.FunctionCode && !env.HasBinding("arguments"))
+            // process all variable declarations in the current parser scope
+            if (!ReferenceEquals(der, null))
             {
             {
-                var argsObj = ArgumentsInstancePool.Rent(functionInstance, functionInstance.FormalParameters, arguments, env, strict);
-                canReleaseArgumentsInstance = true;
-
-                if (strict)
-                {
-                    var declEnv = env as DeclarativeEnvironmentRecord;
-
-                    if (ReferenceEquals(declEnv, null))
-                    {
-                        ExceptionHelper.ThrowArgumentException();
-                    }
-
-                    declEnv.CreateImmutableBinding("arguments", argsObj);
-                }
-                else
-                {
-                    env.CreateMutableBinding("arguments", argsObj);
-                }
+                der.AddVariableDeclarations(variableDeclarations);
             }
             }
-
-            // process all variable declarations in the current parser scope
-            var variableDeclarationsCount = variableDeclarations.Count;
-            for (var i = 0; i < variableDeclarationsCount; i++)
+            else
             {
             {
-                var variableDeclaration = variableDeclarations[i];
-                var declarationsCount = variableDeclaration.Declarations.Count;
-                for (var j = 0; j < declarationsCount; j++)
+                // slow path
+                var variableDeclarationsCount = variableDeclarations.Count;
+                for (var i = 0; i < variableDeclarationsCount; i++)
                 {
                 {
-                    var d = variableDeclaration.Declarations[j];
-                    var dn = ((Identifier) d.Id).Name;
-                    var varAlreadyDeclared = env.HasBinding(dn);
-                    if (!varAlreadyDeclared)
+                    var variableDeclaration = variableDeclarations[i];
+                    var declarationsCount = variableDeclaration.Declarations.Count;
+                    for (var j = 0; j < declarationsCount; j++)
                     {
                     {
-                        env.CreateMutableBinding(dn, Undefined.Instance);
+                        var d = variableDeclaration.Declarations[j];
+                        var dn = ((Identifier) d.Id).Name;
+                        var varAlreadyDeclared = env.HasBinding(dn);
+                        if (!varAlreadyDeclared)
+                        {
+                            env.CreateMutableBinding(dn, Undefined.Instance);
+                        }
                     }
                     }
                 }
                 }
             }
             }

+ 1 - 1
Jint/Native/Argument/ArgumentsInstance.cs

@@ -12,7 +12,7 @@ namespace Jint.Native.Argument
     /// <summary>
     /// <summary>
     /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
     /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
     /// </summary>
     /// </summary>
-    public class ArgumentsInstance : ObjectInstance
+    public sealed class ArgumentsInstance : ObjectInstance
     {
     {
         // cache key container for array iteration for less allocations
         // cache key container for array iteration for less allocations
         private static readonly ThreadLocal<HashSet<string>> _mappedNamed = new ThreadLocal<HashSet<string>>(() => new HashSet<string>());
         private static readonly ThreadLocal<HashSet<string>> _mappedNamed = new ThreadLocal<HashSet<string>>(() => new HashSet<string>());

+ 11 - 7
Jint/Native/Array/ArrayConstructor.cs

@@ -1,4 +1,5 @@
 using System.Collections;
 using System.Collections;
+using System.Runtime.CompilerServices;
 using Jint.Native.Function;
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime;
@@ -92,12 +93,12 @@ namespace Jint.Native.Array
             if (arguments.Length == 1 && arguments.At(0).IsNumber())
             if (arguments.Length == 1 && arguments.At(0).IsNumber())
             {
             {
                 var length = TypeConverter.ToUint32(arguments.At(0));
                 var length = TypeConverter.ToUint32(arguments.At(0));
-                if (!TypeConverter.ToNumber(arguments[0]).Equals(length))
+                if (((JsNumber) arguments[0])._value != length)
                 {
                 {
                     ExceptionHelper.ThrowRangeError(_engine, "Invalid array length");
                     ExceptionHelper.ThrowRangeError(_engine, "Invalid array length");
                 }
                 }
 
 
-                instance.SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.OnlyWritable));
+                instance._length = new PropertyDescriptor(length, PropertyFlag.OnlyWritable);
             }
             }
             else if (arguments.Length == 1 && arguments[0] is ObjectWrapper objectWrapper)
             else if (arguments.Length == 1 && arguments[0] is ObjectWrapper objectWrapper)
             {
             {
@@ -117,7 +118,7 @@ namespace Jint.Native.Array
             }
             }
             else
             else
             {
             {
-                instance.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
+                instance._length = new PropertyDescriptor(0, PropertyFlag.OnlyWritable);
                 if (arguments.Length > 0)
                 if (arguments.Length > 0)
                 {
                 {
                     PrototypeObject.Push(instance, arguments);
                     PrototypeObject.Push(instance, arguments);
@@ -127,12 +128,15 @@ namespace Jint.Native.Array
             return instance;
             return instance;
         }
         }
 
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal ArrayInstance ConstructFast(uint length)
         internal ArrayInstance ConstructFast(uint length)
         {
         {
-            var instance = new ArrayInstance(Engine, length);
-            instance.Prototype = PrototypeObject;
-            instance.Extensible = true;
-            instance.SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.OnlyWritable));
+            var instance = new ArrayInstance(Engine, length)
+            {
+                Prototype = PrototypeObject,
+                Extensible = true,
+                _length = new PropertyDescriptor(length, PropertyFlag.OnlyWritable)
+            };
             return instance;
             return instance;
         }
         }
     }
     }

+ 8 - 21
Jint/Native/Array/ArrayInstance.cs

@@ -16,7 +16,7 @@ namespace Jint.Native.Array
         private const string PropertyNameLength = "length";
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
         private const int PropertyNameLengthLength = 6;
 
 
-        private PropertyDescriptor _length;
+        internal PropertyDescriptor _length;
 
 
         private const int MaxDenseArrayLength = 1024 * 10;
         private const int MaxDenseArrayLength = 1024 * 10;
 
 
@@ -295,7 +295,7 @@ namespace Jint.Native.Array
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public uint GetLength()
         public uint GetLength()
         {
         {
-            return (uint) ((JsNumber) _length.Value)._value;
+            return (uint) ((JsNumber) _length._value)._value;
         }
         }
 
 
         protected override void AddProperty(string propertyName, PropertyDescriptor descriptor)
         protected override void AddProperty(string propertyName, PropertyDescriptor descriptor)
@@ -526,21 +526,9 @@ namespace Jint.Native.Array
         {
         {
             value = Undefined;
             value = Undefined;
 
 
-            if (!TryGetDescriptor(index, out var desc)
-                || desc == null
-                || desc == PropertyDescriptor.Undefined
-                || (ReferenceEquals(desc.Value, null) && ReferenceEquals(desc.Get, null)))
-            {
-                desc = GetProperty(TypeConverter.ToString(index));
-            }
-
-            if (desc != null && desc != PropertyDescriptor.Undefined)
-            {
-                bool success = desc.TryGetValue(this, out value);
-                return success;
-            }
-
-            return false;
+            TryGetDescriptor(index, out var desc);
+            desc = desc ?? GetProperty(TypeConverter.ToString(index)) ?? PropertyDescriptor.Undefined; 
+            return desc.TryGetValue(this, out value);
         }
         }
 
 
         internal bool DeleteAt(uint index)
         internal bool DeleteAt(uint index)
@@ -566,13 +554,12 @@ namespace Jint.Native.Array
         {
         {
             if (_dense != null)
             if (_dense != null)
             {
             {
-                if (index >= _dense.Length)
+                descriptor = null;
+                if (index < _dense.Length)
                 {
                 {
-                    descriptor = null;
-                    return false;
+                    descriptor = _dense[index];
                 }
                 }
 
 
-                descriptor = _dense[index];
                 return descriptor != null;
                 return descriptor != null;
             }
             }
 
 

+ 2 - 9
Jint/Native/Array/ArrayPrototype.cs

@@ -213,11 +213,7 @@ namespace Jint.Native.Array
             var thisArg = arguments.At(1);
             var thisArg = arguments.At(1);
             var callable = GetCallable(callbackfn);
             var callable = GetCallable(callbackfn);
 
 
-            var jsValues = Engine.JsValueArrayPool.RentArray(1);
-            jsValues[0] = len;
-            var a = Engine.Array.Construct(jsValues, len);
-            Engine.JsValueArrayPool.ReturnArray(jsValues);
-            
+            var a = Engine.Array.ConstructFast(len);
             var args = Engine.JsValueArrayPool.RentArray(3);
             var args = Engine.JsValueArrayPool.RentArray(3);
             for (uint k = 0; k < len; k++)
             for (uint k = 0; k < len; k++)
             {
             {
@@ -230,10 +226,7 @@ namespace Jint.Native.Array
                     a.SetIndexValue(k, mappedValue, updateLength: false);
                     a.SetIndexValue(k, mappedValue, updateLength: false);
                 }
                 }
             }
             }
-
-            a.SetLength(len);
             Engine.JsValueArrayPool.ReturnArray(args);
             Engine.JsValueArrayPool.ReturnArray(args);
-
             return a;
             return a;
         }
         }
 
 
@@ -1049,7 +1042,7 @@ namespace Jint.Native.Array
 
 
                 public override uint GetSmallestIndex() => _array.GetSmallestIndex();
                 public override uint GetSmallestIndex() => _array.GetSmallestIndex();
 
 
-                public override uint GetLength() => _array.GetLength();
+                public override uint GetLength() => (uint) ((JsNumber) _array._length._value)._value;
 
 
                 public override void SetLength(uint length) => _array.Put("length", length, true);
                 public override void SetLength(uint length) => _array.Put("length", length, true);
 
 

+ 1 - 1
Jint/Native/Error/ErrorConstructor.cs

@@ -5,7 +5,7 @@ using Jint.Runtime.Descriptors;
 
 
 namespace Jint.Native.Error
 namespace Jint.Native.Error
 {
 {
-    public class ErrorConstructor : FunctionInstance, IConstructor
+    public sealed class ErrorConstructor : FunctionInstance, IConstructor
     {
     {
         private string _name;
         private string _name;
 
 

+ 1 - 1
Jint/Native/Function/BindFunctionInstance.cs

@@ -4,7 +4,7 @@ using Jint.Runtime;
 
 
 namespace Jint.Native.Function
 namespace Jint.Native.Function
 {
 {
-    public class BindFunctionInstance : FunctionInstance, IConstructor
+    public sealed class BindFunctionInstance : FunctionInstance, IConstructor
     {
     {
         public BindFunctionInstance(Engine engine) : base(engine, System.Array.Empty<string>(), null, false)
         public BindFunctionInstance(Engine engine) : base(engine, System.Array.Empty<string>(), null, false)
         {
         {

+ 5 - 4
Jint/Native/Function/EvalFunctionInstance.cs

@@ -6,7 +6,7 @@ using Jint.Runtime.Environments;
 
 
 namespace Jint.Native.Function
 namespace Jint.Native.Function
 {
 {
-    public class EvalFunctionInstance: FunctionInstance
+    public sealed class EvalFunctionInstance : FunctionInstance
     {
     {
         private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
         private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
 
 
@@ -23,12 +23,13 @@ namespace Jint.Native.Function
 
 
         public JsValue Call(JsValue thisObject, JsValue[] arguments, bool directCall)
         public JsValue Call(JsValue thisObject, JsValue[] arguments, bool directCall)
         {
         {
-            if (arguments.At(0).Type != Types.String)
+            var arg = arguments.At(0);
+            if (arg.Type != Types.String)
             {
             {
-                return arguments.At(0);
+                return arg;
             }
             }
 
 
-            var code = TypeConverter.ToString(arguments.At(0));
+            var code = TypeConverter.ToString(arg);
 
 
             try
             try
             {
             {

+ 2 - 2
Jint/Native/Function/FunctionInstance.cs

@@ -10,11 +10,11 @@ namespace Jint.Native.Function
     {
     {
         private const string PropertyNamePrototype = "prototype";
         private const string PropertyNamePrototype = "prototype";
         private const int PropertyNamePrototypeLength = 9;
         private const int PropertyNamePrototypeLength = 9;
-        private PropertyDescriptor _prototype;
+        protected PropertyDescriptor _prototype;
 
 
         private const string PropertyNameLength = "length";
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
         private const int PropertyNameLengthLength = 6;
-        private PropertyDescriptor _length;
+        protected PropertyDescriptor _length;
         
         
         protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironment scope, bool strict)
         protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironment scope, bool strict)
             : this(engine, parameters, scope, strict, objectClass: "Function")
             : this(engine, parameters, scope, strict, objectClass: "Function")

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

@@ -36,7 +36,7 @@ namespace Jint.Native.Function
             Extensible = true;
             Extensible = true;
             Prototype = _engine.Function.PrototypeObject;
             Prototype = _engine.Function.PrototypeObject;
 
 
-            DefineOwnProperty("length", new PropertyDescriptor(JsNumber.Create(FormalParameters.Length), PropertyFlag.AllForbidden), false);
+            _length = new PropertyDescriptor(JsNumber.Create(FormalParameters.Length), PropertyFlag.AllForbidden);
 
 
             var proto = new ObjectInstanceWithConstructor(engine, this)
             var proto = new ObjectInstanceWithConstructor(engine, this)
             {
             {
@@ -44,7 +44,7 @@ namespace Jint.Native.Function
                 Prototype = _engine.Object.PrototypeObject
                 Prototype = _engine.Object.PrototypeObject
             };
             };
 
 
-            SetOwnProperty("prototype", new PropertyDescriptor(proto, PropertyFlag.OnlyWritable));
+            _prototype = new PropertyDescriptor(proto, PropertyFlag.OnlyWritable);
 
 
             if (_functionDeclaration.Id != null)
             if (_functionDeclaration.Id != null)
             {
             {
@@ -150,11 +150,11 @@ namespace Jint.Native.Function
                 {
                 {
                     thisBinding = thisArg;
                     thisBinding = thisArg;
                 }
                 }
-                else if (thisArg.IsUndefined() || thisArg.IsNull())
+                else if (thisArg._type == Types.Undefined || thisArg._type == Types.Null)
                 {
                 {
                     thisBinding = _engine.Global;
                     thisBinding = _engine.Global;
                 }
                 }
-                else if (!thisArg.IsObject())
+                else if (thisArg._type != Types.Object)
                 {
                 {
                     thisBinding = TypeConverter.ToObject(_engine, thisArg);
                     thisBinding = TypeConverter.ToObject(_engine, thisArg);
                 }
                 }

+ 1 - 1
Jint/Native/JsString.cs

@@ -191,7 +191,7 @@ namespace Jint.Native
                         return false;
                         return false;
                     }
                     }
 
 
-                    return ToString().Equals(otherString);
+                    return ToString() == otherString;
                 }
                 }
 
 
                 return base.Equals(other);
                 return base.Equals(other);

+ 1 - 1
Jint/Native/JsValue.cs

@@ -181,7 +181,7 @@ namespace Jint.Native
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public T TryCast<T>(Action<JsValue> fail = null) where T : class
         public T TryCast<T>(Action<JsValue> fail = null) where T : class
         {
         {
-            if (IsObject())
+            if (_type == Types.Object)
             {
             {
                 if (this is T o)
                 if (this is T o)
                 {
                 {

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

@@ -55,7 +55,7 @@ namespace Jint.Native.Number
                 return "NaN";
                 return "NaN";
             }
             }
 
 
-            if (m.Equals(0))
+            if (m == 0)
             {
             {
                 return "0";
                 return "0";
             }
             }
@@ -188,7 +188,7 @@ namespace Jint.Native.Number
                 return "NaN";
                 return "NaN";
             }
             }
 
 
-            if (x.Equals(0))
+            if (x == 0)
             {
             {
                 return "0";
                 return "0";
             }
             }
@@ -212,7 +212,7 @@ namespace Jint.Native.Number
             var fraction = x -  integer;
             var fraction = x -  integer;
 
 
             string result = ToBase(integer, radix);
             string result = ToBase(integer, radix);
-            if (!fraction.Equals(0))
+            if (fraction != 0)
             {
             {
                 result += "." + ToFractionBase(fraction, radix);
                 result += "." + ToFractionBase(fraction, radix);
             }
             }
@@ -245,7 +245,7 @@ namespace Jint.Native.Number
             // http://www.mathpath.org/concepts/Num/frac.htm
             // http://www.mathpath.org/concepts/Num/frac.htm
 
 
             const string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
             const string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
-            if (n.Equals(0))
+            if (n == 0)
             {
             {
                 return "0";
                 return "0";
             }
             }
@@ -270,7 +270,7 @@ namespace Jint.Native.Number
                 return "NaN";
                 return "NaN";
             }
             }
 
 
-            if (m.Equals(0))
+            if (m == 0)
             {
             {
                 return "0";
                 return "0";
             }
             }

+ 2 - 7
Jint/Native/Object/ObjectConstructor.cs

@@ -145,7 +145,7 @@ namespace Jint.Native.Object
             if (o is StringInstance s)
             if (o is StringInstance s)
             {
             {
                 var length = s.PrimitiveValue.AsStringWithoutTypeCheck().Length;
                 var length = s.PrimitiveValue.AsStringWithoutTypeCheck().Length;
-                array = Engine.Array.Construct(ownProperties.Count + length);
+                array = Engine.Array.ConstructFast((uint) (ownProperties.Count + length));
                 for (var i = 0; i < length; i++)
                 for (var i = 0; i < length; i++)
                 {
                 {
                     array.SetIndexValue(n, TypeConverter.ToString(i), updateLength: false);
                     array.SetIndexValue(n, TypeConverter.ToString(i), updateLength: false);
@@ -402,11 +402,7 @@ namespace Jint.Native.Object
                 .ToArray();
                 .ToArray();
             var n = enumerableProperties.Length;
             var n = enumerableProperties.Length;
 
 
-            var args = _engine.JsValueArrayPool.RentArray(1);
-            args[0] = n;
-            var array = Engine.Array.Construct(args, (uint) n);
-            _engine.JsValueArrayPool.ReturnArray(args);
-
+            var array = Engine.Array.ConstructFast((uint) n);
             uint index = 0;
             uint index = 0;
             foreach (var prop in enumerableProperties)
             foreach (var prop in enumerableProperties)
             {
             {
@@ -414,7 +410,6 @@ namespace Jint.Native.Object
                 array.SetIndexValue(index, p, updateLength: false);
                 array.SetIndexValue(index, p, updateLength: false);
                 index++;
                 index++;
             }
             }
-            array.SetLength(index);
             return array;
             return array;
         }
         }
     }
     }

+ 16 - 23
Jint/Native/Object/ObjectInstance.cs

@@ -18,18 +18,17 @@ namespace Jint.Native.Object
 {
 {
     public class ObjectInstance : JsValue, IEquatable<ObjectInstance>
     public class ObjectInstance : JsValue, IEquatable<ObjectInstance>
     {
     {
-        private MruPropertyCache2<PropertyDescriptor> _intrinsicProperties;
-        private MruPropertyCache2<PropertyDescriptor> _properties;
+        private Dictionary<string, PropertyDescriptor> _intrinsicProperties;
+        private Dictionary<string, PropertyDescriptor> _properties;
         
         
         private readonly string _class;
         private readonly string _class;
         protected readonly Engine _engine;
         protected readonly Engine _engine;
         
         
         public ObjectInstance(Engine engine) : this(engine, "Object")
         public ObjectInstance(Engine engine) : this(engine, "Object")
         {
         {
-            _engine = engine;
         }
         }
         
         
-        protected ObjectInstance(Engine engine, in string objectClass) : base(Types.Object)
+        protected ObjectInstance(Engine engine, string objectClass) : base(Types.Object)
         {
         {
             _engine = engine;
             _engine = engine;
             _class = objectClass;
             _class = objectClass;
@@ -63,7 +62,7 @@ namespace Jint.Native.Object
         {
         {
             if (_intrinsicProperties == null)
             if (_intrinsicProperties == null)
             {
             {
-                _intrinsicProperties = new MruPropertyCache2<PropertyDescriptor>();
+                _intrinsicProperties = new Dictionary<string, PropertyDescriptor>(StringComparer.Ordinal);
             }
             }
 
 
             _intrinsicProperties[symbol.AsSymbol()] = new PropertyDescriptor(value, writable, enumerable, configurable);
             _intrinsicProperties[symbol.AsSymbol()] = new PropertyDescriptor(value, writable, enumerable, configurable);
@@ -84,7 +83,7 @@ namespace Jint.Native.Object
         /// A String value indicating a specification defined
         /// A String value indicating a specification defined
         /// classification of objects.
         /// classification of objects.
         /// </summary>
         /// </summary>
-        public ref readonly string Class => ref _class;
+        public string Class => _class;
 
 
         public virtual IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         public virtual IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
         {
@@ -92,7 +91,7 @@ namespace Jint.Native.Object
 
 
             if (_properties != null)
             if (_properties != null)
             {
             {
-                foreach (var pair in _properties.GetEnumerator())
+                foreach (var pair in _properties)
                 {
                 {
                     yield return pair;
                     yield return pair;
                 }
                 }
@@ -103,7 +102,7 @@ namespace Jint.Native.Object
         {
         {
             if (_properties == null)
             if (_properties == null)
             {
             {
-                _properties = new MruPropertyCache2<PropertyDescriptor>();
+                _properties = new Dictionary<string, PropertyDescriptor>(StringComparer.Ordinal);
             }
             }
 
 
             _properties.Add(propertyName, descriptor);
             _properties.Add(propertyName, descriptor);
@@ -124,7 +123,7 @@ namespace Jint.Native.Object
         {
         {
             EnsureInitialized();
             EnsureInitialized();
 
 
-            return _properties?.ContainsKey(propertyName) ?? false;
+            return _properties?.ContainsKey(propertyName) == true;
         }
         }
 
 
         public virtual void RemoveOwnProperty(string propertyName)
         public virtual void RemoveOwnProperty(string propertyName)
@@ -154,7 +153,9 @@ namespace Jint.Native.Object
                 return Undefined;
                 return Undefined;
             }
             }
 
 
-            if (desc.IsDataDescriptor())
+            // IsDataDescriptor inlined
+            if ((desc._flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0 
+                || !ReferenceEquals(desc.Value, null))
             {
             {
                 var val = desc.Value;
                 var val = desc.Value;
                 return val ?? Undefined;
                 return val ?? Undefined;
@@ -183,12 +184,9 @@ namespace Jint.Native.Object
         {
         {
             EnsureInitialized();
             EnsureInitialized();
 
 
-            if (_properties != null && _properties.TryGetValue(propertyName, out var x))
-            {
-                return x;
-            }
-
-            return PropertyDescriptor.Undefined;
+            PropertyDescriptor descriptor = null;
+            _properties?.TryGetValue(propertyName, out descriptor);
+            return descriptor ?? PropertyDescriptor.Undefined;
         }
         }
 
 
         protected internal virtual void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         protected internal virtual void SetOwnProperty(string propertyName, PropertyDescriptor desc)
@@ -197,7 +195,7 @@ namespace Jint.Native.Object
 
 
             if (_properties == null)
             if (_properties == null)
             {
             {
-                _properties = new MruPropertyCache2<PropertyDescriptor>();
+                _properties = new Dictionary<string, PropertyDescriptor>();
             }
             }
 
 
             _properties[propertyName] = desc;
             _properties[propertyName] = desc;
@@ -218,12 +216,7 @@ namespace Jint.Native.Object
                 return prop;
                 return prop;
             }
             }
 
 
-            if (ReferenceEquals(Prototype, null))
-            {
-                return PropertyDescriptor.Undefined;
-            }
-
-            return Prototype.GetProperty(propertyName);
+            return Prototype?.GetProperty(propertyName) ?? PropertyDescriptor.Undefined;
         }
         }
 
 
         public bool TryGetValue(string propertyName, out JsValue value)
         public bool TryGetValue(string propertyName, out JsValue value)

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

@@ -395,18 +395,18 @@ namespace Jint.Native.String
             TypeConverter.CheckObjectCoercible(Engine, thisObj);
             TypeConverter.CheckObjectCoercible(Engine, thisObj);
 
 
             var start = TypeConverter.ToNumber(arguments.At(0));
             var start = TypeConverter.ToNumber(arguments.At(0));
-            if (double.NegativeInfinity.Equals(start))
+            if (double.IsNegativeInfinity(start))
             {
             {
                 start = 0;
                 start = 0;
             }
             }
-            if (double.PositiveInfinity.Equals(start))
+            if (double.IsPositiveInfinity(start))
             {
             {
                 return string.Empty;
                 return string.Empty;
             }
             }
 
 
             var s = TypeConverter.ToString(thisObj);
             var s = TypeConverter.ToString(thisObj);
             var end = TypeConverter.ToNumber(arguments.At(1));
             var end = TypeConverter.ToNumber(arguments.At(1));
-            if (double.PositiveInfinity.Equals(end))
+            if (double.IsPositiveInfinity(end))
             {
             {
                 end = s.Length;
                 end = s.Length;
             }
             }

+ 2 - 7
Jint/Options.cs

@@ -3,13 +3,12 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using Jint.Native;
 using Jint.Native;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
 
 
 namespace Jint
 namespace Jint
 {
 {
-    public class Options
+    public sealed class Options
     {
     {
         private bool _discardGlobal;
         private bool _discardGlobal;
         private bool _strict;
         private bool _strict;
@@ -177,11 +176,7 @@ namespace Jint
 
 
         internal long _MemoryLimit => _memoryLimit;
         internal long _MemoryLimit => _memoryLimit;
 
 
-        internal int _MaxStatements
-        {
-            [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get { return _maxStatements; }
-        }
+        internal int _MaxStatements => _maxStatements;
 
 
         internal int MaxRecursionDepth => _maxRecursionDepth;
         internal int MaxRecursionDepth => _maxRecursionDepth;
 
 

+ 5 - 5
Jint/Pooling/ObjectPool.cs

@@ -134,7 +134,7 @@ namespace Jint.Pooling
             // We will interlock only when we have a candidate. in a worst case we may miss some
             // We will interlock only when we have a candidate. in a worst case we may miss some
             // recently returned objects. Not a big deal.
             // recently returned objects. Not a big deal.
             T inst = _firstItem;
             T inst = _firstItem;
-            if (inst != null)
+            if (!ReferenceEquals(inst, null))
             {
             {
                 _firstItem = null;
                 _firstItem = null;
                 return inst;
                 return inst;
@@ -161,7 +161,7 @@ namespace Jint.Pooling
             for (int i = 0; i < items.Length; i++)
             for (int i = 0; i < items.Length; i++)
             {
             {
                 T inst = items[i].Value;
                 T inst = items[i].Value;
-                if (inst != null)
+                if (!ReferenceEquals(inst, null))
                 {
                 {
                     items[i].Value = null;
                     items[i].Value = null;
                     return inst;
                     return inst;
@@ -184,7 +184,7 @@ namespace Jint.Pooling
             Validate(obj);
             Validate(obj);
             ForgetTrackedObject(obj);
             ForgetTrackedObject(obj);
  
  
-            if (_firstItem == null)
+            if (ReferenceEquals(_firstItem, null))
             {
             {
                 // Intentionally not using interlocked here. 
                 // Intentionally not using interlocked here. 
                 // In a worst case scenario two objects may be stored into same slot.
                 // In a worst case scenario two objects may be stored into same slot.
@@ -202,7 +202,7 @@ namespace Jint.Pooling
             var items = _items;
             var items = _items;
             for (int i = 0; i < items.Length; i++)
             for (int i = 0; i < items.Length; i++)
             {
             {
-                if (items[i].Value == null)
+                if (ReferenceEquals(items[i].Value, null))
                 {
                 {
                     // Intentionally not using interlocked here. 
                     // Intentionally not using interlocked here. 
                     // In a worst case scenario two objects may be stored into same slot.
                     // In a worst case scenario two objects may be stored into same slot.
@@ -265,7 +265,7 @@ namespace Jint.Pooling
             for (int i = 0; i < items.Length; i++)
             for (int i = 0; i < items.Length; i++)
             {
             {
                 var value = items[i].Value;
                 var value = items[i].Value;
-                if (value == null)
+                if (ReferenceEquals(value, null))
                 {
                 {
                     return;
                     return;
                 }
                 }

+ 5 - 5
Jint/Runtime/Debugger/BreakPoint.cs

@@ -1,11 +1,7 @@
 namespace Jint.Runtime.Debugger
 namespace Jint.Runtime.Debugger
 {
 {
-    public class BreakPoint
+    public sealed class BreakPoint
     {
     {
-        public int Line { get; set; }
-        public int Char { get; set; }
-        public string Condition { get; set; }
-
         public BreakPoint(int line, int character)
         public BreakPoint(int line, int character)
         {
         {
             Line = line;
             Line = line;
@@ -17,5 +13,9 @@
         {
         {
             Condition = condition;
             Condition = condition;
         }
         }
+
+        public int Line { get; }
+        public int Char { get; }
+        public string Condition { get; }
     }
     }
 }
 }

+ 27 - 14
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -9,8 +9,8 @@ namespace Jint.Runtime.Descriptors
     {
     {
         public static readonly PropertyDescriptor Undefined = new PropertyDescriptor(PropertyFlag.None);
         public static readonly PropertyDescriptor Undefined = new PropertyDescriptor(PropertyFlag.None);
 
 
-        private PropertyFlag _flags;
-        private JsValue _value;
+        internal PropertyFlag _flags;
+        internal JsValue _value;
 
 
         protected PropertyDescriptor(PropertyFlag flags)
         protected PropertyDescriptor(PropertyFlag flags)
         {
         {
@@ -19,12 +19,20 @@ namespace Jint.Runtime.Descriptors
         
         
         protected internal PropertyDescriptor(JsValue value, PropertyFlag flags) : this(flags)
         protected internal PropertyDescriptor(JsValue value, PropertyFlag flags) : this(flags)
         {
         {
-            Value = value;
+            if ((_flags & PropertyFlag.CustomJsValue) != 0)
+            {
+                CustomValue = value;
+            }
+            _value = value;
         }
         }
 
 
         public PropertyDescriptor(JsValue value, bool? writable, bool? enumerable, bool? configurable)
         public PropertyDescriptor(JsValue value, bool? writable, bool? enumerable, bool? configurable)
         {
         {
-            Value = value;
+            if ((_flags & PropertyFlag.CustomJsValue) != 0)
+            {
+                CustomValue = value;
+            }
+            _value = value;  
 
 
             if (writable != null)
             if (writable != null)
             {
             {
@@ -326,7 +334,9 @@ namespace Jint.Runtime.Descriptors
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool IsDataDescriptor()
         public bool IsDataDescriptor()
         {
         {
-            return WritableSet || !ReferenceEquals(Value, null);
+            return (_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0 
+                   || (_flags & PropertyFlag.CustomJsValue) != 0 && !ReferenceEquals(CustomValue, null)
+                   || !ReferenceEquals(_value, null);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -344,22 +354,25 @@ namespace Jint.Runtime.Descriptors
         {
         {
             value = JsValue.Undefined;
             value = JsValue.Undefined;
 
 
-            if (this == Undefined)
-            {
-                value = JsValue.Undefined;
-                return false;
-            }
-
-            if (IsDataDescriptor())
+            // IsDataDescriptor logic inlined
+            if ((_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0)
             {
             {
-                var val = Value;
+                var val = (_flags & PropertyFlag.CustomJsValue) != 0
+                    ? CustomValue
+                    : _value;
+                
                 if (!ReferenceEquals(val, null))
                 if (!ReferenceEquals(val, null))
                 {
                 {
                     value = val;
                     value = val;
                     return true;
                     return true;
                 }
                 }
             }
             }
-
+            
+            if (this == Undefined)
+            {
+                return false;
+            }
+            
             var getter = Get;
             var getter = Get;
             if (!ReferenceEquals(getter, null) && !getter.IsUndefined())
             if (!ReferenceEquals(getter, null) && !getter.IsUndefined())
             {
             {

+ 1 - 1
Jint/Runtime/Environments/Binding.cs

@@ -2,7 +2,7 @@
 
 
 namespace Jint.Runtime.Environments
 namespace Jint.Runtime.Environments
 {
 {
-    public class Binding
+    public sealed class Binding
     {
     {
         public JsValue Value;
         public JsValue Value;
         public bool CanBeDeleted;
         public bool CanBeDeleted;

+ 101 - 9
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -1,6 +1,9 @@
 using System;
 using System;
+using System.Collections.Generic;
+using Esprima.Ast;
 using Jint.Native;
 using Jint.Native;
 using Jint.Native.Argument;
 using Jint.Native.Argument;
+using Jint.Native.Function;
 
 
 namespace Jint.Runtime.Environments
 namespace Jint.Runtime.Environments
 {
 {
@@ -21,9 +24,9 @@ namespace Jint.Runtime.Environments
 
 
         public override bool HasBinding(string name)
         public override bool HasBinding(string name)
         {
         {
-            if (_argumentsBinding != null && name.Length == 9 && name == BindingNameArguments)
+            if (name.Length == 9 && name == BindingNameArguments)
             {
             {
-                return true;
+                return _argumentsBinding != null;
             }
             }
 
 
             return _bindings?.ContainsKey(name) == true;
             return _bindings?.ContainsKey(name) == true;
@@ -34,11 +37,11 @@ namespace Jint.Runtime.Environments
             var binding = new Binding
             var binding = new Binding
             {
             {
                 Value = value,
                 Value = value,
-                CanBeDeleted =  canBeDeleted,
+                CanBeDeleted = canBeDeleted,
                 Mutable = true
                 Mutable = true
             };
             };
 
 
-            if (name == BindingNameArguments)
+            if (name.Length == 9 && name == BindingNameArguments)
             {
             {
                 _argumentsBinding = binding;
                 _argumentsBinding = binding;
             }
             }
@@ -48,6 +51,7 @@ namespace Jint.Runtime.Environments
                 {
                 {
                     _bindings = new MruPropertyCache2<Binding>();
                     _bindings = new MruPropertyCache2<Binding>();
                 }
                 }
+
                 _bindings.Add(name, binding);
                 _bindings.Add(name, binding);
             }
             }
         }
         }
@@ -59,7 +63,10 @@ namespace Jint.Runtime.Environments
                 _bindings = new MruPropertyCache2<Binding>();
                 _bindings = new MruPropertyCache2<Binding>();
             }
             }
 
 
-            var binding = name == BindingNameArguments ? _argumentsBinding : _bindings[name];
+            var binding = name.Length == 9 && name == BindingNameArguments
+                ? _argumentsBinding 
+                : _bindings[name];
+
             if (binding.Mutable)
             if (binding.Mutable)
             {
             {
                 binding.Value = value;
                 binding.Value = value;
@@ -75,7 +82,9 @@ namespace Jint.Runtime.Environments
 
 
         public override JsValue GetBindingValue(string name, bool strict)
         public override JsValue GetBindingValue(string name, bool strict)
         {
         {
-            var binding = name == BindingNameArguments ? _argumentsBinding : _bindings[name];
+            var binding = name.Length == 9 && name == BindingNameArguments
+                ? _argumentsBinding 
+                : _bindings[name];
 
 
             if (!binding.Mutable && binding.Value.IsUndefined())
             if (!binding.Mutable && binding.Value.IsUndefined())
             {
             {
@@ -153,6 +162,7 @@ namespace Jint.Runtime.Environments
                 {
                 {
                     _bindings = new MruPropertyCache2<Binding>();
                     _bindings = new MruPropertyCache2<Binding>();
                 }
                 }
+
                 _bindings.Add(name, binding);
                 _bindings.Add(name, binding);
             }
             }
         }
         }
@@ -168,10 +178,92 @@ namespace Jint.Runtime.Environments
 
 
         internal void ReleaseArguments()
         internal void ReleaseArguments()
         {
         {
-            if (_argumentsBinding?.Value is ArgumentsInstance instance)
+            _engine.ArgumentsInstancePool.Return(_argumentsBinding?.Value as ArgumentsInstance);
+            _argumentsBinding = null;
+        }
+
+        /// <summary>
+        /// Optimized version for function calls.
+        /// </summary>
+        internal void AddFunctionParameters(FunctionInstance functionInstance, JsValue[] arguments, ArgumentsInstance strict)
+        {
+            var parameters = functionInstance.FormalParameters;
+            bool empty = _bindings == null;
+            if (empty)
             {
             {
-                _engine.ArgumentsInstancePool.Return(instance);
-                _argumentsBinding = null;
+                _bindings = new MruPropertyCache2<Binding>();
+            }
+
+            for (var i = 0; i < parameters.Length; i++)
+            {
+                var argName = parameters[i];
+                var jsValue = i + 1 > arguments.Length ? Undefined : arguments[i];
+
+                if (empty || !_bindings.TryGetValue(argName, out var existing))
+                {
+                    var binding = new Binding
+                    {
+                        Value = jsValue,
+                        CanBeDeleted = false,
+                        Mutable = true
+                    };
+
+                    if (argName.Length == 9 && argName == BindingNameArguments)
+                    {
+                        _argumentsBinding = binding;
+                    }
+                    else
+                    {
+                        _bindings[argName] = binding;
+                    }
+                }
+                else
+                {
+                    if (existing.Mutable)
+                    {
+                        existing.Value = jsValue;
+                    }
+                    else
+                    {
+                        ExceptionHelper.ThrowTypeError(_engine, "Can't update the value of an immutable binding.");
+                    }
+                }
+            }
+
+            if (_argumentsBinding == null)
+            {
+                _argumentsBinding = new Binding {Value = strict, Mutable = true};
+            }
+        }
+
+        internal void AddVariableDeclarations(List<VariableDeclaration> variableDeclarations)
+        {
+            var variableDeclarationsCount = variableDeclarations.Count;
+            for (var i = 0; i < variableDeclarationsCount; i++)
+            {
+                var variableDeclaration = variableDeclarations[i];
+                var declarationsCount = variableDeclaration.Declarations.Count;
+                for (var j = 0; j < declarationsCount; j++)
+                {
+                    if (_bindings == null)
+                    {
+                        _bindings = new MruPropertyCache2<Binding>();
+                    }
+                    
+                    var d = variableDeclaration.Declarations[j];
+                    var dn = ((Identifier) d.Id).Name;
+
+                    if (!_bindings.ContainsKey(dn))
+                    {
+                        var binding = new Binding
+                        {
+                            Value = Undefined,
+                            CanBeDeleted = false,
+                            Mutable = true
+                        };
+                        _bindings.Add(dn, binding);
+                    }
+                }
             }
             }
         }
         }
     }
     }

+ 79 - 118
Jint/Runtime/ExpressionIntepreter.cs

@@ -5,6 +5,7 @@ using Esprima.Ast;
 using Jint.Native;
 using Jint.Native;
 using Jint.Native.Function;
 using Jint.Native.Function;
 using Jint.Native.Number;
 using Jint.Native.Number;
+using Jint.Pooling;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Environments;
@@ -13,12 +14,13 @@ using Jint.Runtime.References;
 
 
 namespace Jint.Runtime
 namespace Jint.Runtime
 {
 {
-    public class ExpressionInterpreter
+    public sealed class ExpressionInterpreter
     {
     {
         private readonly Engine _engine;
         private readonly Engine _engine;
         private readonly bool _isDebugMode;
         private readonly bool _isDebugMode;
         private readonly int _maxRecursionDepth;
         private readonly int _maxRecursionDepth;
         private readonly IReferenceResolver _referenceResolver;
         private readonly IReferenceResolver _referenceResolver;
+        private readonly ReferencePool _referencePool;
 
 
         public ExpressionInterpreter(Engine engine)
         public ExpressionInterpreter(Engine engine)
         {
         {
@@ -28,6 +30,7 @@ namespace Jint.Runtime
             _isDebugMode = engine.Options.IsDebugMode;
             _isDebugMode = engine.Options.IsDebugMode;
             _maxRecursionDepth = engine.Options.MaxRecursionDepth;
             _maxRecursionDepth = engine.Options.MaxRecursionDepth;
             _referenceResolver = engine.Options.ReferenceResolver;
             _referenceResolver = engine.Options.ReferenceResolver;
+            _referencePool = engine.ReferencePool;
         }
         }
 
 
         private object EvaluateExpression(Expression expression)
         private object EvaluateExpression(Expression expression)
@@ -52,8 +55,8 @@ namespace Jint.Runtime
 
 
         public JsValue EvaluateAssignmentExpression(AssignmentExpression assignmentExpression)
         public JsValue EvaluateAssignmentExpression(AssignmentExpression assignmentExpression)
         {
         {
-            var lref = EvaluateExpression((Expression) assignmentExpression.Left) as Reference;
-            JsValue rval = _engine.GetValue(EvaluateExpression(assignmentExpression.Right), true);
+            var lref = _engine.EvaluateExpression((Expression) assignmentExpression.Left) as Reference;
+            JsValue rval = _engine.GetValue(_engine.EvaluateExpression(assignmentExpression.Right), true);
 
 
             if (lref == null)
             if (lref == null)
             {
             {
@@ -65,7 +68,7 @@ namespace Jint.Runtime
                 lref.AssertValid(_engine);
                 lref.AssertValid(_engine);
 
 
                 _engine.PutValue(lref, rval);
                 _engine.PutValue(lref, rval);
-                _engine.ReferencePool.Return(lref);
+                _referencePool.Return(lref);
                 return rval;
                 return rval;
             }
             }
 
 
@@ -151,7 +154,7 @@ namespace Jint.Runtime
 
 
             _engine.PutValue(lref, lval);
             _engine.PutValue(lref, lval);
 
 
-            _engine.ReferencePool.Return(lref);
+            _referencePool.Return(lref);
             return lval;
             return lval;
         }
         }
 
 
@@ -176,7 +179,7 @@ namespace Jint.Runtime
                     return double.NaN;
                     return double.NaN;
                 }
                 }
 
 
-                if (double.IsInfinity(lN) && rN.Equals(0))
+                if (double.IsInfinity(lN) && rN == 0)
                 {
                 {
                     if (NumberInstance.IsNegativeZero(rN))
                     if (NumberInstance.IsNegativeZero(rN))
                     {
                     {
@@ -186,12 +189,12 @@ namespace Jint.Runtime
                     return lN;
                     return lN;
                 }
                 }
 
 
-                if (lN.Equals(0) && rN.Equals(0))
+                if (lN == 0 && rN == 0)
                 {
                 {
                     return double.NaN;
                     return double.NaN;
                 }
                 }
 
 
-                if (rN.Equals(0))
+                if (rN == 0)
                 {
                 {
                     if (NumberInstance.IsNegativeZero(rN))
                     if (NumberInstance.IsNegativeZero(rN))
                     {
                     {
@@ -214,7 +217,7 @@ namespace Jint.Runtime
             }
             }
             else
             else
             {
             {
-                left = _engine.GetValue(EvaluateExpression(expression.Left), true);
+                left = _engine.GetValue(_engine.EvaluateExpression(expression.Left), true);
             }
             }
 
 
             JsValue right;
             JsValue right;
@@ -224,7 +227,7 @@ namespace Jint.Runtime
             }
             }
             else
             else
             {
             {
-                right = _engine.GetValue(EvaluateExpression(expression.Right), true);
+                right = _engine.GetValue(_engine.EvaluateExpression(expression.Right), true);
             }
             }
 
 
             JsValue value;
             JsValue value;
@@ -374,7 +377,7 @@ namespace Jint.Runtime
 
 
         public JsValue EvaluateLogicalExpression(BinaryExpression binaryExpression)
         public JsValue EvaluateLogicalExpression(BinaryExpression binaryExpression)
         {
         {
-            var left = _engine.GetValue(EvaluateExpression(binaryExpression.Left), true);
+            var left = _engine.GetValue(_engine.EvaluateExpression(binaryExpression.Left), true);
 
 
             switch (binaryExpression.Operator)
             switch (binaryExpression.Operator)
             {
             {
@@ -384,7 +387,7 @@ namespace Jint.Runtime
                         return left;
                         return left;
                     }
                     }
 
 
-                    return _engine.GetValue(EvaluateExpression(binaryExpression.Right), true);
+                    return _engine.GetValue(_engine.EvaluateExpression(binaryExpression.Right), true);
 
 
                 case BinaryOperator.LogicalOr:
                 case BinaryOperator.LogicalOr:
                     if (TypeConverter.ToBoolean(left))
                     if (TypeConverter.ToBoolean(left))
@@ -392,7 +395,7 @@ namespace Jint.Runtime
                         return left;
                         return left;
                     }
                     }
 
 
-                    return _engine.GetValue(EvaluateExpression(binaryExpression.Right), true);
+                    return _engine.GetValue(_engine.EvaluateExpression(binaryExpression.Right), true);
 
 
                 default:
                 default:
                     ExceptionHelper.ThrowNotImplementedException();
                     ExceptionHelper.ThrowNotImplementedException();
@@ -463,57 +466,29 @@ namespace Jint.Runtime
                 return false;
                 return false;
             }
             }
 
 
-            if (typea == Types.Undefined || typea == Types.Null)
+            switch (typea)
             {
             {
-                return true;
-            }
-
-            if (typea == Types.Number)
-            {
-                var nx = ((JsNumber) x)._value;
-                var ny = ((JsNumber) y)._value;
-
-                if (double.IsNaN(nx) || double.IsNaN(ny))
-                {
-                    return false;
-                }
-
-                if (nx.Equals(ny))
-                {
+                case Types.Undefined:
+                case Types.Null:
                     return true;
                     return true;
-                }
-
-                return false;
-            }
-
-            if (typea == Types.String)
-            {
-                return x.AsStringWithoutTypeCheck() == y.AsStringWithoutTypeCheck();
-            }
-
-            if (typea == Types.Boolean)
-            {
-                return ((JsBoolean) x)._value == ((JsBoolean) y)._value;
-            }
-
-            if (typea == Types.Object)
-            {
-                if (x.AsObject() is IObjectWrapper xw)
-                {
+                case Types.Number:
+                    var nx = ((JsNumber) x)._value;
+                    var ny = ((JsNumber) y)._value;
+                    return !double.IsNaN(nx) && !double.IsNaN(ny) && nx == ny;
+                case Types.String:
+                    return x.AsStringWithoutTypeCheck() == y.AsStringWithoutTypeCheck();
+                case Types.Boolean:
+                    return ((JsBoolean) x)._value == ((JsBoolean) y)._value;
+                case Types.Object when x.AsObject() is IObjectWrapper xw:
                     var yw = y.AsObject() as IObjectWrapper;
                     var yw = y.AsObject() as IObjectWrapper;
                     if (yw == null)
                     if (yw == null)
                         return false;
                         return false;
-
                     return Equals(xw.Target, yw.Target);
                     return Equals(xw.Target, yw.Target);
-                }
-            }
-
-            if (typea == Types.None)
-            {
-                return true;
+                case Types.None:
+                    return true;
+                default:
+                    return x == y;
             }
             }
-
-            return x == y;
         }
         }
 
 
         public static bool SameValue(JsValue x, JsValue y)
         public static bool SameValue(JsValue x, JsValue y)
@@ -526,12 +501,11 @@ namespace Jint.Runtime
                 return false;
                 return false;
             }
             }
 
 
-            if (typea == Types.None)
-            {
-                return true;
-            }
-            if (typea == Types.Number)
+            switch (typea)
             {
             {
+                case Types.None:
+                    return true;
+                case Types.Number:
                 var nx = TypeConverter.ToNumber(x);
                 var nx = TypeConverter.ToNumber(x);
                 var ny = TypeConverter.ToNumber(y);
                 var ny = TypeConverter.ToNumber(y);
 
 
@@ -540,9 +514,9 @@ namespace Jint.Runtime
                     return true;
                     return true;
                 }
                 }
 
 
-                if (nx.Equals(ny))
+                if (nx == ny)
                 {
                 {
-                    if (nx.Equals(0))
+                    if (nx == 0)
                     {
                     {
                         // +0 !== -0
                         // +0 !== -0
                         return NumberInstance.IsNegativeZero(nx) == NumberInstance.IsNegativeZero(ny);
                         return NumberInstance.IsNegativeZero(nx) == NumberInstance.IsNegativeZero(ny);
@@ -552,16 +526,14 @@ namespace Jint.Runtime
                 }
                 }
 
 
                 return false;
                 return false;
+                case Types.String:
+                    return TypeConverter.ToString(x) == TypeConverter.ToString(y);
+                case Types.Boolean:
+                    return TypeConverter.ToBoolean(x) == TypeConverter.ToBoolean(y);
+                default:
+                    return x == y;
             }
             }
-            if (typea == Types.String)
-            {
-                return TypeConverter.ToString(x) == TypeConverter.ToString(y);
-            }
-            if (typea == Types.Boolean)
-            {
-                return TypeConverter.ToBoolean(x) == TypeConverter.ToBoolean(y);
-            }
-            return x == y;
+
         }
         }
 
 
         public static JsValue Compare(JsValue x, JsValue y, bool leftFirst = true)
         public static JsValue Compare(JsValue x, JsValue y, bool leftFirst = true)
@@ -591,7 +563,7 @@ namespace Jint.Runtime
                     return Undefined.Instance;
                     return Undefined.Instance;
                 }
                 }
 
 
-                if (nx.Equals(ny))
+                if (nx == ny)
                 {
                 {
                     return false;
                     return false;
                 }
                 }
@@ -777,7 +749,7 @@ namespace Jint.Runtime
         /// <returns></returns>
         /// <returns></returns>
         public Reference EvaluateMemberExpression(MemberExpression memberExpression)
         public Reference EvaluateMemberExpression(MemberExpression memberExpression)
         {
         {
-            var baseReference = EvaluateExpression(memberExpression.Object);
+            var baseReference = _engine.EvaluateExpression(memberExpression.Object);
             var baseValue = _engine.GetValue(baseReference);
             var baseValue = _engine.GetValue(baseReference);
 
 
             string propertyNameString;
             string propertyNameString;
@@ -788,7 +760,7 @@ namespace Jint.Runtime
             }
             }
             else
             else
             {
             {
-                var propertyNameReference = EvaluateExpression(memberExpression.Property);
+                var propertyNameReference = _engine.EvaluateExpression(memberExpression.Property);
                 var propertyNameValue = _engine.GetValue(propertyNameReference, true);
                 var propertyNameValue = _engine.GetValue(propertyNameReference, true);
                 propertyNameString = TypeConverter.ToString(propertyNameValue);
                 propertyNameString = TypeConverter.ToString(propertyNameValue);
             }
             }
@@ -797,9 +769,9 @@ namespace Jint.Runtime
 
 
             if (baseReference is Reference r)
             if (baseReference is Reference r)
             {
             {
-                _engine.ReferencePool.Return(r);
+                _referencePool.Return(r);
             }
             }
-            return _engine.ReferencePool.Rent(baseValue, propertyNameString, StrictModeScope.IsStrictModeCode);
+            return _referencePool.Rent(baseValue, propertyNameString, StrictModeScope.IsStrictModeCode);
         }
         }
 
 
         public JsValue EvaluateFunctionExpression(IFunction functionExpression)
         public JsValue EvaluateFunctionExpression(IFunction functionExpression)
@@ -824,14 +796,13 @@ namespace Jint.Runtime
 
 
         public JsValue EvaluateCallExpression(CallExpression callExpression)
         public JsValue EvaluateCallExpression(CallExpression callExpression)
         {
         {
-            var callee = EvaluateExpression(callExpression.Callee);
+            var callee = _engine.EvaluateExpression(callExpression.Callee);
             
             
             if (_isDebugMode)
             if (_isDebugMode)
             {
             {
                 _engine.DebugHandler.AddToDebugCallStack(callExpression);
                 _engine.DebugHandler.AddToDebugCallStack(callExpression);
             }
             }
 
 
-            JsValue thisObject;
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
 
 
             var arguments = Array.Empty<JsValue>();
             var arguments = Array.Empty<JsValue>();
@@ -866,10 +837,9 @@ namespace Jint.Runtime
             var func = _engine.GetValue(callee);
             var func = _engine.GetValue(callee);
 
 
             var r = callee as Reference;
             var r = callee as Reference;
-
             if (_maxRecursionDepth >= 0)
             if (_maxRecursionDepth >= 0)
             {
             {
-                var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
+                var stackItem = new CallStackElement(callExpression, func, r?._name ?? "anonymous function");
 
 
                 var recursionDepth = _engine.CallStack.Push(stackItem);
                 var recursionDepth = _engine.CallStack.Push(stackItem);
 
 
@@ -880,12 +850,12 @@ namespace Jint.Runtime
                 }
                 }
             }
             }
 
 
-            if (func.IsUndefined())
+            if (func._type == Types.Undefined)
             {
             {
                 ExceptionHelper.ThrowTypeError(_engine, r == null ? "" : $"Object has no method '{r.GetReferencedName()}'");
                 ExceptionHelper.ThrowTypeError(_engine, r == null ? "" : $"Object has no method '{r.GetReferencedName()}'");
             }
             }
 
 
-            if (!func.IsObject())
+            if (func._type != Types.Object)
             {
             {
                 if (_referenceResolver == null || !_referenceResolver.TryGetCallable(_engine, callee, out func))
                 if (_referenceResolver == null || !_referenceResolver.TryGetCallable(_engine, callee, out func))
                 {
                 {
@@ -894,35 +864,32 @@ namespace Jint.Runtime
                 }
                 }
             }
             }
 
 
-            var callable = func.TryCast<ICallable>();
+            var callable = func as ICallable;
             if (callable == null)
             if (callable == null)
             {
             {
                 ExceptionHelper.ThrowTypeError(_engine);
                 ExceptionHelper.ThrowTypeError(_engine);
             }
             }
 
 
+            var thisObject = Undefined.Instance;
             if (r != null)
             if (r != null)
             {
             {
                 if (r.IsPropertyReference())
                 if (r.IsPropertyReference())
                 {
                 {
-                    thisObject = r.GetBase();
+                    thisObject = r._baseValue;
                 }
                 }
                 else
                 else
                 {
                 {
-                    var env = r.GetBase().TryCast<EnvironmentRecord>();
+                    var env = (EnvironmentRecord) r._baseValue;
                     thisObject = env.ImplicitThisValue();
                     thisObject = env.ImplicitThisValue();
                 }
                 }
-            }
-            else
-            {
-                thisObject = Undefined.Instance;
-            }
-
-            // is it a direct call to eval ? http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1.1
-            if (r != null && r.GetReferencedName() == "eval" && callable is EvalFunctionInstance instance)
-            {
-                var value = instance.Call(thisObject, arguments, true);
-                _engine.ReferencePool.Return(r);
-                return value;
+                
+                // is it a direct call to eval ? http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1.1
+                if (r._name == "eval" && callable is EvalFunctionInstance instance)
+                {
+                    var value = instance.Call(thisObject, arguments, true);
+                    _referencePool.Return(r);
+                    return value;
+                }
             }
             }
 
 
             var result = callable.Call(thisObject, arguments);
             var result = callable.Call(thisObject, arguments);
@@ -942,7 +909,7 @@ namespace Jint.Runtime
                 _engine.JsValueArrayPool.ReturnArray(arguments);
                 _engine.JsValueArrayPool.ReturnArray(arguments);
             }
             }
 
 
-            _engine.ReferencePool.Return(r);
+            _referencePool.Return(r);
             return result;
             return result;
         }
         }
 
 
@@ -982,7 +949,7 @@ namespace Jint.Runtime
             }
             }
 
 
             _engine.PutValue(r, newValue);
             _engine.PutValue(r, newValue);
-            _engine.ReferencePool.Return(r);
+            _referencePool.Return(r);
             return updateExpression.Prefix ? newValue : oldValue;
             return updateExpression.Prefix ? newValue : oldValue;
         }
         }
 
 
@@ -997,7 +964,7 @@ namespace Jint.Runtime
             BuildArguments(newExpression.Arguments, arguments, out _);
             BuildArguments(newExpression.Arguments, arguments, out _);
 
 
             // todo: optimize by defining a common abstract class or interface
             // todo: optimize by defining a common abstract class or interface
-            var callee = _engine.GetValue(EvaluateExpression(newExpression.Callee), true).TryCast<IConstructor>();
+            var callee = _engine.GetValue(_engine.EvaluateExpression(newExpression.Callee), true).TryCast<IConstructor>();
 
 
             if (callee == null)
             if (callee == null)
             {
             {
@@ -1017,22 +984,16 @@ namespace Jint.Runtime
             var elements = arrayExpression.Elements;
             var elements = arrayExpression.Elements;
             var count = elements.Count;
             var count = elements.Count;
             
             
-            var jsValues = _engine.JsValueArrayPool.RentArray(1);
-            jsValues[0] = count;
-            
-            var a = _engine.Array.Construct(jsValues, (uint) count);
+            var a = _engine.Array.ConstructFast((uint) count);
             for (var n = 0; n < count; n++)
             for (var n = 0; n < count; n++)
             {
             {
                 var expr = elements[n];
                 var expr = elements[n];
                 if (expr != null)
                 if (expr != null)
                 {
                 {
-                    var value = _engine.GetValue(EvaluateExpression((Expression) expr), true);
+                    var value = _engine.GetValue(_engine.EvaluateExpression((Expression) expr), true);
                     a.SetIndexValue((uint) n, value, updateLength: false);
                     a.SetIndexValue((uint) n, value, updateLength: false);
                 }
                 }
             }
             }
-            a.SetLength((uint) count);
-            _engine.JsValueArrayPool.ReturnArray(jsValues);
-
             return a;
             return a;
         }
         }
 
 
@@ -1063,29 +1024,29 @@ namespace Jint.Runtime
                     }
                     }
                     if (r.IsUnresolvableReference())
                     if (r.IsUnresolvableReference())
                     {
                     {
-                        if (r.IsStrict())
+                        if (r._strict)
                         {
                         {
                             ExceptionHelper.ThrowSyntaxError(_engine);
                             ExceptionHelper.ThrowSyntaxError(_engine);
                         }
                         }
 
 
-                        _engine.ReferencePool.Return(r);
+                        _referencePool.Return(r);
                         return true;
                         return true;
                     }
                     }
                     if (r.IsPropertyReference())
                     if (r.IsPropertyReference())
                     {
                     {
                         var o = TypeConverter.ToObject(_engine, r.GetBase());
                         var o = TypeConverter.ToObject(_engine, r.GetBase());
-                        var jsValue = o.Delete(r.GetReferencedName(), r.IsStrict());
-                        _engine.ReferencePool.Return(r);
+                        var jsValue = o.Delete(r._name, r._strict);
+                        _referencePool.Return(r);
                         return jsValue;
                         return jsValue;
                     }
                     }
-                    if (r.IsStrict())
+                    if (r._strict)
                     {
                     {
                         ExceptionHelper.ThrowSyntaxError(_engine);
                         ExceptionHelper.ThrowSyntaxError(_engine);
                     }
                     }
 
 
                     var bindings = r.GetBase().TryCast<EnvironmentRecord>();
                     var bindings = r.GetBase().TryCast<EnvironmentRecord>();
                     var referencedName = r.GetReferencedName();
                     var referencedName = r.GetReferencedName();
-                    _engine.ReferencePool.Return(r);
+                    _referencePool.Return(r);
 
 
                     return bindings.DeleteBinding(referencedName);
                     return bindings.DeleteBinding(referencedName);
 
 
@@ -1099,7 +1060,7 @@ namespace Jint.Runtime
                     {
                     {
                         if (r.IsUnresolvableReference())
                         if (r.IsUnresolvableReference())
                         {
                         {
-                            _engine.ReferencePool.Return(r);
+                            _referencePool.Return(r);
                             return "undefined";
                             return "undefined";
                         }
                         }
                     }
                     }
@@ -1143,7 +1104,7 @@ namespace Jint.Runtime
             for (var i = 0; i < count; i++)
             for (var i = 0; i < count; i++)
             {
             {
                 var argument = (Expression) expressionArguments[i];
                 var argument = (Expression) expressionArguments[i];
-                targetArray[i] = _engine.GetValue(EvaluateExpression(argument), true);
+                targetArray[i] = _engine.GetValue(_engine.EvaluateExpression(argument), true);
                 cacheable &= argument is Literal;
                 cacheable &= argument is Literal;
             }
             }
         }
         }

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

@@ -10,7 +10,7 @@ using Jint.Runtime.Descriptors.Specialized;
 
 
 namespace Jint.Runtime.Interop
 namespace Jint.Runtime.Interop
 {
 {
-    public class TypeReference : FunctionInstance, IConstructor, IObjectWrapper
+    public sealed class TypeReference : FunctionInstance, IConstructor, IObjectWrapper
     {
     {
         private TypeReference(Engine engine)
         private TypeReference(Engine engine)
             : base(engine, null, null, false, "TypeReference")
             : base(engine, null, null, false, "TypeReference")

+ 7 - 15
Jint/Runtime/MruPropertyCache2.cs

@@ -71,12 +71,12 @@ namespace Jint.Runtime
 
 
         public bool ContainsKey(string key)
         public bool ContainsKey(string key)
         {
         {
-            if (_set && key.Equals(_key))
+            if (_set && key == _key)
             {
             {
                 return true;
                 return true;
             }
             }
 
 
-            return _dictionary != null && _dictionary.ContainsKey(key);
+            return _dictionary?.ContainsKey(key) == true;
         }
         }
 
 
         public IEnumerable<KeyValuePair<string, TValue>> GetEnumerator()
         public IEnumerable<KeyValuePair<string, TValue>> GetEnumerator()
@@ -97,36 +97,28 @@ namespace Jint.Runtime
             }
             }
         }
         }
 
 
-        public bool Remove(string key)
+        public void Remove(string key)
         {
         {
-            bool removed = false;
-            if (_set && key.Equals(_key))
+            if (_set && key == _key)
             {
             {
                 _set = false;
                 _set = false;
                 _key = null;
                 _key = null;
                 _value = null;
                 _value = null;
-                removed = true;
             }
             }
 
 
             _dictionary?.Remove(key);
             _dictionary?.Remove(key);
-            return removed;
         }
         }
 
 
         public bool TryGetValue(string key, out TValue value)
         public bool TryGetValue(string key, out TValue value)
         {
         {
-            if (_set && _key.Equals(key))
+            value = null;
+            if (_set && _key == key)
             {
             {
                 value = _value;
                 value = _value;
                 return true;
                 return true;
             }
             }
 
 
-            if (_dictionary == null)
-            {
-                value = null;
-                return false;
-            }
-
-            return _dictionary.TryGetValue(key, out value);
+            return _dictionary?.TryGetValue(key, out value) == true;
         }
         }
 
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 5 - 5
Jint/Runtime/References/Reference.cs

@@ -11,9 +11,9 @@ namespace Jint.Runtime.References
     /// </summary>
     /// </summary>
     public sealed class Reference
     public sealed class Reference
     {
     {
-        private JsValue _baseValue;
-        private string _name;
-        private bool _strict;
+        internal JsValue _baseValue;
+        internal string _name;
+        internal bool _strict;
 
 
         public Reference(JsValue baseValue, string name, bool strict)
         public Reference(JsValue baseValue, string name, bool strict)
         {
         {
@@ -42,13 +42,13 @@ namespace Jint.Runtime.References
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool HasPrimitiveBase()
         public bool HasPrimitiveBase()
         {
         {
-            return _baseValue.IsPrimitive();
+            return _baseValue._type != Types.Object && _baseValue._type != Types.None;
         }
         }
 
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool IsUnresolvableReference()
         public bool IsUnresolvableReference()
         {
         {
-            return _baseValue.IsUndefined();
+            return _baseValue._type == Types.Undefined;
         }
         }
 
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 51 - 24
Jint/Runtime/StatementInterpreter.cs

@@ -7,7 +7,7 @@ using Jint.Runtime.References;
 
 
 namespace Jint.Runtime
 namespace Jint.Runtime
 {
 {
-    public class StatementInterpreter
+    public sealed class StatementInterpreter
     {
     {
         private readonly Engine _engine;
         private readonly Engine _engine;
 
 
@@ -37,11 +37,11 @@ namespace Jint.Runtime
             Completion result;
             Completion result;
             if (TypeConverter.ToBoolean(_engine.GetValue(_engine.EvaluateExpression(ifStatement.Test), true)))
             if (TypeConverter.ToBoolean(_engine.GetValue(_engine.EvaluateExpression(ifStatement.Test), true)))
             {
             {
-                result = ExecuteStatement(ifStatement.Consequent);
+                result = _engine.ExecuteStatement(ifStatement.Consequent);
             }
             }
             else if (ifStatement.Alternate != null)
             else if (ifStatement.Alternate != null)
             {
             {
-                result = ExecuteStatement(ifStatement.Alternate);
+                result = _engine.ExecuteStatement(ifStatement.Alternate);
             }
             }
             else
             else
             {
             {
@@ -56,7 +56,7 @@ namespace Jint.Runtime
             // TODO: Esprima added Statement.Label, maybe not necessary as this line is finding the
             // TODO: Esprima added Statement.Label, maybe not necessary as this line is finding the
             // containing label and could keep a table per program with all the labels
             // containing label and could keep a table per program with all the labels
             // labeledStatement.Body.LabelSet = labeledStatement.Label;
             // labeledStatement.Body.LabelSet = labeledStatement.Label;
-            var result = ExecuteStatement(labeledStatement.Body);
+            var result = _engine.ExecuteStatement(labeledStatement.Body);
             if (result.Type == CompletionType.Break && result.Identifier == labeledStatement.Label.Name)
             if (result.Type == CompletionType.Break && result.Identifier == labeledStatement.Label.Name)
             {
             {
                 var value = result.Value;
                 var value = result.Value;
@@ -78,7 +78,7 @@ namespace Jint.Runtime
 
 
             do
             do
             {
             {
-                var stmt = ExecuteStatement(doWhileStatement.Body);
+                var stmt = _engine.ExecuteStatement(doWhileStatement.Body);
                 if (!ReferenceEquals(stmt.Value, null))
                 if (!ReferenceEquals(stmt.Value, null))
                 {
                 {
                     v = stmt.Value;
                     v = stmt.Value;
@@ -120,7 +120,7 @@ namespace Jint.Runtime
                     return new Completion(CompletionType.Normal, v, null);
                     return new Completion(CompletionType.Normal, v, null);
                 }
                 }
 
 
-                var stmt = ExecuteStatement(whileStatement.Body);
+                var stmt = _engine.ExecuteStatement(whileStatement.Body);
 
 
                 if (!ReferenceEquals(stmt.Value, null))
                 if (!ReferenceEquals(stmt.Value, null))
                 {
                 {
@@ -154,7 +154,7 @@ namespace Jint.Runtime
             {
             {
                 if (init.Type == Nodes.VariableDeclaration)
                 if (init.Type == Nodes.VariableDeclaration)
                 {
                 {
-                    var c = ExecuteStatement((Statement) init);
+                    var c = _engine.ExecuteStatement((Statement) init);
 
 
                 }
                 }
                 else
                 else
@@ -175,7 +175,7 @@ namespace Jint.Runtime
                     }
                     }
                 }
                 }
 
 
-                var stmt = ExecuteStatement(forStatement.Body);
+                var stmt = _engine.ExecuteStatement(forStatement.Body);
                 if (!ReferenceEquals(stmt.Value, null))
                 if (!ReferenceEquals(stmt.Value, null))
                 {
                 {
                     v = stmt.Value;
                     v = stmt.Value;
@@ -229,7 +229,8 @@ namespace Jint.Runtime
             {
             {
                 var keys = _engine.Object.GetOwnPropertyNames(Undefined.Instance, Arguments.From(cursor)).AsArray();
                 var keys = _engine.Object.GetOwnPropertyNames(Undefined.Instance, Arguments.From(cursor)).AsArray();
 
 
-                for (var i = 0; i < keys.GetLength(); i++)
+                var length = keys.GetLength();
+                for (var i = 0; i < length; i++)
                 {
                 {
                     var p = keys.GetOwnProperty(TypeConverter.ToString(i)).Value.AsStringWithoutTypeCheck();
                     var p = keys.GetOwnProperty(TypeConverter.ToString(i)).Value.AsStringWithoutTypeCheck();
 
 
@@ -254,7 +255,7 @@ namespace Jint.Runtime
 
 
                     _engine.PutValue(varRef, p);
                     _engine.PutValue(varRef, p);
 
 
-                    var stmt = ExecuteStatement(forInStatement.Body);
+                    var stmt = _engine.ExecuteStatement(forInStatement.Body);
                     if (!ReferenceEquals(stmt.Value, null))
                     if (!ReferenceEquals(stmt.Value, null))
                     {
                     {
                         v = stmt.Value;
                         v = stmt.Value;
@@ -336,7 +337,7 @@ namespace Jint.Runtime
             Completion c;
             Completion c;
             try
             try
             {
             {
-                c = ExecuteStatement(withStatement.Body);
+                c = _engine.ExecuteStatement(withStatement.Body);
             }
             }
             catch (JavaScriptException e)
             catch (JavaScriptException e)
             {
             {
@@ -418,17 +419,24 @@ namespace Jint.Runtime
 
 
         public Completion ExecuteStatementList(List<StatementListItem> statementList)
         public Completion ExecuteStatementList(List<StatementListItem> statementList)
         {
         {
+            // optimize common case without loop
+            return statementList.Count == 1 
+                ? ExecuteSingleStatement((Statement) statementList[0]) 
+                : ExecuteMultipleStatements(statementList);
+        }
+
+        private Completion ExecuteMultipleStatements(List<StatementListItem> statementList)
+        {
+            Statement s = null;
             var c = new Completion(CompletionType.Normal, null, null);
             var c = new Completion(CompletionType.Normal, null, null);
             Completion sl = c;
             Completion sl = c;
-            Statement s = null;
-
             try
             try
             {
             {
                 var statementListCount = statementList.Count;
                 var statementListCount = statementList.Count;
                 for (var i = 0; i < statementListCount; i++)
                 for (var i = 0; i < statementListCount; i++)
                 {
                 {
                     s = (Statement) statementList[i];
                     s = (Statement) statementList[i];
-                    c = ExecuteStatement(s);
+                    c = _engine.ExecuteStatement(s);
                     if (c.Type != CompletionType.Normal)
                     if (c.Type != CompletionType.Normal)
                     {
                     {
                         var executeStatementList = new Completion(
                         var executeStatementList = new Completion(
@@ -445,13 +453,37 @@ namespace Jint.Runtime
             }
             }
             catch (JavaScriptException v)
             catch (JavaScriptException v)
             {
             {
-                var completion = new Completion(CompletionType.Throw, v.Error, null, v.Location ?? s.Location);
+                var completion = new Completion(CompletionType.Throw, v.Error, null, v.Location ?? s?.Location);
                 return completion;
                 return completion;
             }
             }
 
 
             return new Completion(c.Type, c.GetValueOrDefault(), c.Identifier);
             return new Completion(c.Type, c.GetValueOrDefault(), c.Identifier);
         }
         }
 
 
+        private Completion ExecuteSingleStatement(Statement s)
+        {
+            try
+            {
+                var c = _engine.ExecuteStatement(s);
+                if (c.Type != CompletionType.Normal)
+                {
+                    var completion = new Completion(
+                        c.Type,
+                        c.Value,
+                        c.Identifier,
+                        c.Location);
+
+                    return completion;
+                }
+
+                return new Completion(c.Type, c.GetValueOrDefault(), c.Identifier);
+            }
+            catch (JavaScriptException v)
+            {
+                return new Completion(CompletionType.Throw, v.Error, null, v.Location ?? s?.Location);
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.13
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.13
         /// </summary>
         /// </summary>
@@ -470,7 +502,7 @@ namespace Jint.Runtime
         /// <returns></returns>
         /// <returns></returns>
         public Completion ExecuteTryStatement(TryStatement tryStatement)
         public Completion ExecuteTryStatement(TryStatement tryStatement)
         {
         {
-            var b = ExecuteStatement(tryStatement.Block);
+            var b = _engine.ExecuteStatement(tryStatement.Block);
             if (b.Type == CompletionType.Throw)
             if (b.Type == CompletionType.Throw)
             {
             {
                 // execute catch
                 // execute catch
@@ -483,14 +515,14 @@ namespace Jint.Runtime
                     catchEnv.Record.CreateMutableBinding(((Identifier) catchClause.Param).Name, c);
                     catchEnv.Record.CreateMutableBinding(((Identifier) catchClause.Param).Name, c);
 
 
                     _engine.UpdateLexicalEnvironment(catchEnv);
                     _engine.UpdateLexicalEnvironment(catchEnv);
-                    b = ExecuteStatement(catchClause.Body);
+                    b = _engine.ExecuteStatement(catchClause.Body);
                     _engine.UpdateLexicalEnvironment(oldEnv);
                     _engine.UpdateLexicalEnvironment(oldEnv);
                 }
                 }
             }
             }
 
 
             if (tryStatement.Finalizer != null)
             if (tryStatement.Finalizer != null)
             {
             {
-                var f = ExecuteStatement(tryStatement.Finalizer);
+                var f = _engine.ExecuteStatement(tryStatement.Finalizer);
                 if (f.Type == CompletionType.Normal)
                 if (f.Type == CompletionType.Normal)
                 {
                 {
                     return b;
                     return b;
@@ -515,12 +547,7 @@ namespace Jint.Runtime
                 var declaration = statement.Declarations[i];
                 var declaration = statement.Declarations[i];
                 if (declaration.Init != null)
                 if (declaration.Init != null)
                 {
                 {
-                    if (!(_engine.EvaluateExpression(declaration.Id) is Reference lhs))
-                    {
-                        ExceptionHelper.ThrowArgumentException();
-                        return new Completion();
-                    }
-
+                    var lhs = (Reference) _engine.EvaluateExpression(declaration.Id);
                     lhs.AssertValid(_engine);
                     lhs.AssertValid(_engine);
 
 
                     var value = _engine.GetValue(_engine.EvaluateExpression(declaration.Init), true);
                     var value = _engine.GetValue(_engine.EvaluateExpression(declaration.Init), true);

+ 82 - 157
Jint/Runtime/TypeConverter.cs

@@ -10,7 +10,6 @@ using Jint.Native.Number;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Native.String;
 using Jint.Native.String;
 using Jint.Runtime.References;
 using Jint.Runtime.References;
-using Jint.Native.Symbol;
 
 
 namespace Jint.Runtime
 namespace Jint.Runtime
 {
 {
@@ -27,7 +26,7 @@ namespace Jint.Runtime
         Completion = 20,
         Completion = 20,
     }
     }
 
 
-    public class TypeConverter
+    public static class TypeConverter
     {
     {
         // how many decimals to check when determining if double is actually an int
         // how many decimals to check when determining if double is actually an int
         private const double DoubleIsIntegerTolerance = double.Epsilon * 100;
         private const double DoubleIsIntegerTolerance = double.Epsilon * 100;
@@ -69,77 +68,46 @@ namespace Jint.Runtime
         /// </summary>
         /// </summary>
         public static bool ToBoolean(JsValue o)
         public static bool ToBoolean(JsValue o)
         {
         {
-            if (o.IsBoolean())
+            switch (o._type)
             {
             {
-                return ((JsBoolean) o)._value;
-            }
-
-            if (o.IsUndefined() || o.IsNull())
-            {
-                return false;
-            }
-
-            if (o.IsNumber())
-            {
-                var n = ((JsNumber) o)._value;
-                if (n.Equals(0) || double.IsNaN(n))
-                {
+                case Types.Boolean:
+                    return ((JsBoolean) o)._value;
+                case Types.Undefined:
+                case Types.Null:
                     return false;
                     return false;
-                }
-
-                return true;
-            }
-
-            if (o.IsString())
-            {
-                return !((JsString) o).IsNullOrEmpty();
+                case Types.Number:
+                    var n = ((JsNumber) o)._value;
+                    return n != 0 && !double.IsNaN(n);
+                case Types.String:
+                    return !((JsString) o).IsNullOrEmpty();
+                default:
+                    return true;
             }
             }
-
-            return true;
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.3
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.3
         /// </summary>
         /// </summary>
-        /// <param name="o"></param>
-        /// <returns></returns>
         public static double ToNumber(JsValue o)
         public static double ToNumber(JsValue o)
         {
         {
-            // check number first as this is what is usually expected
-            if (o.IsNumber())
-            {
-                return ((JsNumber) o)._value;
-            }
-
-            if (o.IsUndefined())
-            {
-                return double.NaN;
-            }
-
-            if (o.IsNull())
-            {
-                return 0;
-            }
-
-            if (o._type == Types.Object)
-            {
-                if (o is IPrimitiveInstance p)
-                {
-                    o = p.PrimitiveValue;
-                }
-            }
-
-            if (o.IsBoolean())
-            {
-                return ((JsBoolean) o)._value ? 1 : 0;
-            }
-
-            if (o.IsString())
-            {
-                return ToNumber(o.AsStringWithoutTypeCheck());
+            switch (o._type)
+            {
+                // check number first as this is what is usually expected
+                case Types.Number:
+                    return ((JsNumber) o)._value;
+                case Types.Undefined:
+                    return double.NaN;
+                case Types.Null:
+                    return 0;
+                case Types.Object when o is IPrimitiveInstance p:
+                    return ToNumber(ToPrimitive(p.PrimitiveValue, Types.Number));
+                case Types.Boolean:
+                    return ((JsBoolean) o)._value ? 1 : 0;
+                case Types.String:
+                    return ToNumber(o.AsStringWithoutTypeCheck());
+                default:
+                    return ToNumber(ToPrimitive(o, Types.Number));
             }
             }
-
-            return ToNumber(ToPrimitive(o, Types.Number));
         }
         }
 
 
         private static double ToNumber(string input)
         private static double ToNumber(string input)
@@ -154,19 +122,22 @@ namespace Jint.Runtime
                 ? StringPrototype.TrimEx(input)
                 ? StringPrototype.TrimEx(input)
                 : input;
                 : input;
 
 
-            if (string.IsNullOrEmpty(s))
+            if (s.Length == 0)
             {
             {
                 return 0;
                 return 0;
             }
             }
 
 
-            if ("+Infinity".Equals(s) || "Infinity".Equals(s))
+            if (s.Length == 8 || s.Length == 9)
             {
             {
-                return double.PositiveInfinity;
-            }
+                if ("+Infinity" == s || "Infinity" == s)
+                {
+                    return double.PositiveInfinity;
+                }
 
 
-            if ("-Infinity".Equals(s))
-            {
-                return double.NegativeInfinity;
+                if ("-Infinity" == s)
+                {
+                    return double.NegativeInfinity;
+                }
             }
             }
 
 
             // todo: use a common implementation with JavascriptParser
             // todo: use a common implementation with JavascriptParser
@@ -180,11 +151,11 @@ namespace Jint.Runtime
                         return double.NaN;
                         return double.NaN;
                     }
                     }
 
 
-                    double n = Double.Parse(s,
+                    double n = double.Parse(s,
                         NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign |
                         NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign |
                         NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite |
                         NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite |
                         NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
                         NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
-                    if (s.StartsWith("-") && n.Equals(0))
+                    if (s.StartsWith("-") && n == 0)
                     {
                     {
                         return -0.0;
                         return -0.0;
                     }
                     }
@@ -220,7 +191,7 @@ namespace Jint.Runtime
                 return 0;
                 return 0;
             }
             }
 
 
-            if (number.Equals(0) || double.IsInfinity(number))
+            if (number == 0 || double.IsInfinity(number))
             {
             {
                 return number;
                 return number;
             }
             }
@@ -237,7 +208,7 @@ namespace Jint.Runtime
                 return 0;
                 return 0;
             }
             }
 
 
-            if (number.Equals(0) || double.IsInfinity(number))
+            if (number == 0 || double.IsInfinity(number))
             {
             {
                 return number;
                 return number;
             }
             }
@@ -295,7 +266,7 @@ namespace Jint.Runtime
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal static string ToString(uint i)
         internal static string ToString(uint i)
         {
         {
-            return i >= 0 && i < intToString.Length
+            return i < intToString.Length
                 ? intToString[i]
                 ? intToString[i]
                 : i.ToString();
                 : i.ToString();
         }
         }
@@ -327,97 +298,51 @@ namespace Jint.Runtime
         /// <returns></returns>
         /// <returns></returns>
         public static string ToString(JsValue o)
         public static string ToString(JsValue o)
         {
         {
-            if (o.IsString())
-            {
-                return o.AsStringWithoutTypeCheck();
+            switch (o._type)
+            {
+                case Types.String:
+                    return o.AsStringWithoutTypeCheck();
+                case Types.Boolean:
+                    return ((JsBoolean) o)._value ? "true" : "false";
+                case Types.Number:
+                    return ToString(((JsNumber) o)._value);
+                case Types.Symbol:
+                    return o.AsSymbol();
+                case Types.Undefined:
+                    return Undefined.Text;
+                case Types.Null:
+                    return Null.Text;
+                case Types.Object when o is IPrimitiveInstance p:
+                    return ToString(ToPrimitive(p.PrimitiveValue, Types.String));
+                default:
+                    return ToString(ToPrimitive(o, Types.String));
             }
             }
-
-            if (o.IsUndefined())
-            {
-                return Undefined.Text;
-            }
-
-            if (o.IsNull())
-            {
-                return Null.Text;
-            }
-
-            if (o.IsObject())
-            {
-                if (o is IPrimitiveInstance p)
-                {
-                    o = p.PrimitiveValue;
-                }
-                else
-                {
-                    var s = o.AsInstance<SymbolInstance>();
-                    if (!ReferenceEquals(s, null))
-                    {
-                        // TODO: throw a TypeError
-                        // NB: But it requires an Engine reference
-                        ExceptionHelper.ThrowJavaScriptException("TypeError");
-                    }
-                }
-            }
-
-            if (o.IsBoolean())
-            {
-                return ((JsBoolean) o)._value ? "true" : "false";
-            }
-
-            if (o.IsNumber())
-            {
-                return ToString(((JsNumber) o)._value);
-            }
-
-            if (o.IsSymbol())
-            {
-                return o.AsSymbol();
-            }
-
-            return ToString(ToPrimitive(o, Types.String));
         }
         }
 
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static ObjectInstance ToObject(Engine engine, JsValue value)
         public static ObjectInstance ToObject(Engine engine, JsValue value)
         {
         {
-            if (value.IsObject())
-            {
-                return (ObjectInstance) value;
+            switch (value._type)
+            {
+                case Types.Object:
+                    return (ObjectInstance) value;
+                case Types.Boolean:
+                    return engine.Boolean.Construct(((JsBoolean) value)._value);
+                case Types.Number:
+                    return engine.Number.Construct(((JsNumber) value)._value);
+                case Types.String:
+                    return engine.String.Construct(value.AsStringWithoutTypeCheck());
+                case Types.Symbol:
+                    return engine.Symbol.Construct(((JsSymbol) value)._value);
+                default:
+                    ExceptionHelper.ThrowTypeError(engine);
+                    return null;
             }
             }
-
-            if (value.IsBoolean())
-            {
-                return engine.Boolean.Construct(((JsBoolean) value)._value);
-            }
-
-            if (value.IsNumber())
-            {
-                return engine.Number.Construct(((JsNumber) value)._value);
-            }
-
-            if (value.IsString())
-            {
-                return engine.String.Construct(value.AsStringWithoutTypeCheck());
-            }
-
-            if (value.IsSymbol())
-            {
-                return engine.Symbol.Construct(((JsSymbol) value)._value);
-            }
-
-            if (value.IsUndefined() || value.IsNull())
-            {
-                ExceptionHelper.ThrowTypeError(engine);
-            }
-            
-            ExceptionHelper.ThrowTypeError(engine);
-            return null;
         }
         }
 
 
         public static Types GetPrimitiveType(JsValue value)
         public static Types GetPrimitiveType(JsValue value)
         {
         {
-            if (value.IsObject())
+            if (value._type == Types.Object)
             {
             {
                 if (value is IPrimitiveInstance primitive)
                 if (value is IPrimitiveInstance primitive)
                 {
                 {
@@ -436,7 +361,7 @@ namespace Jint.Runtime
             MemberExpression expression,
             MemberExpression expression,
             object baseReference)
             object baseReference)
         {
         {
-            if (!o.IsUndefined() && !o.IsNull())
+            if (o._type != Types.Undefined && o._type != Types.Null)
             {
             {
                 return;
                 return;
             }
             }
@@ -464,7 +389,7 @@ namespace Jint.Runtime
 
 
         public static void CheckObjectCoercible(Engine engine, JsValue o)
         public static void CheckObjectCoercible(Engine engine, JsValue o)
         {
         {
-            if (o.IsUndefined() || o.IsNull())
+            if (o._type == Types.Undefined || o._type == Types.Null)
             {
             {
                 ExceptionHelper.ThrowTypeError(engine);
                 ExceptionHelper.ThrowTypeError(engine);
             }
             }
@@ -522,7 +447,7 @@ namespace Jint.Runtime
 
 
         public static bool TypeIsNullable(Type type)
         public static bool TypeIsNullable(Type type)
         {
         {
-            return !type.IsValueType() || Nullable.GetUnderlyingType(type) != null;
+            return !type.IsValueType || Nullable.GetUnderlyingType(type) != null;
         }
         }
     }
     }
 }
 }