Browse Source

Merge pull request #495 from lahma/perf/optimize-array-instance

Optimize PropertyDescriptor with flags
Sébastien Ros 7 years ago
parent
commit
37df293e32
52 changed files with 588 additions and 633 deletions
  1. 2 2
      Jint/Engine.cs
  2. 10 10
      Jint/Native/Argument/ArgumentsInstance.cs
  3. 6 6
      Jint/Native/Array/ArrayConstructor.cs
  4. 58 61
      Jint/Native/Array/ArrayInstance.cs
  5. 2 3
      Jint/Native/Array/ArrayPrototype.cs
  6. 3 3
      Jint/Native/Boolean/BooleanConstructor.cs
  7. 2 2
      Jint/Native/Boolean/BooleanPrototype.cs
  8. 3 3
      Jint/Native/Date/DateConstructor.cs
  9. 2 2
      Jint/Native/Date/DatePrototype.cs
  10. 3 3
      Jint/Native/Error/ErrorConstructor.cs
  11. 2 2
      Jint/Native/Error/ErrorPrototype.cs
  12. 2 2
      Jint/Native/Function/EvalFunctionInstance.cs
  13. 3 3
      Jint/Native/Function/FunctionConstructor.cs
  14. 7 7
      Jint/Native/Function/FunctionInstance.cs
  15. 6 6
      Jint/Native/Function/FunctionPrototype.cs
  16. 16 16
      Jint/Native/Function/ScriptFunctionInstance.cs
  17. 2 2
      Jint/Native/Function/ThrowTypeError.cs
  18. 1 1
      Jint/Native/JsNumber.cs
  19. 25 23
      Jint/Native/JsValue.cs
  20. 3 3
      Jint/Native/Json/JsonSerializer.cs
  21. 8 8
      Jint/Native/Number/NumberConstructor.cs
  22. 16 19
      Jint/Native/Object/ObjectConstructor.cs
  23. 56 71
      Jint/Native/Object/ObjectInstance.cs
  24. 1 1
      Jint/Native/Object/ObjectPrototype.cs
  25. 8 8
      Jint/Native/RegExp/RegExpConstructor.cs
  26. 3 4
      Jint/Native/RegExp/RegExpPrototype.cs
  27. 5 5
      Jint/Native/String/StringConstructor.cs
  28. 6 7
      Jint/Native/String/StringInstance.cs
  29. 3 3
      Jint/Native/String/StringPrototype.cs
  30. 3 3
      Jint/Native/Symbol/SymbolConstructor.cs
  31. 2 2
      Jint/Native/Symbol/SymbolPrototype.cs
  32. 0 16
      Jint/Runtime/Descriptors/IPropertyDescriptor .cs
  33. 224 56
      Jint/Runtime/Descriptors/PropertyDescriptor.cs
  34. 0 62
      Jint/Runtime/Descriptors/PropertyDescriptorExtensions.cs
  35. 24 0
      Jint/Runtime/Descriptors/PropertyFlag.cs
  36. 0 24
      Jint/Runtime/Descriptors/Specialized/AllForbiddenPropertyDescriptor.cs
  37. 4 9
      Jint/Runtime/Descriptors/Specialized/ClrAccessDescriptor.cs
  38. 0 24
      Jint/Runtime/Descriptors/Specialized/ConfigurableEnumerableWritablePropertyDescriptor.cs
  39. 0 24
      Jint/Runtime/Descriptors/Specialized/EnumerablePropertyDescriptor.cs
  40. 36 0
      Jint/Runtime/Descriptors/Specialized/GetSetPropertyDescriptor.cs
  41. 0 1
      Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs
  42. 0 24
      Jint/Runtime/Descriptors/Specialized/NonConfigurablePropertyDescriptor.cs
  43. 0 24
      Jint/Runtime/Descriptors/Specialized/NonEnumerablePropertyDescriptor.cs
  44. 0 24
      Jint/Runtime/Descriptors/Specialized/NullConfigurationPropertyDescriptor.cs
  45. 0 24
      Jint/Runtime/Descriptors/Specialized/WritablePropertyDescriptor.cs
  46. 2 3
      Jint/Runtime/Environments/ObjectEnvironmentRecord.cs
  47. 15 13
      Jint/Runtime/ExpressionIntepreter.cs
  48. 2 2
      Jint/Runtime/Interop/ClrFunctionInstance.cs
  49. 2 2
      Jint/Runtime/Interop/NamespaceReference.cs
  50. 3 3
      Jint/Runtime/Interop/ObjectWrapper.cs
  51. 6 6
      Jint/Runtime/Interop/TypeReference.cs
  52. 1 1
      Jint/Runtime/StatementInterpreter.cs

+ 2 - 2
Jint/Engine.cs

@@ -841,7 +841,7 @@ namespace Jint
                     {
                         var go = Global;
                         var existingProp = go.GetProperty(fn);
-                        if (existingProp.Configurable.Value)
+                        if (existingProp.Configurable)
                         {
                             go.DefineOwnProperty(fn,
                                 new PropertyDescriptor(
@@ -853,7 +853,7 @@ namespace Jint
                         }
                         else
                         {
-                            if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable.Value))
+                            if (existingProp.IsAccessorDescriptor() || !existingProp.Enumerable)
                             {
                                 throw new JavaScriptException(TypeError);
                             }

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

@@ -55,7 +55,7 @@ namespace Jint.Native.Argument
 
             var self = this;
             var len = _args.Length;
-            self.SetOwnProperty("length", new NonEnumerablePropertyDescriptor(len));
+            self.SetOwnProperty("length", new PropertyDescriptor(len, PropertyFlag.NonEnumerable));
             if (_args.Length > 0)
             {
                 var map = Engine.Object.Construct(Arguments.Empty);
@@ -65,7 +65,7 @@ namespace Jint.Native.Argument
                 {
                     var indxStr = TypeConverter.ToString(indx);
                     var val = _args[indx];
-                    self.SetOwnProperty(indxStr, new ConfigurableEnumerableWritablePropertyDescriptor(val));
+                    self.SetOwnProperty(indxStr, new PropertyDescriptor(val, PropertyFlag.ConfigurableEnumerableWritable));
                     if (indx < _names.Length)
                     {
                         var name = _names[indx];
@@ -87,14 +87,14 @@ namespace Jint.Native.Argument
             // step 13
             if (!_strict)
             {
-                self.SetOwnProperty("callee", new NonEnumerablePropertyDescriptor(_func));
+                self.SetOwnProperty("callee", new PropertyDescriptor(_func, PropertyFlag.NonEnumerable));
             }
             // step 14
             else
             {
                 var thrower = Engine.Function.ThrowTypeError;
-                self.DefineOwnProperty("caller", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
-                self.DefineOwnProperty("callee", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
+                self.DefineOwnProperty("caller", new GetSetPropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
+                self.DefineOwnProperty("callee", new GetSetPropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
             }
         }
 
@@ -102,7 +102,7 @@ namespace Jint.Native.Argument
 
         public override string Class => "Arguments";
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             EnsureInitialized();
 
@@ -147,7 +147,7 @@ namespace Jint.Native.Argument
 
             if (ownDesc.IsDataDescriptor())
             {
-                var valueDesc = new NullConfigurationPropertyDescriptor(value);
+                var valueDesc = new PropertyDescriptor(value, PropertyFlag.None);
                 DefineOwnProperty(propertyName, valueDesc, throwOnError);
                 return;
             }
@@ -162,12 +162,12 @@ namespace Jint.Native.Argument
             }
             else
             {
-                var newDesc = new ConfigurableEnumerableWritablePropertyDescriptor(value);
+                var newDesc = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable);
                 DefineOwnProperty(propertyName, newDesc, throwOnError);
             }
         }
 
-        public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
+        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             EnsureInitialized();
 
@@ -197,7 +197,7 @@ namespace Jint.Native.Argument
                             map.Put(propertyName, desc.Value, throwOnError);
                         }
 
-                        if (desc.Writable.HasValue && desc.Writable.Value == false)
+                        if (desc.WritableSet && !desc.Writable)
                         {
                             map.Delete(propertyName, false);
                         }

+ 6 - 6
Jint/Native/Array/ArrayConstructor.cs

@@ -3,7 +3,7 @@ using System.Collections;
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Array
@@ -25,17 +25,17 @@ namespace Jint.Native.Array
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = ArrayPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             // The initial value of Array.prototype is the Array prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
 
         public void Configure()
         {
-            SetOwnProperty("isArray", new NonEnumerablePropertyDescriptor(new ClrFunctionInstance(Engine, IsArray, 1)));
+            SetOwnProperty("isArray", new PropertyDescriptor(new ClrFunctionInstance(Engine, IsArray, 1), PropertyFlag.NonEnumerable));
         }
 
         private static JsValue IsArray(JsValue thisObj, JsValue[] arguments)
@@ -98,7 +98,7 @@ namespace Jint.Native.Array
                     throw new JavaScriptException(Engine.RangeError, "Invalid array length");
                 }
 
-                instance.SetOwnProperty("length", new WritablePropertyDescriptor(length));
+                instance.SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.OnlyWritable));
             }
             else if (arguments.Length == 1 && arguments[0] is ObjectWrapper objectWrapper)
             {
@@ -118,7 +118,7 @@ namespace Jint.Native.Array
             }
             else
             {
-                instance.SetOwnProperty("length", new WritablePropertyDescriptor(0));
+                instance.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
                 if (arguments.Length > 0)
                 {
                     PrototypeObject.Push(instance, arguments);

+ 58 - 61
Jint/Native/Array/ArrayInstance.cs

@@ -1,9 +1,10 @@
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
+
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
+
 using PropertyDescriptor = Jint.Runtime.Descriptors.PropertyDescriptor;
 using TypeConverter = Jint.Runtime.TypeConverter;
 
@@ -16,24 +17,24 @@ namespace Jint.Native.Array
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
 
-        private IPropertyDescriptor _length;
+        private PropertyDescriptor _length;
 
         private const int MaxDenseArrayLength = 1024 * 10;
 
         // we have dense and sparse, we usually can start with dense and fall back to sparse when necessary
-        private IPropertyDescriptor[] _dense;
-        private Dictionary<uint, IPropertyDescriptor> _sparse;
+        private PropertyDescriptor[] _dense;
+        private Dictionary<uint, PropertyDescriptor> _sparse;
 
         public ArrayInstance(Engine engine, uint capacity = 0) : base(engine)
         {
             _engine = engine;
             if (capacity < MaxDenseArrayLength)
             {
-                _dense = capacity > 0 ? new IPropertyDescriptor[capacity] : System.Array.Empty<IPropertyDescriptor>();
+                _dense = capacity > 0 ? new PropertyDescriptor[capacity] : System.Array.Empty<PropertyDescriptor>();
             }
             else
             {
-                _sparse = new Dictionary<uint, IPropertyDescriptor>((int) (capacity <= 1024 ? capacity : 1024));
+                _sparse = new Dictionary<uint, PropertyDescriptor>((int) (capacity <= 1024 ? capacity : 1024));
             }
         }
 
@@ -58,7 +59,7 @@ namespace Jint.Native.Array
 
             if (ownDesc.IsDataDescriptor())
             {
-                var valueDesc = new NullConfigurationPropertyDescriptor(value);
+                var valueDesc = new PropertyDescriptor(value, PropertyFlag.None);
                 DefineOwnProperty(propertyName, valueDesc, throwOnError);
                 return;
             }
@@ -73,12 +74,12 @@ namespace Jint.Native.Array
             }
             else
             {
-                var newDesc = new ConfigurableEnumerableWritablePropertyDescriptor(value);
+                var newDesc = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable);
                 DefineOwnProperty(propertyName, newDesc, throwOnError);
             }
         }
 
