Marko Lahma 2 лет назад
Родитель
Сommit
eeb4865ddc

+ 23 - 0
Jint.Benchmark/ObjectAccessBenchmark.cs

@@ -0,0 +1,23 @@
+using BenchmarkDotNet.Attributes;
+using Esprima.Ast;
+
+namespace Jint.Benchmark;
+
+[MemoryDiagnoser]
+public class ObjectAccessBenchmark
+{
+    private readonly Script _script;
+
+    public ObjectAccessBenchmark()
+    {
+        const string Script = @"const summary = { res: 0; }; for (var i =0; i < 1_000_000; ++i){ summary.res = summary.res + 1; }";
+        _script = Engine.PrepareScript(Script);
+    }
+
+    [Benchmark]
+    public void UpdateObjectProperty()
+    {
+        var engine = new Engine();
+        engine.Evaluate(_script);
+    }
+}

+ 0 - 1
Jint.Tests.PublicInterface/RavenApiUsageTests.cs

@@ -1,4 +1,3 @@
-using System.Diagnostics;
 using Esprima.Ast;
 using Jint.Constraints;
 using Jint.Native;

+ 1 - 1
Jint/Native/Array/ArrayInstance.cs

@@ -21,7 +21,7 @@ namespace Jint.Native.Array
 
         private ObjectChangeFlags _objectChangeFlags;
 
-        private protected ArrayInstance(Engine engine) : base(engine)
+        private protected ArrayInstance(Engine engine, InternalTypes type) : base(engine, type: type)
         {
             _dense = System.Array.Empty<object?>();
         }

+ 1 - 1
Jint/Native/Array/ArrayPrototype.cs

@@ -25,7 +25,7 @@ namespace Jint.Native.Array
             Engine engine,
             Realm realm,
             ArrayConstructor arrayConstructor,
-            ObjectPrototype objectPrototype) : base(engine)
+            ObjectPrototype objectPrototype) : base(engine, InternalTypes.Object)
         {
             _prototype = objectPrototype;
             _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Writable);

+ 1 - 1
Jint/Native/ArrayBuffer/ArrayBufferConstructor.cs

@@ -25,7 +25,7 @@ namespace Jint.Native.ArrayBuffer
             : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
-            PrototypeObject = new ArrayBufferPrototype(engine, realm, this, objectPrototype);
+            PrototypeObject = new ArrayBufferPrototype(engine, this, objectPrototype);
             _length = new PropertyDescriptor(1, PropertyFlag.Configurable);
             _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
         }

+ 2 - 5
Jint/Native/ArrayBuffer/ArrayBufferPrototype.cs

@@ -10,19 +10,16 @@ namespace Jint.Native.ArrayBuffer
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-prototype-object
     /// </summary>
-    internal sealed class ArrayBufferPrototype : ObjectInstance
+    internal sealed class ArrayBufferPrototype : Prototype
     {
-        private readonly Realm _realm;
         private readonly ArrayBufferConstructor _constructor;
 
         internal ArrayBufferPrototype(
             Engine engine,
-            Realm realm,
             ArrayBufferConstructor constructor,
-            ObjectPrototype objectPrototype) : base(engine, 0)
+            ObjectPrototype objectPrototype) : base(engine, engine.Realm)
         {
             _prototype = objectPrototype;
-            _realm = realm;
             _constructor = constructor;
         }
 

+ 1 - 1
Jint/Native/BigInt/BigIntConstructor.cs

@@ -23,7 +23,7 @@ internal sealed class BigIntConstructor : FunctionInstance, IConstructor
         : base(engine, realm, _functionName)
     {
         _prototype = functionPrototype;
-        PrototypeObject = new BigIntPrototype(engine, realm, this, objectPrototype);
+        PrototypeObject = new BigIntPrototype(engine, this, objectPrototype);
         _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
         _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
     }

+ 2 - 5
Jint/Native/BigInt/BigIntPrototype.cs

