Просмотр исходного кода

fixes #5549 implement defineOwnProperty for typedarray object

Duong Nguyen-Huu 7 лет назад
Родитель
Сommit
eb1a06347b

+ 58 - 0
lib/Runtime/Language/JavascriptOperators.cpp

@@ -9043,6 +9043,64 @@ SetElementIHelper_INDEX_TYPE_IS_NUMBER:
         return DefineOwnPropertyDescriptor(arr, propId, descriptor, throwOnError, scriptContext);
     }
 
+    // ES2017: 9.4.5.3 https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
+    BOOL JavascriptOperators::DefineOwnPropertyForTypedArray(TypedArrayBase* typedArray, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext)
+    {
+        // 1. Assert: IsPropertyKey(P) is true.
+        // 2. Assert: Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
+
+        const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propId);
+        // 3. If Type(P) is String, then
+        // a. Let numericIndex be ! CanonicalNumericIndexString(P).
+        // b. If numericIndex is not undefined, then
+        // i. if IsInteger(numbericIndex), return false
+        // ii. if numbericIndex = -0, return false
+        // iii. If numericIndex < 0, return false.
+
+        if (propertyRecord->IsNumeric()) {
+            uint32 uint32Index = propertyRecord->GetNumericValue();
+            // iv. Let length be O.[[ArrayLength]].
+            uint32 length = typedArray->GetLength();
+            // v. If numericIndex >= length, return false.
+            if (uint32Index >= length)
+            {
+                return Reject(throwOnError, scriptContext, JSERR_InvalidTypedArrayIndex, propId);
+            }
+            // vi. If IsAccessorDescriptor(Desc) is true, return false.
+            // vii. If Desc has a[[Configurable]] field and if Desc.[[Configurable]] is true, return false.
+            // viii. If Desc has an[[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
+            // ix. If Desc has a[[Writable]] field and if Desc.[[Writable]] is false, return false.
+            if (descriptor.IsAccessorDescriptor()
+                || (descriptor.ConfigurableSpecified() && descriptor.IsConfigurable())
+                || (descriptor.EnumerableSpecified() && !descriptor.IsEnumerable())
+                || (descriptor.WritableSpecified() && !descriptor.IsWritable()))
+            {
+                return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
+            }            // x. If Desc has a[[Value]] field, then
+            // 1. Let value be Desc.[[Value]].
+            // 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
+            if (descriptor.ValueSpecified())
+            {
+                Js::Var value = descriptor.GetValue();
+                return typedArray->DirectSetItem(uint32Index, value);
+            }
+            // xi. Return true.
+            return true;
+        }
+        if (!propertyRecord->IsSymbol())
+        {
+            PropertyString *propertyString = scriptContext->GetPropertyString(propId);
+            double result;
+            if (JavascriptConversion::CanonicalNumericIndexString(propertyString, &result, scriptContext))
+            {
+                return Reject(throwOnError, scriptContext, JSERR_InvalidTypedArrayIndex, propId);
+            }
+        }
+        // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc). 
+        return DefineOwnPropertyDescriptor(typedArray, propId, descriptor, throwOnError, scriptContext);
+    }
+
+
     BOOL JavascriptOperators::SetPropertyDescriptor(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor)
     {
         if (descriptor.ValueSpecified())

+ 2 - 0
lib/Runtime/Language/JavascriptOperators.h

@@ -592,6 +592,8 @@ namespace Js
         static BOOL DefineOwnPropertyDescriptor(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext);
         static BOOL DefineOwnPropertyForArray(JavascriptArray* arr, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext);
 
+        static BOOL DefineOwnPropertyForTypedArray(TypedArrayBase * typedArray, PropertyId propId, const PropertyDescriptor & descriptor, bool throwOnError, ScriptContext * scriptContext);
+
         static BOOL IsCompatiblePropertyDescriptor(const PropertyDescriptor& descriptor, PropertyDescriptor* currentDescriptor, bool isExtensible, bool throwOnError, ScriptContext* scriptContext);
 
         template <bool needToSetProperty>

+ 8 - 0
lib/Runtime/Library/JavascriptObject.cpp

@@ -2128,11 +2128,19 @@ BOOL JavascriptObject::DefineOwnPropertyHelper(RecyclableObject* obj, PropertyId
     // so there is no benefit in using ES5 DefineOwnPropertyDescriptor for it, use old implementation.
     if (TypeIds_HostDispatch != obj->GetTypeId())
     {
+        // for Array Exotic Objects
         if (DynamicObject::IsAnyArray(obj))
         {
             returnValue = JavascriptOperators::DefineOwnPropertyForArray(
                 JavascriptArray::FromAnyArray(obj), propId, descriptor, throwOnError, scriptContext);
         }
+        // for Integer Indexed Exotic Objects
+        else if (DynamicObject::IsAnyTypedArray(obj))
+        {
+            returnValue = JavascriptOperators::DefineOwnPropertyForTypedArray(
+                TypedArrayBase::FromVar(obj), propId, descriptor, throwOnError, scriptContext);
+        }
+        // TODO: implement DefineOwnProperty for other object built-in exotic types.
         else
         {
             returnValue = JavascriptOperators::DefineOwnPropertyDescriptor(obj, propId, descriptor, throwOnError, scriptContext);

+ 6 - 0
lib/Runtime/Types/DynamicObject.cpp

@@ -209,6 +209,12 @@ namespace Js
         return HasObjectArray() && GetObjectArrayOrFlagsAsArray()->GetLength() > 0;
     }
 
+    // Check if a Var is either a JavascriptArray* or ES5Array*.
+    bool DynamicObject::IsAnyTypedArray(const Var aValue)
+    {
+        return TypedArrayBase::Is(JavascriptOperators::GetTypeId(aValue));
+    }
+
     // Check if a typeId is of any array type (JavascriptArray or ES5Array).
     bool DynamicObject::IsAnyArrayTypeId(TypeId typeId)
     {

+ 3 - 0
lib/Runtime/Types/DynamicObject.h

@@ -187,6 +187,9 @@ namespace Js
         // Check if a Var is either a JavascriptArray* or ES5Array*.
         static bool IsAnyArray(const Var aValue);
 
+        // Check if a Var is a typedarray.
+        static bool IsAnyTypedArray(const Var aValue);
+
         bool UsesObjectArrayOrFlagsAsFlags() const
         {
             return !!(arrayFlags & DynamicObjectFlags::ObjectArrayFlagsTag);

+ 151 - 0
test/typedarray/reflect_defineProperty.js

@@ -0,0 +1,151 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+    this.WScript.LoadScriptFile("util.js");
+}
+
+var tests = [
+    {
+        name: "Reflect define Property for typedarray can not set writable to false",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "0", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: false,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not set configuration to true",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "0", {
+                value: 42,
+                configurable: true,
+                enumerable: true,
+                writable: false,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not set enumerable to false",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "0", {
+                value: 42,
+                configurable: false,
+                enumerable: false,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not use index >= length",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "2", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not use neg zero index",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "-0", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not use negative index",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "-10", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not use double index",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "1.1", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray can not use accessor descriptor",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "0", {
+                get: function() {}
+            }); 
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, false, "expect false");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray support use symbol index",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, Symbol('foo'), {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            });
+            assert.areEqual(sample[0], 0, "the value should be 0");
+            assert.areEqual(result, true, "expect true");                    
+        }
+    },
+    {
+        name: "Reflect define Property for typedarray work with valid descriptor and index",
+        body: function () {
+            const sample = new Float64Array(2)
+            var result = Reflect.defineProperty(sample, "0", {
+                value: 42,
+                configurable: false,
+                enumerable: true,
+                writable: true,
+            }); 
+            assert.areEqual(sample[0], 42, "the value should be 42");
+            assert.areEqual(result, true, "expect true");                    
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: false /*so no need to provide baseline*/ });

+ 6 - 0
test/typedarray/rlexe.xml

@@ -112,6 +112,12 @@
       <compile-flags>-args summary -endargs</compile-flags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>reflect_defineProperty.js</files>
+      <tags>typedarray</tags>
+    </default>
+  </test>
   <test>
     <default>
       <files>objectproperty.js</files>