-        public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
+        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             var oldLenDesc = _length;
             var oldLen = (uint) TypeConverter.ToNumber(oldLenDesc.Value);
@@ -103,7 +104,7 @@ namespace Jint.Native.Array
                     return base.DefineOwnProperty("length", newLenDesc, throwOnError);
                 }
 
-                if (!oldLenDesc.Writable.Value)
+                if (!oldLenDesc.Writable)
                 {
                     if (throwOnError)
                     {
@@ -114,7 +115,7 @@ namespace Jint.Native.Array
                 }
 
                 bool newWritable;
-                if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value)
+                if (!newLenDesc.WritableSet || newLenDesc.Writable)
                 {
                     newWritable = true;
                 }
@@ -130,22 +131,7 @@ namespace Jint.Native.Array
                     return false;
                 }
 
-                int count = 0;
-                if (_dense != null)
-                {
-                    for (int i = 0; i < _dense.Length; ++i)
-                    {
-                        if (_dense[i] != null)
-                        {
-                            count++;
-                        }
-                    }
-                }
-                else
-                {
-                    count = _sparse.Count;
-                }
-
+                var count = _dense?.Length ?? _sparse.Count;
                 if (count < oldLen - newLen)
                 {
                     if (_dense != null)
@@ -160,7 +146,7 @@ namespace Jint.Native.Array
                             // is it the index of the array
                             if (keyIndex >= newLen && keyIndex < oldLen)
                             {
-                                var deleteSucceeded = Delete(TypeConverter.ToString(keyIndex), false);
+                                var deleteSucceeded = DeleteAt(keyIndex);
                                 if (!deleteSucceeded)
                                 {
                                     newLenDesc.Value = keyIndex + 1;
@@ -190,7 +176,7 @@ namespace Jint.Native.Array
                         for (var i = 0; i < keysCount; i++)
                         {
                             var keyIndex = keys[i];
-                            
+
                             // is it the index of the array
                             if (keyIndex >= newLen && keyIndex < oldLen)
                             {
@@ -252,7 +238,7 @@ namespace Jint.Native.Array
             }
             else if (IsArrayIndex(propertyName, out var index))
             {
-                if (index >= oldLen && !oldLenDesc.Writable.Value)
+                if (index >= oldLen && !oldLenDesc.Writable)
                 {
                     if (throwOnError)
                     {
@@ -287,43 +273,46 @@ namespace Jint.Native.Array
 
         public uint GetLength()
         {
-            return TypeConverter.ToUint32(_length.Value);
+            return (uint) ((JsNumber) _length.Value)._value;
         }
 
-        protected override void AddProperty(string propertyName, IPropertyDescriptor descriptor)
+        protected override void AddProperty(string propertyName, PropertyDescriptor descriptor)
         {
             if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
             {
                 _length = descriptor;
                 return;
             }
+
             base.AddProperty(propertyName, descriptor);
         }
 
-        protected override bool TryGetProperty(string propertyName, out IPropertyDescriptor descriptor)
+        protected override bool TryGetProperty(string propertyName, out PropertyDescriptor descriptor)
         {
             if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
             {
                 descriptor = _length;
                 return _length != null;
             }
+
             return base.TryGetProperty(propertyName, out descriptor);
         }
 
-        public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+        public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
             if (_length != null)
             {
-                yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameLength, _length);
+                yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameLength, _length);
             }
 
             if (_dense != null)
             {
-                for (var i = 0; i < _dense.Length; i++)
+                var length = System.Math.Min(_dense.Length, GetLength());
+                for (var i = 0; i < length; i++)
                 {
                     if (_dense[i] != null)
                     {
-                        yield return new KeyValuePair<string, IPropertyDescriptor>(TypeConverter.ToString(i), _dense[i]);
+                        yield return new KeyValuePair<string, PropertyDescriptor>(TypeConverter.ToString(i), _dense[i]);
                     }
                 }
             }
@@ -331,7 +320,7 @@ namespace Jint.Native.Array
             {
                 foreach (var entry in _sparse)
                 {
-                    yield return new KeyValuePair<string, IPropertyDescriptor>(TypeConverter.ToString(entry.Key), entry.Value);
+                    yield return new KeyValuePair<string, PropertyDescriptor>(TypeConverter.ToString(entry.Key), entry.Value);
                 }
             }
 
@@ -341,7 +330,7 @@ namespace Jint.Native.Array
             }
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             if (IsArrayIndex(propertyName, out var index))
             {
@@ -361,7 +350,7 @@ namespace Jint.Native.Array
             return base.GetOwnProperty(propertyName);
         }
 
-        protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+        protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
             if (IsArrayIndex(propertyName, out var index))
             {
@@ -383,7 +372,7 @@ namespace Jint.Native.Array
             {
                 return index < GetLength()
                        && (_sparse == null || _sparse.ContainsKey(index))
-                       && (_dense == null || _dense[index] != null);
+                       && (_dense == null || (index < _dense.Length && _dense[index] != null));
             }
 
             if (p == PropertyNameLength)
@@ -396,8 +385,7 @@ namespace Jint.Native.Array
 
         public override void RemoveOwnProperty(string p)
         {
-            uint index;
-            if (IsArrayIndex(p, out index))
+            if (IsArrayIndex(p, out var index))
             {
                 DeleteAt(index);
             }
@@ -470,7 +458,7 @@ namespace Jint.Native.Array
                 _length.Value = index + 1;
             }
 
-            WriteArrayValue(index, new ConfigurableEnumerableWritablePropertyDescriptor(value));
+            WriteArrayValue(index, new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable));
         }
 
         internal uint GetSmallestIndex()
@@ -515,22 +503,25 @@ namespace Jint.Native.Array
             return false;
         }
 
-        internal void DeleteAt(uint index)
+        internal bool DeleteAt(uint index)
         {
             if (_dense != null)
             {
                 if (index < _dense.Length)
                 {
                     _dense[index] = null;
+                    return true;
                 }
             }
             else
             {
-                _sparse.Remove(index);
+                return _sparse.Remove(index);
             }
+
+            return false;
         }
 
-        private bool TryGetDescriptor(uint index, out IPropertyDescriptor descriptor)
+        private bool TryGetDescriptor(uint index, out PropertyDescriptor descriptor)
         {
             if (_dense != null)
             {
@@ -547,7 +538,8 @@ namespace Jint.Native.Array
             return _sparse.TryGetValue(index, out descriptor);
         }
 
-        internal void WriteArrayValue(uint index, IPropertyDescriptor desc)
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal void WriteArrayValue(uint index, PropertyDescriptor desc)
         {
             // calculate eagerly so we know if we outgrow
             var newSize = _dense != null && index >= _dense.Length
@@ -572,29 +564,34 @@ namespace Jint.Native.Array
             {
                 if (_dense != null)
                 {
-                    _sparse = new Dictionary<uint, IPropertyDescriptor>(_dense.Length <= 1024 ? _dense.Length : 0);
-                    // need to move data
-                    for (uint i = 0; i < _dense.Length; ++i)
-                    {
-                        if (_dense[i] != null)
-                        {
-                            _sparse[i] = _dense[i];
-                        }
-                    }
-
-                    _dense = null;
+                    ConvertToSparse();
                 }
-
                 _sparse[index] = desc;
             }
         }
 
+        private void ConvertToSparse()
+        {
+            _sparse = new Dictionary<uint, PropertyDescriptor>(_dense.Length <= 1024 ? _dense.Length : 0);
+            // need to move data
+            for (uint i = 0; i < _dense.Length; ++i)
+            {
+                if (_dense[i] != null)
+                {
+                    _sparse[i] = _dense[i];
+                }
+            }
+
+            _dense = null;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal void EnsureCapacity(uint capacity)
         {
             if (capacity > _dense.Length)
             {
                 // need to grow
-                var newArray = new IPropertyDescriptor[capacity];
+                var newArray = new PropertyDescriptor[capacity];
                 System.Array.Copy(_dense, newArray, _dense.Length);
                 _dense = newArray;
             }

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

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Array
@@ -26,7 +25,7 @@ namespace Jint.Native.Array
             };
 
             obj.FastAddProperty("length", 0, true, false, false);
-            obj.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(arrayConstructor));
+            obj.SetOwnProperty("constructor", new PropertyDescriptor(arrayConstructor, PropertyFlag.NonEnumerable));
 
             return obj;
         }
@@ -820,7 +819,7 @@ namespace Jint.Native.Array
 
             // this is not in the specs, but is necessary in case the last element of the last
             // array doesn't exist, and thus the length would not be incremented
-            a.DefineOwnProperty("length", new NullConfigurationPropertyDescriptor(n), false);
+            a.DefineOwnProperty("length", new PropertyDescriptor(n, PropertyFlag.None), false);
 
             return a;
         }

+ 3 - 3
Jint/Native/Boolean/BooleanConstructor.cs

@@ -1,7 +1,7 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Boolean
 {
@@ -20,10 +20,10 @@ namespace Jint.Native.Boolean
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = BooleanPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             // The initial value of Boolean.prototype is the Boolean prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }

+ 2 - 2
Jint/Native/Boolean/BooleanPrototype.cs

@@ -1,5 +1,5 @@
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Boolean
@@ -20,7 +20,7 @@ namespace Jint.Native.Boolean
             obj.PrimitiveValue = false;
             obj.Extensible = true;
 
-            obj.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(booleanConstructor));
+            obj.SetOwnProperty("constructor", new PropertyDescriptor(booleanConstructor, PropertyFlag.NonEnumerable));
 
             return obj;
         }

+ 3 - 3
Jint/Native/Date/DateConstructor.cs

@@ -3,7 +3,7 @@ using System.Globalization;
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Date
@@ -25,10 +25,10 @@ namespace Jint.Native.Date
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = DatePrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(7));
+            obj.SetOwnProperty("length", new PropertyDescriptor(7, PropertyFlag.AllForbidden));
 
             // The initial value of Date.prototype is the Date prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }

+ 2 - 2
Jint/Native/Date/DatePrototype.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Globalization;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Date
@@ -25,7 +25,7 @@ namespace Jint.Native.Date
                 PrimitiveValue = double.NaN
             };
 
-            obj.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(dateConstructor));
+            obj.SetOwnProperty("constructor", new PropertyDescriptor(dateConstructor, PropertyFlag.NonEnumerable));
 
             return obj;
         }

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