@@ -12,20 +12,17 @@ namespace Jint.Native.BigInt;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-properties-of-the-bigint-prototype-object
 /// </summary>
-internal sealed class BigIntPrototype : ObjectInstance
+internal sealed class BigIntPrototype : Prototype
 {
-    private readonly Realm _realm;
     private readonly BigIntConstructor _constructor;
 
     internal BigIntPrototype(
         Engine engine,
-        Realm realm,
         BigIntConstructor constructor,
         ObjectPrototype objectPrototype)
-        : base(engine, ObjectClass.Object)
+        : base(engine, engine.Realm)
     {
         _prototype = objectPrototype;
-        _realm = realm;
         _constructor = constructor;
     }
 

+ 1 - 1
Jint/Native/DataView/DataViewConstructor.cs

@@ -21,7 +21,7 @@ namespace Jint.Native.DataView
             : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
-            PrototypeObject = new DataViewPrototype(engine, realm, this, objectPrototype);
+            PrototypeObject = new DataViewPrototype(engine, this, objectPrototype);
             _length = new PropertyDescriptor(1, PropertyFlag.Configurable);
             _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
         }

+ 2 - 5
Jint/Native/DataView/DataViewPrototype.cs

@@ -12,19 +12,16 @@ namespace Jint.Native.DataView
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-the-dataview-prototype-object
     /// </summary>
-    internal sealed class DataViewPrototype : ObjectInstance
+    internal sealed class DataViewPrototype : Prototype
     {
-        private readonly Realm _realm;
         private readonly DataViewConstructor _constructor;
 
         internal DataViewPrototype(
             Engine engine,
-            Realm realm,
             DataViewConstructor constructor,
-            ObjectPrototype objectPrototype) : base(engine)
+            ObjectPrototype objectPrototype) : base(engine, engine.Realm)
         {
             _prototype = objectPrototype;
-            _realm = realm;
             _constructor = constructor;
         }
 

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

@@ -66,7 +66,7 @@ namespace Jint.Native.Date
             : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
-            PrototypeObject = new DatePrototype(engine, realm, this, objectPrototype);
+            PrototypeObject = new DatePrototype(engine, this, objectPrototype);
             _length = new PropertyDescriptor(7, PropertyFlag.Configurable);
             _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
         }

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

@@ -12,7 +12,7 @@ namespace Jint.Native.Date
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-the-date-prototype-object
     /// </summary>