@@ -1,7 +1,7 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Error
 {
@@ -23,10 +23,10 @@ namespace Jint.Native.Error
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = ErrorPrototype.CreatePrototypeObject(engine, obj, name);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             // The initial value of Error.prototype is the Error prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }

+ 2 - 2
Jint/Native/Error/ErrorPrototype.cs

@@ -1,6 +1,6 @@
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Error
@@ -18,7 +18,7 @@ namespace Jint.Native.Error
         public static ErrorPrototype CreatePrototypeObject(Engine engine, ErrorConstructor errorConstructor, string name)
         {
             var obj = new ErrorPrototype(engine, name) { Extensible = true };
-            obj.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(errorConstructor));
+            obj.SetOwnProperty("constructor", new PropertyDescriptor(errorConstructor, PropertyFlag.NonEnumerable));
             obj.FastAddProperty("message", "", true, false, true);
 
             if (name != "Error")

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

@@ -1,7 +1,7 @@
 using Esprima;
 using Jint.Native.Argument;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 
 namespace Jint.Native.Function
@@ -16,7 +16,7 @@ namespace Jint.Native.Function
         {
             _engine = engine;
             Prototype = Engine.Function.PrototypeObject;
-            SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
         }
 
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)

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

@@ -4,7 +4,7 @@ using Esprima;
 using Esprima.Ast;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 
 namespace Jint.Native.Function
@@ -28,8 +28,8 @@ namespace Jint.Native.Function
             // The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object
             obj.Prototype = obj.PrototypeObject;
 
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             return obj;
         }

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

@@ -10,11 +10,11 @@ namespace Jint.Native.Function
     {
         private const string PropertyNamePrototype = "prototype";
         private const int PropertyNamePrototypeLength = 9;
-        private IPropertyDescriptor _prototype;
+        private PropertyDescriptor _prototype;
 
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
-        private IPropertyDescriptor _length;
+        private PropertyDescriptor _length;
 
         private readonly Engine _engine;
 
@@ -97,15 +97,15 @@ namespace Jint.Native.Function
             return v;
         }
 
-        public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+        public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
             if (_prototype != null)
             {
-                yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNamePrototype, _prototype);
+                yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNamePrototype, _prototype);
             }
             if (_length != null)
             {
-                yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameLength, _length);
+                yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameLength, _length);
             }
 
             foreach (var entry in base.GetOwnProperties())
@@ -114,7 +114,7 @@ namespace Jint.Native.Function
             }
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
             {
@@ -128,7 +128,7 @@ namespace Jint.Native.Function
             return base.GetOwnProperty(propertyName);
         }
 
-        protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+        protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
             if (propertyName.Length == PropertyNamePrototypeLength && propertyName == PropertyNamePrototype)
             {

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

@@ -23,14 +23,14 @@ namespace Jint.Native.Function
             // The value of the [[Prototype]] internal property of the Function prototype object is the standard built-in Object prototype object
             obj.Prototype = engine.Object.PrototypeObject;
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
+            obj.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
 
             return obj;
         }
 
         public void Configure()
         {
-            SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(Engine.Function));
+            SetOwnProperty("constructor", new PropertyDescriptor(Engine.Function, PropertyFlag.NonEnumerable));
             FastAddProperty("toString", new ClrFunctionInstance(Engine, ToString), true, false, true);
             FastAddProperty("apply", new ClrFunctionInstance(Engine, Apply, 2), true, false, true);
             FastAddProperty("call", new ClrFunctionInstance(Engine, CallImpl, 1), true, false, true);
@@ -55,17 +55,17 @@ namespace Jint.Native.Function
             if (o != null)
             {
                 var l = TypeConverter.ToNumber(o.Get("length")) - (arguments.Length - 1);
-                f.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(System.Math.Max(l, 0)));
+                f.SetOwnProperty("length", new PropertyDescriptor(System.Math.Max(l, 0), PropertyFlag.AllForbidden));
             }
             else
             {
-                f.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
+                f.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
             }
 
 
             var thrower = Engine.Function.ThrowTypeError;
-            f.DefineOwnProperty("caller", new PropertyDescriptor(thrower, thrower, false, false), false);
-            f.DefineOwnProperty("arguments", new PropertyDescriptor(thrower, thrower, false, false), false);
+            f.DefineOwnProperty("caller", new GetSetPropertyDescriptor(thrower, thrower, false, false), false);
+            f.DefineOwnProperty("arguments", new GetSetPropertyDescriptor(thrower, thrower, false, false), false);
 
 
             return f;

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

@@ -18,7 +18,7 @@ namespace Jint.Native.Function
         private const string PropertyNameName = "name";
         private const int PropertyNameNameLength = 4;
 
-        private IPropertyDescriptor _name;
+        private PropertyDescriptor _name;
 
         private readonly IFunction _functionDeclaration;
 
@@ -37,7 +37,7 @@ namespace Jint.Native.Function
             Extensible = true;
             Prototype = engine.Function.PrototypeObject;
 
-            DefineOwnProperty("length", new AllForbiddenPropertyDescriptor(JsNumber.Create(FormalParameters.Length)), false);
+            DefineOwnProperty("length", new PropertyDescriptor(JsNumber.Create(FormalParameters.Length), PropertyFlag.AllForbidden), false);
 
             var proto = new ObjectInstanceWithConstructor(engine, this)
             {
@@ -45,26 +45,26 @@ namespace Jint.Native.Function
                 Prototype = Engine.Object.PrototypeObject
             };
 
-            SetOwnProperty("prototype", new WritablePropertyDescriptor(proto));
+            SetOwnProperty("prototype", new PropertyDescriptor(proto, PropertyFlag.OnlyWritable));
 
             if (_functionDeclaration.Id != null)
             {
-                _name = new NullConfigurationPropertyDescriptor(_functionDeclaration.Id.Name);
+                _name = new PropertyDescriptor(_functionDeclaration.Id.Name, PropertyFlag.None);
             }
 
             if (strict)
             {
                 var thrower = engine.Function.ThrowTypeError;
-                DefineOwnProperty("caller", new PropertyDescriptor(thrower, thrower, false, false), false);
-                DefineOwnProperty("arguments", new PropertyDescriptor(thrower, thrower, false, false), false);
+                DefineOwnProperty("caller", new GetSetPropertyDescriptor(thrower, thrower, false, false), false);
+                DefineOwnProperty("arguments", new GetSetPropertyDescriptor(thrower, thrower, false, false), false);
             }
         }
 
-        public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+        public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
             if (_name != null)
             {
-                yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameName, _name);
+                yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameName, _name);
             }
 
             foreach (var entry in base.GetOwnProperties())
@@ -73,7 +73,7 @@ namespace Jint.Native.Function
             }
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             if (propertyName.Length == PropertyNameNameLength && propertyName == PropertyNameName)
             {
@@ -83,7 +83,7 @@ namespace Jint.Native.Function
             return base.GetOwnProperty(propertyName);
         }
 
-        protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+        protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
             if (propertyName.Length == PropertyNameNameLength && propertyName == PropertyNameName)
             {
@@ -238,18 +238,18 @@ namespace Jint.Native.Function
         {
             private const string PropertyNameConstructor = "constructor";
             private const int PropertyNameConstructorLength = 11;
-            private IPropertyDescriptor _constructor;
+            private PropertyDescriptor _constructor;
 
             public ObjectInstanceWithConstructor(Engine engine, ObjectInstance thisObj) : base(engine)
             {
-                _constructor = new NonEnumerablePropertyDescriptor(thisObj);
+                _constructor = new PropertyDescriptor(thisObj, PropertyFlag.NonEnumerable);
             }
 
-            public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+            public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
             {
                 if (_constructor != null)
                 {
-                    yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameConstructor, _constructor);
+                    yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameConstructor, _constructor);
                 }
 
                 foreach (var entry in base.GetOwnProperties())
@@ -258,7 +258,7 @@ namespace Jint.Native.Function
                 }
             }
 