-    internal sealed class DatePrototype : ObjectInstance
+    internal sealed class DatePrototype : Prototype
     {
         // ES6 section 20.3.1.1 Time Values and Time Range
         private const double MinYear = -1000000.0;
@@ -20,18 +20,15 @@ namespace Jint.Native.Date
         private const double MinMonth = -10000000.0;
         private const double MaxMonth = -MinMonth;
 
-        private readonly Realm _realm;
         private readonly DateConstructor _constructor;
 
         internal DatePrototype(
             Engine engine,
-            Realm realm,
             DateConstructor constructor,
             ObjectPrototype objectPrototype)
-            : base(engine)
+            : base(engine, engine.Realm)
         {
             _prototype = objectPrototype;
-            _realm = realm;
             _constructor = constructor;
         }
 

+ 1 - 1
Jint/Native/DateInstance.cs

@@ -23,7 +23,7 @@ public class JsDate : ObjectInstance
     {
     }
 
-    public JsDate(Engine engine, double dateValue) : base(engine, ObjectClass.Date)
+    public JsDate(Engine engine, double dateValue) : base(engine, ObjectClass.Date, InternalTypes.Object | InternalTypes.PlainObject)
     {
         _prototype = engine.Realm.Intrinsics.Date.PrototypeObject;
         _dateValue = dateValue.TimeClip();

+ 1 - 1
Jint/Native/Global/GlobalObject.cs

@@ -18,7 +18,7 @@ namespace Jint.Native.Global
 
         internal GlobalObject(
             Engine engine,
-            Realm realm) : base(engine, ObjectClass.Object, InternalTypes.Object)
+            Realm realm) : base(engine, ObjectClass.Object, InternalTypes.Object | InternalTypes.PlainObject)
         {
             _realm = realm;
         }

+ 1 - 1
Jint/Native/JsObject.cs

@@ -8,7 +8,7 @@ namespace Jint.Native;
 /// </summary>
 public sealed class JsObject : ObjectInstance
 {
-    public JsObject(Engine engine) : base(engine, type: InternalTypes.Object)
+    public JsObject(Engine engine) : base(engine, type: InternalTypes.Object | InternalTypes.PlainObject)
     {
     }
 }

+ 6 - 0
Jint/Native/Number/NumberInstance.cs

@@ -8,6 +8,12 @@ internal class NumberInstance : ObjectInstance, IPrimitiveInstance
 {
     private static readonly long NegativeZeroBits = BitConverter.DoubleToInt64Bits(-0.0);
 
+    private protected NumberInstance(Engine engine, InternalTypes type)
+        : base(engine, ObjectClass.Number, type)
+    {
+        NumberData = JsNumber.PositiveZero;
+    }
+
     public NumberInstance(Engine engine, JsNumber value)
         : base(engine, ObjectClass.Number)
     {

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

@@ -24,7 +24,7 @@ namespace Jint.Native.Number
             Realm realm,
             NumberConstructor constructor,
             ObjectPrototype objectPrototype)
-            : base(engine, JsNumber.PositiveZero)
+            : base(engine, InternalTypes.Object | InternalTypes.PlainObject)
         {
             _prototype = objectPrototype;
             _realm = realm;

+ 45 - 4
Jint/Native/Object/ObjectInstance.cs

@@ -310,11 +310,21 @@ namespace Jint.Native.Object
 
         public override JsValue Get(JsValue property, JsValue receiver)
         {
-            var desc = GetOwnProperty(property);
-
-            if (desc != PropertyDescriptor.Undefined)
+            if ((_type & InternalTypes.PlainObject) != 0 && ReferenceEquals(this, receiver) && property is JsString jsString)
             {
-                return UnwrapJsValue(desc, receiver);
+                EnsureInitialized();
+                if (_properties?.TryGetValue(jsString.ToString(), out var ownDesc) == true)
+                {
+                    return UnwrapJsValue(ownDesc, receiver);
+                }
+            }
+            else
+            {
+                var desc = GetOwnProperty(property);
+                if (desc != PropertyDescriptor.Undefined)
+                {
+                    return UnwrapJsValue(desc, receiver);
+                }
             }
 
             return Prototype?.Get(property, receiver) ?? Undefined;
@@ -456,6 +466,19 @@ namespace Jint.Native.Object
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool Set(JsValue property, JsValue value)
         {
+            if ((_type & InternalTypes.PlainObject) != 0 && property is JsString jsString)
+            {
+                var key = (Key) jsString.ToString();
+                if (_properties?.TryGetValue(key, out var ownDesc) == true)
+                {
+                    if ((ownDesc._flags & PropertyFlag.Writable) != 0)
+                    {
+                        ownDesc._value = value;
+                        return true;
+                    }
+                }
+            }
+
             return Set(property, value, this);
         }
 
@@ -465,6 +488,24 @@ namespace Jint.Native.Object
         /// https://tc39.es/ecma262/#sec-ordinarysetwithowndescriptor
         /// </summary>
         public override bool Set(JsValue property, JsValue value, JsValue receiver)
+        {
+            if ((_type & InternalTypes.PlainObject) != 0 && ReferenceEquals(this, receiver) && property is JsString jsString)
+            {
+                var key = (Key) jsString.ToString();
+                if (_properties?.TryGetValue(key, out var ownDesc) == true)
+                {
+                    if ((ownDesc._flags & PropertyFlag.Writable) != 0)
+                    {
+                        ownDesc._value = value;
+                        return true;
+                    }
+                }
+            }
+
+            return SetUnlikely(property, value, receiver);
+        }
+
+        private bool SetUnlikely(JsValue property, JsValue value, JsValue receiver)
         {
             var ownDesc = GetOwnProperty(property);
 

+ 1 - 1
Jint/Native/Prototype.cs

@@ -7,7 +7,7 @@ public abstract class Prototype : ObjectInstance
 {
     internal readonly Realm _realm;
 
-    private protected Prototype(Engine engine, Realm realm) : base(engine)
+    private protected Prototype(Engine engine, Realm realm) : base(engine, type: InternalTypes.Object | InternalTypes.PlainObject)
     {
         _realm = realm;
     }

+ 1 - 1
Jint/Native/TypedArray/IntrinsicTypedArrayConstructor.cs

@@ -21,7 +21,7 @@ namespace Jint.Native.TypedArray
             string functionName) : base(engine, realm, new JsString(functionName))
         {
             _prototype = functionPrototype;
-            PrototypeObject = new IntrinsicTypedArrayPrototype(engine, realm, objectPrototype, this);
+            PrototypeObject = new IntrinsicTypedArrayPrototype(engine, objectPrototype, this);
             _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Configurable);
             _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
         }

+ 2 - 5
Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

@@ -15,20 +15,17 @@ namespace Jint.Native.TypedArray
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-the-%typedarrayprototype%-object
     /// </summary>
-    internal sealed class IntrinsicTypedArrayPrototype : ObjectInstance
+    internal sealed class IntrinsicTypedArrayPrototype : Prototype
     {
-        private readonly Realm _realm;
         private readonly IntrinsicTypedArrayConstructor _constructor;
         private ClrFunctionInstance? _originalIteratorFunction;
 
         internal IntrinsicTypedArrayPrototype(
             Engine engine,
-            Realm realm,
             ObjectInstance objectPrototype,
-            IntrinsicTypedArrayConstructor constructor) : base(engine)
+            IntrinsicTypedArrayConstructor constructor) : base(engine, engine.Realm)
         {
             _prototype = objectPrototype;
-            _realm = realm;
             _constructor = constructor;
         }
 

+ 2 - 3
Jint/Native/TypedArray/TypedArrayPrototype.cs

@@ -1,5 +1,4 @@
 using Jint.Collections;
-using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.TypedArray
@@ -7,7 +6,7 @@ namespace Jint.Native.TypedArray
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-typedarray-prototype-objects
     /// </summary>
-    internal sealed class TypedArrayPrototype : ObjectInstance
+    internal sealed class TypedArrayPrototype : Prototype
     {
         private readonly TypedArrayConstructor _constructor;
         private readonly TypedArrayElementType _arrayElementType;
@@ -16,7 +15,7 @@ namespace Jint.Native.TypedArray
             Engine engine,
             IntrinsicTypedArrayPrototype objectPrototype,
             TypedArrayConstructor constructor,
-            TypedArrayElementType type) : base(engine)
+            TypedArrayElementType type) : base(engine, engine.Realm)
         {
             _prototype = objectPrototype;
             _constructor = constructor;

+ 4 - 1
Jint/Runtime/TypeConverter.cs

@@ -54,8 +54,11 @@ namespace Jint.Runtime
         RequiresCloning = 1024,
         Module = 2048,
 
+        // the object doesn't override important GetOwnProperty etc which change behavior
+        PlainObject = 4096,
+
         Primitive = Boolean | String | Number | Integer | BigInt | Symbol,
-        InternalFlags = ObjectEnvironmentRecord | RequiresCloning
+        InternalFlags = ObjectEnvironmentRecord | RequiresCloning | PlainObject | Module
     }
 
     public static class TypeConverter