-            public override IPropertyDescriptor GetOwnProperty(string propertyName)
+            public override PropertyDescriptor GetOwnProperty(string propertyName)
             {
                 if (propertyName.Length == PropertyNameConstructorLength && propertyName == PropertyNameConstructor)
                 {
@@ -268,7 +268,7 @@ namespace Jint.Native.Function
                 return base.GetOwnProperty(propertyName);
             }
 
-            protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+            protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
             {
                 if (propertyName.Length == PropertyNameConstructorLength && propertyName == PropertyNameConstructor)
                 {

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

@@ -1,5 +1,5 @@
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Function
 {
@@ -10,7 +10,7 @@ namespace Jint.Native.Function
         public ThrowTypeError(Engine engine): base(engine, System.Array.Empty<string>(), engine.GlobalEnvironment, false)
         {
             _engine = engine;
-            DefineOwnProperty("length", new AllForbiddenPropertyDescriptor(0), false);
+            DefineOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden), false);
             Extensible = false;
         }
 

+ 1 - 1
Jint/Native/JsNumber.cs

@@ -6,7 +6,7 @@ namespace Jint.Native
 {
     public sealed class JsNumber : JsValue, IEquatable<JsNumber>
     {
-        private readonly double _value;
+        internal readonly double _value;
 
         // how many decimals to check when determining if double is actually an int
         private const double DoubleIsIntegerTolerance = double.Epsilon * 100;

+ 25 - 23
Jint/Native/JsValue.cs

@@ -8,7 +8,7 @@ using Jint.Native.Date;
 using Jint.Native.Object;
 using Jint.Native.RegExp;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native
@@ -205,10 +205,11 @@ namespace Jint.Native
                 return jsValue;
             }
 
-            var objectConvertersCount = engine.Options._ObjectConverters.Count;
-            for (var i = 0; i < objectConvertersCount; i++)
+            var converters = engine.Options._ObjectConverters;
+            var convertersCount = converters.Count;
+            for (var i = 0; i < convertersCount; i++)
             {
-                var converter = engine.Options._ObjectConverters[i];
+                var converter = converters[i];
                 if (converter.TryConvert(value, out var result))
                 {
                     return result;
@@ -233,25 +234,6 @@ namespace Jint.Native
 
             if (value is System.Array a)
             {
-                JsValue Convert(Engine e, object v)
-                {
-                    var array = (System.Array) v;
-                    var arrayLength = (uint) array.Length;
-
-                    var jsArray = new ArrayInstance(e, arrayLength);
-                    jsArray.Prototype = e.Array.PrototypeObject;
-                    jsArray.Extensible = true;
-                    
-                    for (uint i = 0; i < arrayLength; ++i)
-                    {
-                        var jsItem = FromObject(e, array.GetValue(i));
-                        jsArray.WriteArrayValue(i, new ConfigurableEnumerableWritablePropertyDescriptor(jsItem));
-                    }
-                    jsArray.SetOwnProperty("length", new WritablePropertyDescriptor(arrayLength));
-
-                    return jsArray;
-                }
-
                 // racy, we don't care, worst case we'll catch up later
                 Interlocked.CompareExchange(ref Engine.TypeMappers, new Dictionary<Type, Func<Engine, object, JsValue>>(typeMappers)
                 {
@@ -275,6 +257,26 @@ namespace Jint.Native
             return new ObjectWrapper(engine, value);
         }
 
+        private static JsValue Convert(Engine e, object v)
+        {
+            var array = (System.Array) v;
+            var arrayLength = (uint) array.Length;
+
+            var jsArray = new ArrayInstance(e, arrayLength);
+            jsArray.Prototype = e.Array.PrototypeObject;
+            jsArray.Extensible = true;
+
+            for (uint i = 0; i < arrayLength; ++i)
+            {
+                var jsItem = FromObject(e, array.GetValue(i));
+                jsArray.WriteArrayValue(i, new PropertyDescriptor(jsItem, PropertyFlag.ConfigurableEnumerableWritable));
+            }
+
+            jsArray.SetOwnProperty("length", new PropertyDescriptor(arrayLength, PropertyFlag.OnlyWritable));
+
+            return jsArray;
+        }
+
         /// <summary>
         /// Converts a <see cref="JsValue"/> to its underlying CLR value.
         /// </summary>

+ 3 - 3
Jint/Native/Json/JsonSerializer.cs

@@ -5,7 +5,7 @@ using Jint.Native.Array;
 using Jint.Native.Global;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Json
 {
@@ -113,7 +113,7 @@ namespace Jint.Native.Json
             }
 
             var wrapper = _engine.Object.Construct(Arguments.Empty);
-            wrapper.DefineOwnProperty("", new ConfigurableEnumerableWritablePropertyDescriptor(value), false);
+            wrapper.DefineOwnProperty("", new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable), false);
 
             return Str("", wrapper);
         }
@@ -317,7 +317,7 @@ namespace Jint.Native.Json
             _indent += _gap;
 
             var k = _propertyList ?? value.GetOwnProperties()
-                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value == true)
+                .Where(x => x.Value.Enumerable)
                 .Select(x => x.Key)
                 .ToList();
 

+ 8 - 8
Jint/Native/Number/NumberConstructor.cs

@@ -1,7 +1,7 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Number
 {
@@ -22,21 +22,21 @@ namespace Jint.Native.Number
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = NumberPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             // The initial value of Number.prototype is the Number prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
 
         public void Configure()
         {
-            SetOwnProperty("MAX_VALUE", new AllForbiddenPropertyDescriptor(double.MaxValue));
-            SetOwnProperty("MIN_VALUE", new AllForbiddenPropertyDescriptor(double.Epsilon));
-            SetOwnProperty("NaN", new AllForbiddenPropertyDescriptor(double.NaN));
-            SetOwnProperty("NEGATIVE_INFINITY", new AllForbiddenPropertyDescriptor(double.NegativeInfinity));
-            SetOwnProperty("POSITIVE_INFINITY", new AllForbiddenPropertyDescriptor(double.PositiveInfinity));
+            SetOwnProperty("MAX_VALUE", new PropertyDescriptor(double.MaxValue, PropertyFlag.AllForbidden));
+            SetOwnProperty("MIN_VALUE", new PropertyDescriptor(double.Epsilon, PropertyFlag.AllForbidden));
+            SetOwnProperty("NaN", new PropertyDescriptor(double.NaN, PropertyFlag.AllForbidden));
+            SetOwnProperty("NEGATIVE_INFINITY", new PropertyDescriptor(double.NegativeInfinity, PropertyFlag.AllForbidden));
+            SetOwnProperty("POSITIVE_INFINITY", new PropertyDescriptor(double.PositiveInfinity, PropertyFlag.AllForbidden));
         }
 
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)

+ 16 - 19
Jint/Native/Object/ObjectConstructor.cs

@@ -5,7 +5,6 @@ using Jint.Native.Function;
 using Jint.Native.String;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Object
@@ -26,8 +25,8 @@ namespace Jint.Native.Object
 
             obj.PrototypeObject = ObjectPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
@@ -222,7 +221,7 @@ namespace Jint.Native.Object
             var descriptors = new List<KeyValuePair<string, PropertyDescriptor>>();
             foreach (var p in props.GetOwnProperties())
             {
-                if (!p.Value.Enumerable.HasValue || !p.Value.Enumerable.Value)
+                if (!p.Value.Enumerable)
                 {
                     continue;
                 }
@@ -248,16 +247,14 @@ namespace Jint.Native.Object
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var properties = new List<KeyValuePair<string, IPropertyDescriptor>>(o.GetOwnProperties());
+            var properties = new List<KeyValuePair<string, PropertyDescriptor>>(o.GetOwnProperties());
             foreach (var prop in properties)
             {
                 var propertyDescriptor = prop.Value;
-                if (propertyDescriptor.Configurable.HasValue && propertyDescriptor.Configurable.Value)
+                if (propertyDescriptor.Configurable)
                 {
-                    var mutable = propertyDescriptor as PropertyDescriptor ?? new PropertyDescriptor(propertyDescriptor);
-                    mutable.Configurable = false;
-                    propertyDescriptor = mutable;
-                    FastSetProperty(prop.Key, mutable);
+                    propertyDescriptor.Configurable = false;
+                    FastSetProperty(prop.Key, propertyDescriptor);
                 }
 
                 o.DefineOwnProperty(prop.Key, propertyDescriptor, true);
@@ -277,20 +274,20 @@ namespace Jint.Native.Object
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var properties = new List<KeyValuePair<string, IPropertyDescriptor>>(o.GetOwnProperties());
+            var properties = new List<KeyValuePair<string, PropertyDescriptor>>(o.GetOwnProperties());
             foreach (var p in properties)
             {
                 var desc = o.GetOwnProperty(p.Key);
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value)
+                    if (desc.Writable)
                     {
                         var mutable = desc as PropertyDescriptor ?? new PropertyDescriptor(desc);
                         mutable.Writable = false;
                         desc = mutable;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     var mutable = desc as PropertyDescriptor ?? new PropertyDescriptor(desc);
                     mutable.Configurable = false;
@@ -329,7 +326,7 @@ namespace Jint.Native.Object
 
             foreach (var prop in o.GetOwnProperties())
             {
-                if (prop.Value.Configurable.Value == true)
+                if (prop.Value.Configurable)
                 {
                     return false;
                 }
@@ -352,17 +349,17 @@ namespace Jint.Native.Object
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            foreach (var p in o.GetOwnProperties().Select(x => x.Key))
+            foreach (var pair in o.GetOwnProperties())
             {
-                var desc = o.GetOwnProperty(p);
+                var desc = pair.Value;
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value)
+                    if (desc.Writable)
                     {
                         return false;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     return false;
                 }
@@ -398,7 +395,7 @@ namespace Jint.Native.Object
             }
 
             var enumerableProperties = o.GetOwnProperties()
-                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value)
+                .Where(x => x.Value.Enumerable)
                 .ToArray();
             var n = enumerableProperties.Length;
 

+ 56 - 71
Jint/Native/Object/ObjectInstance.cs

@@ -19,8 +19,8 @@ namespace Jint.Native.Object
 {
     public class ObjectInstance : JsValue, IEquatable<ObjectInstance>
     {
-        private Dictionary<string, IPropertyDescriptor> _intrinsicProperties;
-        private MruPropertyCache2<IPropertyDescriptor> _properties;
+        private Dictionary<string, PropertyDescriptor> _intrinsicProperties;
+        private MruPropertyCache2<PropertyDescriptor> _properties;
 
         public ObjectInstance(Engine engine)
         {
@@ -31,9 +31,7 @@ namespace Jint.Native.Object
 
         protected bool TryGetIntrinsicValue(JsSymbol symbol, out JsValue value)
         {
-            IPropertyDescriptor descriptor;
-
-            if (_intrinsicProperties != null && _intrinsicProperties.TryGetValue(symbol.AsSymbol(), out descriptor))
+            if (_intrinsicProperties != null && _intrinsicProperties.TryGetValue(symbol.AsSymbol(), out var descriptor))
             {
                 value = descriptor.Value;
                 return true;
@@ -57,7 +55,7 @@ namespace Jint.Native.Object
         {
             if (_intrinsicProperties == null)
             {
-                _intrinsicProperties = new Dictionary<string, IPropertyDescriptor>();
+                _intrinsicProperties = new Dictionary<string, PropertyDescriptor>();
             }
 
             _intrinsicProperties[symbol.AsSymbol()] = new PropertyDescriptor(value, writable, enumerable, configurable);
@@ -80,7 +78,7 @@ namespace Jint.Native.Object
         /// </summary>
         public virtual string Class => "Object";
 
-        public virtual IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+        public virtual IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
             EnsureInitialized();
 
@@ -93,17 +91,17 @@ namespace Jint.Native.Object
             }
         }
 
-        protected virtual void AddProperty(string propertyName, IPropertyDescriptor descriptor)
+        protected virtual void AddProperty(string propertyName, PropertyDescriptor descriptor)
         {
             if (_properties == null)
             {
-                _properties = new MruPropertyCache2<IPropertyDescriptor>();
+                _properties = new MruPropertyCache2<PropertyDescriptor>();
             }
 
             _properties.Add(propertyName, descriptor);
         }
 
-        protected virtual bool TryGetProperty(string propertyName, out IPropertyDescriptor descriptor)
+        protected virtual bool TryGetProperty(string propertyName, out PropertyDescriptor descriptor)
         {
             if (_properties == null)
             {
@@ -141,7 +139,7 @@ namespace Jint.Native.Object
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal JsValue UnwrapJsValue(IPropertyDescriptor desc)
+        internal JsValue UnwrapJsValue(PropertyDescriptor desc)
         {
             if (desc == PropertyDescriptor.Undefined)
             {
@@ -173,7 +171,7 @@ namespace Jint.Native.Object
         /// </summary>
         /// <param name="propertyName"></param>
         /// <returns></returns>
-        public virtual IPropertyDescriptor GetOwnProperty(string propertyName)
+        public virtual PropertyDescriptor GetOwnProperty(string propertyName)
         {
             EnsureInitialized();
 
@@ -185,13 +183,13 @@ namespace Jint.Native.Object
             return PropertyDescriptor.Undefined;
         }
 
-        protected internal virtual void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+        protected internal virtual void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
             EnsureInitialized();
 
             if (_properties == null)
             {
-                _properties = new MruPropertyCache2<IPropertyDescriptor>();
+                _properties = new MruPropertyCache2<PropertyDescriptor>();
             }
 
             _properties[propertyName] = desc;
@@ -203,7 +201,7 @@ namespace Jint.Native.Object
         /// <param name="propertyName"></param>
         /// <returns></returns>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public IPropertyDescriptor GetProperty(string propertyName)
+        public PropertyDescriptor GetProperty(string propertyName)
         {
             var prop = GetOwnProperty(propertyName);
 
@@ -302,7 +300,7 @@ namespace Jint.Native.Object
             }
             else
             {
-                var newDesc = new ConfigurableEnumerableWritablePropertyDescriptor(value);
+                var newDesc = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable);
                 DefineOwnProperty(propertyName, newDesc, throwOnError);
             }
         }
@@ -331,7 +329,7 @@ namespace Jint.Native.Object
                     return true;
                 }
 
-                return desc.Writable.HasValue && desc.Writable.Value;
+                return desc.Writable;
             }
 
             if (Prototype == null)
@@ -360,10 +358,8 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            else
-            {
-                return inherited.Writable.HasValue && inherited.Writable.Value;
-            }
+
+            return inherited.Writable;
         }
 
         /// <summary>
@@ -396,7 +392,7 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (desc.Configurable.HasValue && desc.Configurable.Value)
+            if (desc.Configurable)
             {
                 RemoveOwnProperty(propertyName);
                 return true;
@@ -484,7 +480,7 @@ namespace Jint.Native.Object
         /// <param name="desc"></param>
         /// <param name="throwOnError"></param>
         /// <returns></returns>
-        public virtual bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
+        public virtual bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             var current = GetOwnProperty(propertyName);
 
@@ -508,23 +504,20 @@ namespace Jint.Native.Object
                 {
                     if (desc.IsGenericDescriptor() || desc.IsDataDescriptor())
                     {
-                        IPropertyDescriptor propertyDescriptor;
-                        if (desc.Configurable.GetValueOrDefault() && desc.Enumerable.GetValueOrDefault() && desc.Writable.GetValueOrDefault())
+                        PropertyDescriptor propertyDescriptor;
+                        if (desc.Configurable && desc.Enumerable && desc.Writable)
                         {
-                            propertyDescriptor = new ConfigurableEnumerableWritablePropertyDescriptor(desc.Value != null ? desc.Value : Undefined);
+                            propertyDescriptor = new PropertyDescriptor(desc.Value != null ? desc.Value : Undefined, PropertyFlag.ConfigurableEnumerableWritable);
                         }
-                        else if (!desc.Configurable.GetValueOrDefault() && !desc.Enumerable.GetValueOrDefault() && !desc.Writable.GetValueOrDefault())
+                        else if (!desc.Configurable && !desc.Enumerable && !desc.Writable)
                         {
-                            propertyDescriptor = new AllForbiddenPropertyDescriptor(desc.Value != null ? desc.Value : Undefined);
+                            propertyDescriptor = new PropertyDescriptor(desc.Value != null ? desc.Value : Undefined, PropertyFlag.AllForbidden);
                         }
                         else
                         {
                             propertyDescriptor = new PropertyDescriptor(desc)
                             {
-                                Value = desc.Value != null ? desc.Value : Undefined,
-                                Writable = desc.Writable.HasValue ? desc.Writable.Value : false,
-                                Enumerable = desc.Enumerable.HasValue ? desc.Enumerable.Value : false,
-                                Configurable = desc.Configurable.HasValue ? desc.Configurable.Value : false
+                                Value = desc.Value != null ? desc.Value : Undefined
                             };
                         }
 
@@ -532,13 +525,7 @@ namespace Jint.Native.Object
                     }
                     else
                     {
-                        SetOwnProperty(propertyName, new PropertyDescriptor(desc)
-                        {
-                            Get = desc.Get,
-                            Set = desc.Set,
-                            Enumerable = desc.Enumerable.HasValue ? desc.Enumerable : false,
-                            Configurable = desc.Configurable.HasValue ? desc.Configurable : false,
-                        });
+                        SetOwnProperty(propertyName, new GetSetPropertyDescriptor(desc));
                     }
                 }
 
@@ -546,9 +533,9 @@ namespace Jint.Native.Object
             }
 
             // Step 5
-            if (!current.Configurable.HasValue &&
-                !current.Enumerable.HasValue &&
-                !current.Writable.HasValue &&
+            if (!current.ConfigurableSet &&
+                !current.EnumerableSet &&
+                !current.WritableSet &&
                 current.Get == null &&
                 current.Set == null &&
                 current.Value == null)
@@ -558,9 +545,9 @@ namespace Jint.Native.Object
 
             // Step 6
             if (
-                current.Configurable == desc.Configurable &&
-                current.Writable == desc.Writable &&
-                current.Enumerable == desc.Enumerable &&
+                current.Configurable == desc.Configurable && current.ConfigurableSet == desc.ConfigurableSet &&
+                current.Writable == desc.Writable && current.WritableSet == desc.WritableSet &&
+                current.Enumerable == desc.Enumerable && current.EnumerableSet == desc.EnumerableSet &&
                 ((current.Get == null && desc.Get == null) || (current.Get != null && desc.Get != null && ExpressionInterpreter.SameValue(current.Get, desc.Get))) &&
                 ((current.Set == null && desc.Set == null) || (current.Set != null && desc.Set != null && ExpressionInterpreter.SameValue(current.Set, desc.Set))) &&
                 ((current.Value == null && desc.Value == null) || (current.Value != null && desc.Value != null && ExpressionInterpreter.StrictlyEqual(current.Value, desc.Value)))
@@ -569,9 +556,9 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (!current.Configurable.HasValue || !current.Configurable.Value)
+            if (!current.Configurable)
             {
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     if (throwOnError)
                     {
@@ -581,7 +568,7 @@ namespace Jint.Native.Object
                     return false;
                 }
 
-                if (desc.Enumerable.HasValue && (!current.Enumerable.HasValue || desc.Enumerable.Value != current.Enumerable.Value))
+                if (desc.EnumerableSet && (desc.Enumerable != current.Enumerable))
                 {
                     if (throwOnError)
                     {
@@ -596,7 +583,7 @@ namespace Jint.Native.Object
             {
                 if (current.IsDataDescriptor() != desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value)
+                    if (!current.Configurable)
                     {
                         if (throwOnError)
                         {
@@ -608,7 +595,7 @@ namespace Jint.Native.Object
 
                     if (current.IsDataDescriptor())
                     {
-                        SetOwnProperty(propertyName, current = new PropertyDescriptor(
+                        SetOwnProperty(propertyName, current = new GetSetPropertyDescriptor(
                             get: JsValue.Undefined,
                             set: JsValue.Undefined,
                             enumerable: current.Enumerable,
@@ -627,9 +614,9 @@ namespace Jint.Native.Object
                 }
                 else if (current.IsDataDescriptor() && desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || current.Configurable.Value == false)
+                    if (!current.Configurable)
                     {
-                        if (!current.Writable.HasValue || !current.Writable.Value && desc.Writable.HasValue && desc.Writable.Value)
+                        if (!current.Writable && desc.Writable)
                         {
                             if (throwOnError)
                             {
@@ -639,7 +626,7 @@ namespace Jint.Native.Object
                             return false;
                         }
 
-                        if (!current.Writable.Value)
+                        if (!current.Writable)
                         {
                             if (desc.Value != null && !ExpressionInterpreter.SameValue(desc.Value, current.Value))
                             {
@@ -655,7 +642,7 @@ namespace Jint.Native.Object
                 }
                 else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value)
+                    if (!current.Configurable)
                     {
                         if ((desc.Set != null && !ExpressionInterpreter.SameValue(desc.Set, current.Set != null ? current.Set : Undefined))
                             ||
@@ -677,39 +664,37 @@ namespace Jint.Native.Object
                 current.Value = desc.Value;
             }
 
-            PropertyDescriptor mutable = null;
-            if (desc.Writable.HasValue)
+            if (desc.WritableSet)
             {
-                current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
-                mutable.Writable = desc.Writable;
+                current.Writable = desc.Writable;
             }
 
-            if (desc.Enumerable.HasValue)
+            if (desc.EnumerableSet)
             {
-                current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
-                mutable.Enumerable = desc.Enumerable;
+                current.Enumerable = desc.Enumerable;
             }
 
-            if (desc.Configurable.HasValue)
+            if (desc.ConfigurableSet)
             {
-                current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
-                mutable.Configurable = desc.Configurable;
+                current.Configurable = desc.Configurable;
             }
 
+            PropertyDescriptor mutable = null;
             if (desc.Get != null)
             {
-                current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
-                mutable.Get = desc.Get;
+                mutable = new GetSetPropertyDescriptor(mutable ?? current);
+                ((GetSetPropertyDescriptor) mutable).SetGet(desc.Get);
             }
 
             if (desc.Set != null)
             {
-                mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
-                mutable.Set = desc.Set;
+                mutable = new GetSetPropertyDescriptor(mutable ?? current);
+                ((GetSetPropertyDescriptor) mutable).SetSet(desc.Set);
             }
 
             if (mutable != null)
-            {
+            { 
+                // replace old with new type that supports get and set
                 FastSetProperty(propertyName, mutable);
             }
 
@@ -734,7 +719,7 @@ namespace Jint.Native.Object
         /// </summary>
         /// <param name="name"></param>
         /// <param name="value"></param>
-        public void FastSetProperty(string name, IPropertyDescriptor value)
+        public void FastSetProperty(string name, PropertyDescriptor value)
         {
             SetOwnProperty(name, value);
         }
@@ -915,7 +900,7 @@ namespace Jint.Native.Object
 
                     foreach (var p in GetOwnProperties())
                     {
-                        if (!p.Value.Enumerable.HasValue || p.Value.Enumerable.Value == false)
+                        if (!p.Value.Enumerable)
                         {
                             continue;
                         }

+ 1 - 1
Jint/Native/Object/ObjectPrototype.cs

@@ -38,7 +38,7 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            return desc.Enumerable.HasValue && desc.Enumerable.Value;
+            return desc.Enumerable;
         }
 
         private JsValue ValueOf(JsValue thisObject, JsValue[] arguments)

+ 8 - 8
Jint/Native/RegExp/RegExpConstructor.cs

@@ -4,7 +4,7 @@ using Esprima;
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.RegExp
 {
@@ -24,10 +24,10 @@ namespace Jint.Native.RegExp
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = RegExpPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(2));
+            obj.SetOwnProperty("length", new PropertyDescriptor(2, PropertyFlag.AllForbidden));
 
             // The initial value of RegExp.prototype is the RegExp prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
@@ -158,11 +158,11 @@ namespace Jint.Native.RegExp
 
         private static void SetRegexProperties(RegExpInstance r)
         {
-            r.SetOwnProperty("global", new AllForbiddenPropertyDescriptor(r.Global));
-            r.SetOwnProperty("ignoreCase", new AllForbiddenPropertyDescriptor(r.IgnoreCase));
-            r.SetOwnProperty("multiline", new AllForbiddenPropertyDescriptor(r.Multiline));
-            r.SetOwnProperty("source", new AllForbiddenPropertyDescriptor(r.Source));
-            r.SetOwnProperty("lastIndex", new WritablePropertyDescriptor(0));
+            r.SetOwnProperty("global", new PropertyDescriptor(r.Global, PropertyFlag.AllForbidden));
+            r.SetOwnProperty("ignoreCase", new PropertyDescriptor(r.IgnoreCase, PropertyFlag.AllForbidden));
+            r.SetOwnProperty("multiline", new PropertyDescriptor(r.Multiline, PropertyFlag.AllForbidden));
+            r.SetOwnProperty("source", new PropertyDescriptor(r.Source, PropertyFlag.AllForbidden));
+            r.SetOwnProperty("lastIndex", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
         }
 
         private void AssignFlags(RegExpInstance r, string flags)

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

@@ -2,7 +2,6 @@
 using Jint.Native.Array;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.RegExp
@@ -125,9 +124,9 @@ namespace Jint.Native.RegExp
 
         private static ArrayInstance InitReturnValueArray(ArrayInstance array, string inputValue, int lengthValue, int indexValue)
         {
-            array.SetOwnProperty("index", new ConfigurableEnumerableWritablePropertyDescriptor(indexValue));
-            array.SetOwnProperty("input", new ConfigurableEnumerableWritablePropertyDescriptor(inputValue));
-            array.SetOwnProperty("length", new WritablePropertyDescriptor(lengthValue));
+            array.SetOwnProperty("index", new PropertyDescriptor(indexValue, PropertyFlag.ConfigurableEnumerableWritable));
+            array.SetOwnProperty("input", new PropertyDescriptor(inputValue, PropertyFlag.ConfigurableEnumerableWritable));
+            array.SetOwnProperty("length", new PropertyDescriptor(lengthValue, PropertyFlag.OnlyWritable));
             return array;
         }
     }

+ 5 - 5
Jint/Native/String/StringConstructor.cs

@@ -1,7 +1,7 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.String
@@ -22,17 +22,17 @@ namespace Jint.Native.String
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = StringPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(1));
+            obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
 
             // The initial value of String.prototype is the String prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
 
         public void Configure()
         {
-            SetOwnProperty("fromCharCode", new NonEnumerablePropertyDescriptor(new ClrFunctionInstance(Engine, FromCharCode, 1)));
+            SetOwnProperty("fromCharCode", new PropertyDescriptor(new ClrFunctionInstance(Engine, FromCharCode, 1), PropertyFlag.NonEnumerable));
         }
 
         private static JsValue FromCharCode(JsValue thisObj, JsValue[] arguments)
@@ -75,7 +75,7 @@ namespace Jint.Native.String
             instance.PrimitiveValue = value;
             instance.Extensible = true;
 
-            instance.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(value.Length));
+            instance.SetOwnProperty("length", new PropertyDescriptor(value.Length, PropertyFlag.AllForbidden));
 
             return instance;
         }

+ 6 - 7
Jint/Native/String/StringInstance.cs

@@ -2,7 +2,6 @@
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
 
 namespace Jint.Native.String
 {
@@ -11,7 +10,7 @@ namespace Jint.Native.String
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
 
-        private IPropertyDescriptor _length;
+        private PropertyDescriptor _length;
 
         public StringInstance(Engine engine)
             : base(engine)
@@ -37,7 +36,7 @@ namespace Jint.Native.String
             return false;
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             if (propertyName.Length == 8 && propertyName == "Infinity")
             {
@@ -74,14 +73,14 @@ namespace Jint.Native.String
             }
 
             var resultStr = TypeConverter.ToString(str.AsString()[index]);
-            return new EnumerablePropertyDescriptor(resultStr);
+            return new PropertyDescriptor(resultStr, PropertyFlag.OnlyEnumerable);
         }
 
-        public override IEnumerable<KeyValuePair<string, IPropertyDescriptor>> GetOwnProperties()
+        public override IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
             if (_length != null)
             {
-                yield return new KeyValuePair<string, IPropertyDescriptor>(PropertyNameLength, _length);
+                yield return new KeyValuePair<string, PropertyDescriptor>(PropertyNameLength, _length);
             }
 
             foreach (var entry in base.GetOwnProperties())
@@ -90,7 +89,7 @@ namespace Jint.Native.String
             }
         }
 
-        protected internal override void SetOwnProperty(string propertyName, IPropertyDescriptor desc)
+        protected internal override void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
             if (propertyName.Length == PropertyNameLengthLength && propertyName == PropertyNameLength)
             {

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

@@ -6,7 +6,7 @@ using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Native.RegExp;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.String
@@ -27,8 +27,8 @@ namespace Jint.Native.String
             obj.Prototype = engine.Object.PrototypeObject;
             obj.PrimitiveValue = "";
             obj.Extensible = true;
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
-            obj.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(stringConstructor));
+            obj.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
+            obj.SetOwnProperty("constructor", new PropertyDescriptor(stringConstructor, PropertyFlag.NonEnumerable));
 
             return obj;
         }

+ 3 - 3
Jint/Native/Symbol/SymbolConstructor.cs

@@ -1,7 +1,7 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Symbol
@@ -26,10 +26,10 @@ namespace Jint.Native.Symbol
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = SymbolPrototype.CreatePrototypeObject(engine, obj);
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
+            obj.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
 
             // The initial value of String.prototype is the String prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(obj.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
 
 
             return obj;

+ 2 - 2
Jint/Native/Symbol/SymbolPrototype.cs

@@ -1,6 +1,6 @@
 using Jint.Native.Object;
 using Jint.Runtime;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Symbol
@@ -20,7 +20,7 @@ namespace Jint.Native.Symbol
             var obj = new SymbolPrototype(engine);
             obj.Prototype = engine.Object.PrototypeObject;
             obj.Extensible = true;
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
+            obj.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
             obj.FastAddProperty("constructor", symbolConstructor, true, false, true);
 
             return obj;

+ 0 - 16
Jint/Runtime/Descriptors/IPropertyDescriptor .cs

@@ -1,16 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors
-{
-    public interface IPropertyDescriptor
-    {
-        JsValue Get { get; }
-        JsValue Set { get; }
-
-        bool? Enumerable { get; }
-        bool? Writable { get; }
-        bool? Configurable { get; }
-
-        JsValue Value { get; set; }
-    }
-}

+ 224 - 56
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -1,12 +1,15 @@
-using Jint.Native;
+using System.Runtime.CompilerServices;
+using Jint.Native;
 using Jint.Native.Object;
 using Jint.Runtime.Descriptors.Specialized;
 
 namespace Jint.Runtime.Descriptors
 {
-    public class PropertyDescriptor : IPropertyDescriptor
+    public class PropertyDescriptor
     {
-        public static readonly IPropertyDescriptor Undefined = new PropertyDescriptor();
+        public static readonly PropertyDescriptor Undefined = new PropertyDescriptor();
+
+        private PropertyFlag _flags;
 
         protected PropertyDescriptor()
         {
@@ -16,53 +19,150 @@ namespace Jint.Runtime.Descriptors
         {
             Value = value;
 
-            if (writable.HasValue)
+            Writable = writable.GetValueOrDefault();
+            WritableSet = writable != null;
+
+            Enumerable = enumerable.GetValueOrDefault();
+            EnumerableSet = enumerable != null;
+
+            Configurable = configurable.GetValueOrDefault();
+            ConfigurableSet = configurable != null;
+        }
+
+        internal PropertyDescriptor(JsValue value, PropertyFlag flags)
+        {
+            Value = value;
+            _flags = flags;
+        }
+
+        public PropertyDescriptor(PropertyDescriptor descriptor)
+        {
+            Value = descriptor.Value;
+
+            Enumerable = descriptor.Enumerable;
+            EnumerableSet = descriptor.EnumerableSet;
+            
+            Configurable = descriptor.Configurable;
+            ConfigurableSet = descriptor.ConfigurableSet;
+
+            Writable = descriptor.Writable;
+            WritableSet = descriptor.WritableSet;
+        }
+
+        public virtual JsValue Get => null;
+        public virtual JsValue Set => null;
+
+        public bool Enumerable
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & PropertyFlag.Enumerable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            set
             {
-                Writable = writable.Value;
+                _flags |= PropertyFlag.EnumerableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Enumerable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Enumerable);
+                }
             }
-
-            if (enumerable.HasValue)
+        }
+                
+        public bool EnumerableSet
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.EnumerableSet | PropertyFlag.Enumerable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
             {
-                Enumerable = enumerable.Value;
+                if (value)
+                {
+                    _flags |= PropertyFlag.EnumerableSet;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.EnumerableSet);
+                }
             }
+        }
 
-            if (configurable.HasValue)
+        public bool Writable
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & PropertyFlag.Writable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            set
             {
-                Configurable = configurable.Value;
+                _flags |= PropertyFlag.WritableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Writable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Writable);
+                }
             }
         }
 
-        public PropertyDescriptor(JsValue get, JsValue set, bool? enumerable = null, bool? configurable = null)
+        public bool WritableSet
         {
-            Get = get;
-            Set = set;
-
-            if (enumerable.HasValue)
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
             {
-                Enumerable = enumerable.Value;
+                if (value)
+                {
+                    _flags |= PropertyFlag.WritableSet;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.WritableSet);
+                }
             }
+        }
 
-            if (configurable.HasValue)
+        public bool Configurable
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & PropertyFlag.Configurable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            set
             {
-                Configurable = configurable.Value;
+                _flags |= PropertyFlag.ConfigurableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Configurable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Configurable);
+                }
             }
         }
-
-        public PropertyDescriptor(IPropertyDescriptor descriptor)
+        
+        public bool ConfigurableSet
         {
-            Get = descriptor.Get;
-            Set = descriptor.Set;
-            Value = descriptor.Value;
-            Enumerable = descriptor.Enumerable;
-            Configurable = descriptor.Configurable;
-            Writable = descriptor.Writable;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.ConfigurableSet | PropertyFlag.Configurable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
+            {
+                if (value)
+                {
+                    _flags |= PropertyFlag.ConfigurableSet;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.ConfigurableSet);
+                }
+            }
         }
 
-        public JsValue Get { get; set; }
-        public JsValue Set { get; set; }
-        public bool? Enumerable { get; set; }
-        public bool? Writable { get; set; }
-        public bool? Configurable { get; set; }
         public virtual JsValue Value { get; set; }
 
         public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o)
@@ -73,58 +173,73 @@ namespace Jint.Runtime.Descriptors
                 throw new JavaScriptException(engine.TypeError);
             }
 
+            var getProperty = obj.GetProperty("get");
+            var hasGetProperty = getProperty != Undefined;
+            var setProperty = obj.GetProperty("set");
+            var hasSetProperty = setProperty != Undefined;
+            
             if ((obj.HasProperty("value") || obj.HasProperty("writable")) &&
-                (obj.HasProperty("get") || obj.HasProperty("set")))
+                (hasGetProperty || hasSetProperty))
             {
                 throw new JavaScriptException(engine.TypeError);
             }
 
-            var desc = new PropertyDescriptor();
+            var desc = hasGetProperty || hasSetProperty
+                ? new GetSetPropertyDescriptor(null, null, null, null)
+                : new PropertyDescriptor();
 
-            if (obj.HasProperty("enumerable"))
+            var enumerableProperty = obj.GetProperty("enumerable");
+            if (enumerableProperty != Undefined)
             {
-                desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable"));
+                desc.Enumerable = TypeConverter.ToBoolean(obj.UnwrapJsValue(enumerableProperty));
+                desc.EnumerableSet = true;
             }
 
-            if (obj.HasProperty("configurable"))
+            var configurableProperty = obj.GetProperty("configurable");
+            if (configurableProperty != Undefined)
             {
-                desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable"));
+                desc.Configurable = TypeConverter.ToBoolean(obj.UnwrapJsValue(configurableProperty));
+                desc.ConfigurableSet = true;
             }
 
-            if (obj.HasProperty("value"))
+            var valueProperty = obj.GetProperty("value");
+            if (valueProperty != Undefined)
             {
-                var value = obj.Get("value");
-                desc.Value = value;
+                desc.Value = obj.UnwrapJsValue(valueProperty);
             }
 
-            if (obj.HasProperty("writable"))
+            var writableProperty = obj.GetProperty("writable");
+            if (writableProperty != Undefined)
             {
-                desc.Writable = TypeConverter.ToBoolean(obj.Get("writable"));
+                desc.Writable = TypeConverter.ToBoolean(obj.UnwrapJsValue(writableProperty));
+                desc.WritableSet = true;
             }
 
-            if (obj.HasProperty("get"))
+            if (hasGetProperty)
             {
-                var getter = obj.Get("get");
+                var getter = obj.UnwrapJsValue(getProperty);
                 if (getter != JsValue.Undefined && getter.TryCast<ICallable>() == null)
                 {
                     throw new JavaScriptException(engine.TypeError);
                 }
-                desc.Get = getter;
+
+                ((GetSetPropertyDescriptor) desc).SetGet(getter);
             }
 
-            if (obj.HasProperty("set"))
+            if (hasSetProperty)
             {
-                var setter = obj.Get("set");
+                var setter = obj.UnwrapJsValue(setProperty);
                 if (setter != Native.Undefined.Instance && setter.TryCast<ICallable>() == null)
                 {
                     throw new JavaScriptException(engine.TypeError);
                 }
-                desc.Set = setter;
+
+                ((GetSetPropertyDescriptor) desc).SetSet(setter);
             }
 
             if (desc.Get != null || desc.Get != null)
             {
-                if (desc.Value != null || desc.Writable.HasValue)
+                if (desc.Value != null || desc.WritableSet)
                 {
                     throw new JavaScriptException(engine.TypeError);
                 }
@@ -133,7 +248,7 @@ namespace Jint.Runtime.Descriptors
             return desc;
         }
 
-        public static JsValue FromPropertyDescriptor(Engine engine, IPropertyDescriptor desc)
+        public static JsValue FromPropertyDescriptor(Engine engine, PropertyDescriptor desc)
         {
             if (ReferenceEquals(desc, Undefined))
             {
@@ -144,19 +259,72 @@ namespace Jint.Runtime.Descriptors
 
             if (desc.IsDataDescriptor())
             {
-                obj.SetOwnProperty("value", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Value != null ? desc.Value : Native.Undefined.Instance));
-                obj.SetOwnProperty("writable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Writable.HasValue && desc.Writable.Value));
+                obj.SetOwnProperty("value", new PropertyDescriptor(desc.Value != null ? desc.Value : Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
+                obj.SetOwnProperty("writable", new PropertyDescriptor(desc.Writable, PropertyFlag.ConfigurableEnumerableWritable));
             }
             else
             {
-                obj.SetOwnProperty("get", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Get ?? Native.Undefined.Instance));
-                obj.SetOwnProperty("set", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Set ?? Native.Undefined.Instance));
+                obj.SetOwnProperty("get", new PropertyDescriptor(desc.Get ?? Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
+                obj.SetOwnProperty("set", new PropertyDescriptor(desc.Set ?? Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
             }
 
-            obj.SetOwnProperty("enumerable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Enumerable.HasValue && desc.Enumerable.Value));
-            obj.SetOwnProperty("configurable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Configurable.HasValue && desc.Configurable.Value));
+            obj.SetOwnProperty("enumerable", new PropertyDescriptor(desc.Enumerable, PropertyFlag.ConfigurableEnumerableWritable));
+            obj.SetOwnProperty("configurable", new PropertyDescriptor(desc.Configurable, PropertyFlag.ConfigurableEnumerableWritable));
 
             return obj;
         }
+        
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public bool IsAccessorDescriptor()
+        {
+            return Get != null || Set != null;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public bool IsDataDescriptor()
+        {
+            return WritableSet || Value != null;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.3
+        /// </summary>
+        /// <returns></returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public bool IsGenericDescriptor()
+        {
+            return !IsDataDescriptor() && !IsAccessorDescriptor();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal bool TryGetValue(ObjectInstance thisArg, out JsValue value)
+        {
+            value = JsValue.Undefined;
+
+            if (this == Undefined)
+            {
+                value = JsValue.Undefined;
+                return false;
+            }
+
+            if (IsDataDescriptor())
+            {
+                var val = Value;
+                if (val != null)
+                {
+                    value = val;
+                    return true;
+                }
+            }
+
+            if (Get != null && !Get.IsUndefined())
+            {
+                // if getter is not undefined it must be ICallable
+                var callable = Get.TryCast<ICallable>();
+                value = callable.Call(thisArg, Arguments.Empty);
+            }
+
+            return true;
+        }
     }
 }

+ 0 - 62
Jint/Runtime/Descriptors/PropertyDescriptorExtensions.cs

@@ -1,62 +0,0 @@
-using System.Runtime.CompilerServices;
-using Jint.Native;
-using Jint.Native.Object;
-
-namespace Jint.Runtime.Descriptors
-{
-    public static class PropertyDescriptorExtensions
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsAccessorDescriptor(this IPropertyDescriptor descriptor)
-        {
-            return descriptor.Get != null || descriptor.Set != null;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsDataDescriptor(this IPropertyDescriptor descriptor)
-        {
-            return descriptor.Writable.HasValue || descriptor.Value != null;
-        }
-
-        /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.3
-        /// </summary>
-        /// <returns></returns>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsGenericDescriptor(this IPropertyDescriptor descriptor)
-        {
-            return !descriptor.IsDataDescriptor() && !descriptor.IsAccessorDescriptor();
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool TryGetValue(this IPropertyDescriptor descriptor, ObjectInstance thisArg, out JsValue value)
-        {
-            value = JsValue.Undefined;
-
-            if (descriptor == PropertyDescriptor.Undefined)
-            {
-                value = JsValue.Undefined;
-                return false;
-            }
-
-            if (descriptor.IsDataDescriptor())
-            {
-                var val = descriptor.Value;
-                if (val != null)
-                {
-                    value = val;
-                    return true;
-                }
-            }
-
-            if (descriptor.Get != null && !descriptor.Get.IsUndefined())
-            {
-                // if getter is not undefined it must be ICallable
-                var callable = descriptor.Get.TryCast<ICallable>();
-                value = callable.Call(thisArg, Arguments.Empty);
-            }
-
-            return true;
-        }
-    }
-}

+ 24 - 0
Jint/Runtime/Descriptors/PropertyFlag.cs

@@ -0,0 +1,24 @@
+using System;
+
+namespace Jint.Runtime.Descriptors
+{
+    [Flags]
+    internal enum PropertyFlag
+    {
+        None = 0,
+        Enumerable = 1,
+        EnumerableSet = 2,
+        Writable = 4,
+        WritableSet = 8,
+        Configurable = 16,
+        ConfigurableSet = 32,
+        
+        // common helpers
+        AllForbidden = ConfigurableSet | EnumerableSet | WritableSet,
+        ConfigurableEnumerableWritable = Configurable | Enumerable | Writable,
+        NonConfigurable = ConfigurableSet | Enumerable | Writable,
+        OnlyEnumerable = Enumerable | ConfigurableSet | WritableSet,
+        NonEnumerable = Configurable | EnumerableSet | Writable,
+        OnlyWritable = EnumerableSet | Writable | ConfigurableSet
+    }
+}

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/AllForbiddenPropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = false, enumerable = false, writable = false.
-    /// </summary>
-    internal sealed class AllForbiddenPropertyDescriptor : IPropertyDescriptor
-    {
-        public AllForbiddenPropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => false;
-        public bool? Writable => false;
-        public bool? Configurable => false;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 4 - 9
Jint/Runtime/Descriptors/Specialized/ClrAccessDescriptor.cs

@@ -4,7 +4,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Runtime.Descriptors.Specialized
 {
-    internal sealed class ClrAccessDescriptor : IPropertyDescriptor
+    internal sealed class ClrAccessDescriptor : PropertyDescriptor
     {
         private readonly EnvironmentRecord _env;
         private readonly Engine _engine;
@@ -17,20 +17,15 @@ namespace Jint.Runtime.Descriptors.Specialized
             EnvironmentRecord env,
             Engine engine,
             string name)
+            : base(value: null, writable: null, enumerable: null, configurable: true)
         {
             _env = env;
             _engine = engine;
             _name = name;
         }
 
-        public JsValue Get => _get = _get ?? new GetterFunctionInstance(_engine, DoGet);
-        public JsValue Set => _set = _set ?? new SetterFunctionInstance(_engine, DoSet);
-
-        public bool? Enumerable => null;
-        public bool? Writable => null;
-        public bool? Configurable => true;
-
-        public JsValue Value { get; set; }
+        public override JsValue Get => _get = _get ?? new GetterFunctionInstance(_engine, DoGet);
+        public override JsValue Set => _set = _set ?? new SetterFunctionInstance(_engine, DoSet);
 
         private JsValue DoGet(JsValue n)
         {

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/ConfigurableEnumerableWritablePropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = true, enumerable = true, writable = true.
-    /// </summary>
-    internal sealed class ConfigurableEnumerableWritablePropertyDescriptor : IPropertyDescriptor
-    {
-        public ConfigurableEnumerableWritablePropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => true;
-        public bool? Writable => true;
-        public bool? Configurable => true;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/EnumerablePropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = true, enumerable = true, writable = true.
-    /// </summary>
-    internal sealed class EnumerablePropertyDescriptor : IPropertyDescriptor
-    {
-        public EnumerablePropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => true;
-        public bool? Writable => false;
-        public bool? Configurable => false;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 36 - 0
Jint/Runtime/Descriptors/Specialized/GetSetPropertyDescriptor.cs

@@ -0,0 +1,36 @@
+using Jint.Native;
+
+namespace Jint.Runtime.Descriptors.Specialized
+{
+    public sealed class GetSetPropertyDescriptor : PropertyDescriptor
+    {
+        private JsValue _get;
+        private JsValue _set;
+
+        public GetSetPropertyDescriptor(JsValue get, JsValue set, bool? enumerable = null, bool? configurable = null)
+        : base(null, writable: null, enumerable: enumerable, configurable: configurable)
+        {
+            _get = get;
+            _set = set;
+        }
+
+        public GetSetPropertyDescriptor(PropertyDescriptor descriptor) : base(descriptor)
+        {
+            _get = descriptor.Get;
+            _set = descriptor.Set;
+        }
+
+        public override JsValue Get => _get;
+        public override JsValue Set => _set;
+
+        internal void SetGet(JsValue getter)
+        {
+            _get = getter;
+        }
+        
+        internal void SetSet(JsValue setter)
+        {
+            _set = setter;
+        }
+    }
+}

+ 0 - 1
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -49,7 +49,6 @@ namespace Jint.Runtime.Descriptors.Specialized
             Writable = true;
         }
 
-
         public IndexDescriptor(Engine engine, string key, object item)
             : this(engine, item.GetType(), key, item)
         {

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/NonConfigurablePropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = false, enumerable = true, writable = true.
-    /// </summary>
-    internal sealed class NonConfigurablePropertyDescriptor : IPropertyDescriptor
-    {
-        public NonConfigurablePropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => true;
-        public bool? Writable => true;
-        public bool? Configurable => false;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/NonEnumerablePropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = true, enumerable = false, writable  = true.
-    /// </summary>
-    internal sealed class NonEnumerablePropertyDescriptor : IPropertyDescriptor
-    {
-        public NonEnumerablePropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => false;
-        public bool? Writable => true;
-        public bool? Configurable => true;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/NullConfigurationPropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = null, enumerable = null, writable = null.
-    /// </summary>
-    internal sealed class NullConfigurationPropertyDescriptor : IPropertyDescriptor
-    {
-        public NullConfigurationPropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => null;
-        public bool? Writable => null;
-        public bool? Configurable => null;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 0 - 24
Jint/Runtime/Descriptors/Specialized/WritablePropertyDescriptor.cs

@@ -1,24 +0,0 @@
-using Jint.Native;
-
-namespace Jint.Runtime.Descriptors.Specialized
-{
-    /// <summary>
-    /// configurable = false, enumerable = false, writable  = true.
-    /// </summary>
-    internal sealed class WritablePropertyDescriptor : IPropertyDescriptor
-    {
-        public WritablePropertyDescriptor(JsValue value)
-        {
-            Value = value;
-        }
-
-        public JsValue Get => null;
-        public JsValue Set => null;
-
-        public bool? Enumerable => false;
-        public bool? Writable => true;
-        public bool? Configurable => false;
-
-        public JsValue Value { get; set; }
-    }
-}

+ 2 - 3
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -3,7 +3,6 @@ using System.Linq;
 using Jint.Native;
 using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
-using Jint.Runtime.Descriptors.Specialized;
 
 namespace Jint.Runtime.Environments
 {
@@ -35,8 +34,8 @@ namespace Jint.Runtime.Environments
         public override void CreateMutableBinding(string name, JsValue value, bool configurable = true)
         {
             var propertyDescriptor = configurable
-                ? (IPropertyDescriptor) new ConfigurableEnumerableWritablePropertyDescriptor(value)
-                : new NonConfigurablePropertyDescriptor(value);
+                ? new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable)
+                : new PropertyDescriptor(value, PropertyFlag.NonConfigurable);
 
             _bindingObject.SetOwnProperty(name, propertyDescriptor);
         }

+ 15 - 13
Jint/Runtime/ExpressionIntepreter.cs

@@ -664,7 +664,7 @@ namespace Jint.Runtime
                 var property = objectExpression.Properties[i];
                 var propName = property.Key.GetKey();
                 var previous = obj.GetOwnProperty(propName);
-                IPropertyDescriptor propDesc;
+                PropertyDescriptor propDesc;
 
                 switch (property.Kind)
                 {
@@ -672,7 +672,7 @@ namespace Jint.Runtime
                     case PropertyKind.Data:
                         var exprValue = _engine.EvaluateExpression(property.Value.As<Expression>());
                         var propValue = _engine.GetValue(exprValue, true);
-                        propDesc = new ConfigurableEnumerableWritablePropertyDescriptor(propValue);
+                        propDesc = new PropertyDescriptor(propValue, PropertyFlag.ConfigurableEnumerableWritable);
                         break;
 
                     case PropertyKind.Get:
@@ -694,7 +694,7 @@ namespace Jint.Runtime
                             );
                         }
 
-                        propDesc = new PropertyDescriptor(get: get, set: null, enumerable: true, configurable: true);
+                        propDesc = new GetSetPropertyDescriptor(get: get, set: null, enumerable: true, configurable: true);
                         break;
 
                     case PropertyKind.Set:
@@ -716,7 +716,7 @@ namespace Jint.Runtime
                             );
                         }
 
-                        propDesc = new PropertyDescriptor(get: null, set: set, enumerable: true, configurable: true);
+                        propDesc = new GetSetPropertyDescriptor(get: null, set: set, enumerable: true, configurable: true);
                         break;
 
                     default:
@@ -815,14 +815,16 @@ namespace Jint.Runtime
         public JsValue EvaluateCallExpression(CallExpression callExpression)
         {
             var callee = EvaluateExpression(callExpression.Callee);
-
-            if (_engine.Options._IsDebugMode)
+            var options = _engine.Options;
+            var maxRecursionDepth = options._MaxRecursionDepth;
+            var debug = options._IsDebugMode;
+            
+            if (debug)
             {
                 _engine.DebugHandler.AddToDebugCallStack(callExpression);
             }
 
             JsValue thisObject;
-
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
 
             var arguments = Array.Empty<JsValue>();
@@ -858,13 +860,13 @@ namespace Jint.Runtime
 
             var r = callee as Reference;
 
-            if (_engine.Options._MaxRecursionDepth >= 0)
+            if (maxRecursionDepth >= 0)
             {
                 var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
 
                 var recursionDepth = _engine.CallStack.Push(stackItem);
 
-                if (recursionDepth > _engine.Options._MaxRecursionDepth)
+                if (recursionDepth > maxRecursionDepth)
                 {
                     _engine.CallStack.Pop();
                     throw new RecursionDepthOverflowException(_engine.CallStack, stackItem.ToString());
@@ -879,8 +881,8 @@ namespace Jint.Runtime
             if (!func.IsObject())
             {
 
-                if (_engine.Options._ReferenceResolver == null ||
-                    !_engine.Options._ReferenceResolver.TryGetCallable(_engine, callee, out func))
+                if (options._ReferenceResolver == null ||
+                    !options._ReferenceResolver.TryGetCallable(_engine, callee, out func))
                 {
                     throw new JavaScriptException(_engine.TypeError,
                         r == null ? "" : string.Format("Property '{0}' of object is not a function", r.GetReferencedName()));
@@ -920,12 +922,12 @@ namespace Jint.Runtime
 
             var result = callable.Call(thisObject, arguments);
 
-            if (_engine.Options._IsDebugMode)
+            if (debug)
             {
                 _engine.DebugHandler.PopDebugCallStack();
             }
 
-            if (_engine.Options._MaxRecursionDepth >= 0)
+            if (maxRecursionDepth >= 0)
             {
                 _engine.CallStack.Pop();
             }

+ 2 - 2
Jint/Runtime/Interop/ClrFunctionInstance.cs

@@ -1,7 +1,7 @@
 using System;
 using Jint.Native;
 using Jint.Native.Function;
-using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Descriptors;
 
 namespace Jint.Runtime.Interop
 {
@@ -17,7 +17,7 @@ namespace Jint.Runtime.Interop
         {
             _func = func;
             Prototype = engine.Function.PrototypeObject;
-            SetOwnProperty("length", new AllForbiddenPropertyDescriptor(length));
+            SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.AllForbidden));
             Extensible = true;
         }
 

+ 2 - 2
Jint/Runtime/Interop/NamespaceReference.cs

@@ -23,7 +23,7 @@ namespace Jint.Runtime.Interop
             _path = path;
         }
 
-        public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
+        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             if (throwOnError)
             {
@@ -193,7 +193,7 @@ namespace Jint.Runtime.Interop
             }
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             return PropertyDescriptor.Undefined;
         }

+ 3 - 3
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -50,7 +50,7 @@ namespace Jint.Runtime.Interop
             ownDesc.Value = value;
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             if (TryGetProperty(propertyName, out var x))
                 return x;
@@ -86,7 +86,7 @@ namespace Jint.Runtime.Interop
 
             if (methods.Any())
             {
-                var descriptor = new EnumerablePropertyDescriptor(new MethodInfoFunctionInstance(Engine, methods));
+                var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, methods), PropertyFlag.OnlyEnumerable);
                 AddProperty(propertyName, descriptor);
                 return descriptor;
             }
@@ -120,7 +120,7 @@ namespace Jint.Runtime.Interop
 
             if (explicitMethods.Length > 0)
             {
-                var descriptor = new EnumerablePropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods));
+                var descriptor = new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, explicitMethods), PropertyFlag.OnlyEnumerable);
                 AddProperty(propertyName, descriptor);
                 return descriptor;
             }

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

@@ -28,10 +28,10 @@ namespace Jint.Runtime.Interop
             // The value of the [[Prototype]] internal property of the TypeReference constructor is the Function prototype object
             obj.Prototype = engine.Function.PrototypeObject;
 
-            obj.SetOwnProperty("length", new AllForbiddenPropertyDescriptor(0));
+            obj.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.AllForbidden));
 
             // The initial value of Boolean.prototype is the Boolean prototype object
-            obj.SetOwnProperty("prototype", new AllForbiddenPropertyDescriptor(engine.Object.PrototypeObject));
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(engine.Object.PrototypeObject, PropertyFlag.AllForbidden));
 
             return obj;
         }
@@ -108,7 +108,7 @@ namespace Jint.Runtime.Interop
             return wrapper.Target.GetType() == ReferenceType;
         }
 
-        public override bool DefineOwnProperty(string propertyName, IPropertyDescriptor desc, bool throwOnError)
+        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
             if (throwOnError)
             {
@@ -157,7 +157,7 @@ namespace Jint.Runtime.Interop
             ownDesc.Value = value;
         }
 
-        public override IPropertyDescriptor GetOwnProperty(string propertyName)
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
             // todo: cache members locally
 
@@ -170,7 +170,7 @@ namespace Jint.Runtime.Interop
                 {
                     if (enumNames.GetValue(i) as string == propertyName)
                     {
-                        return new AllForbiddenPropertyDescriptor((int) enumValues.GetValue(i));
+                        return new PropertyDescriptor((int) enumValues.GetValue(i), PropertyFlag.AllForbidden);
                     }
                 }
                 return PropertyDescriptor.Undefined;
@@ -198,7 +198,7 @@ namespace Jint.Runtime.Interop
                 return PropertyDescriptor.Undefined;
             }
 
-            return new AllForbiddenPropertyDescriptor(new MethodInfoFunctionInstance(Engine, methodInfo));
+            return new PropertyDescriptor(new MethodInfoFunctionInstance(Engine, methodInfo), PropertyFlag.AllForbidden);
         }
 
         public object Target => ReferenceType;

+ 1 - 1
Jint/Runtime/StatementInterpreter.cs

@@ -257,7 +257,7 @@ namespace Jint.Runtime
 
 
                     var value = cursor.GetOwnProperty(p);
-                    if (!value.Enumerable.HasValue || !value.Enumerable.Value)
+                    if (!value.Enumerable)
                     {
                         continue;
                     }