Skip to content

Commit eb1a063

Browse files
committed
fixes #5549 implement defineOwnProperty for typedarray object
1 parent a330001 commit eb1a063

File tree

7 files changed

+234
-0
lines changed

7 files changed

+234
-0
lines changed

lib/Runtime/Language/JavascriptOperators.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9043,6 +9043,64 @@ using namespace Js;
90439043
return DefineOwnPropertyDescriptor(arr, propId, descriptor, throwOnError, scriptContext);
90449044
}
90459045

9046+
// ES2017: 9.4.5.3 https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
9047+
BOOL JavascriptOperators::DefineOwnPropertyForTypedArray(TypedArrayBase* typedArray, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext)
9048+
{
9049+
// 1. Assert: IsPropertyKey(P) is true.
9050+
// 2. Assert: Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
9051+
9052+
const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propId);
9053+
// 3. If Type(P) is String, then
9054+
// a. Let numericIndex be ! CanonicalNumericIndexString(P).
9055+
// b. If numericIndex is not undefined, then
9056+
// i. if IsInteger(numbericIndex), return false
9057+
// ii. if numbericIndex = -0, return false
9058+
// iii. If numericIndex < 0, return false.
9059+
9060+
if (propertyRecord->IsNumeric()) {
9061+
uint32 uint32Index = propertyRecord->GetNumericValue();
9062+
// iv. Let length be O.[[ArrayLength]].
9063+
uint32 length = typedArray->GetLength();
9064+
// v. If numericIndex >= length, return false.
9065+
if (uint32Index >= length)
9066+
{
9067+
return Reject(throwOnError, scriptContext, JSERR_InvalidTypedArrayIndex, propId);
9068+
}
9069+
// vi. If IsAccessorDescriptor(Desc) is true, return false.
9070+
// vii. If Desc has a[[Configurable]] field and if Desc.[[Configurable]] is true, return false.
9071+
// viii. If Desc has an[[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
9072+
// ix. If Desc has a[[Writable]] field and if Desc.[[Writable]] is false, return false.
9073+
if (descriptor.IsAccessorDescriptor()
9074+
|| (descriptor.ConfigurableSpecified() && descriptor.IsConfigurable())
9075+
|| (descriptor.EnumerableSpecified() && !descriptor.IsEnumerable())
9076+
|| (descriptor.WritableSpecified() && !descriptor.IsWritable()))
9077+
{
9078+
return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
9079+
} // x. If Desc has a[[Value]] field, then
9080+
// 1. Let value be Desc.[[Value]].
9081+
// 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
9082+
if (descriptor.ValueSpecified())
9083+
{
9084+
Js::Var value = descriptor.GetValue();
9085+
return typedArray->DirectSetItem(uint32Index, value);
9086+
}
9087+
// xi. Return true.
9088+
return true;
9089+
}
9090+
if (!propertyRecord->IsSymbol())
9091+
{
9092+
PropertyString *propertyString = scriptContext->GetPropertyString(propId);
9093+
double result;
9094+
if (JavascriptConversion::CanonicalNumericIndexString(propertyString, &result, scriptContext))
9095+
{
9096+
return Reject(throwOnError, scriptContext, JSERR_InvalidTypedArrayIndex, propId);
9097+
}
9098+
}
9099+
// 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
9100+
return DefineOwnPropertyDescriptor(typedArray, propId, descriptor, throwOnError, scriptContext);
9101+
}
9102+
9103+
90469104
BOOL JavascriptOperators::SetPropertyDescriptor(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor)
90479105
{
90489106
if (descriptor.ValueSpecified())

lib/Runtime/Language/JavascriptOperators.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,8 @@ namespace Js
592592
static BOOL DefineOwnPropertyDescriptor(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext);
593593
static BOOL DefineOwnPropertyForArray(JavascriptArray* arr, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext);
594594

595+
static BOOL DefineOwnPropertyForTypedArray(TypedArrayBase * typedArray, PropertyId propId, const PropertyDescriptor & descriptor, bool throwOnError, ScriptContext * scriptContext);
596+
595597
static BOOL IsCompatiblePropertyDescriptor(const PropertyDescriptor& descriptor, PropertyDescriptor* currentDescriptor, bool isExtensible, bool throwOnError, ScriptContext* scriptContext);
596598

597599
template <bool needToSetProperty>

lib/Runtime/Library/JavascriptObject.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,11 +2128,19 @@ BOOL JavascriptObject::DefineOwnPropertyHelper(RecyclableObject* obj, PropertyId
21282128
// so there is no benefit in using ES5 DefineOwnPropertyDescriptor for it, use old implementation.
21292129
if (TypeIds_HostDispatch != obj->GetTypeId())
21302130
{
2131+
// for Array Exotic Objects
21312132
if (DynamicObject::IsAnyArray(obj))
21322133
{
21332134
returnValue = JavascriptOperators::DefineOwnPropertyForArray(
21342135
JavascriptArray::FromAnyArray(obj), propId, descriptor, throwOnError, scriptContext);
21352136
}
2137+
// for Integer Indexed Exotic Objects
2138+
else if (DynamicObject::IsAnyTypedArray(obj))
2139+
{
2140+
returnValue = JavascriptOperators::DefineOwnPropertyForTypedArray(
2141+
TypedArrayBase::FromVar(obj), propId, descriptor, throwOnError, scriptContext);
2142+
}
2143+
// TODO: implement DefineOwnProperty for other object built-in exotic types.
21362144
else
21372145
{
21382146
returnValue = JavascriptOperators::DefineOwnPropertyDescriptor(obj, propId, descriptor, throwOnError, scriptContext);

lib/Runtime/Types/DynamicObject.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ namespace Js
209209
return HasObjectArray() && GetObjectArrayOrFlagsAsArray()->GetLength() > 0;
210210
}
211211

212+
// Check if a Var is either a JavascriptArray* or ES5Array*.
213+
bool DynamicObject::IsAnyTypedArray(const Var aValue)
214+
{
215+
return TypedArrayBase::Is(JavascriptOperators::GetTypeId(aValue));
216+
}
217+
212218
// Check if a typeId is of any array type (JavascriptArray or ES5Array).
213219
bool DynamicObject::IsAnyArrayTypeId(TypeId typeId)
214220
{

lib/Runtime/Types/DynamicObject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ namespace Js
187187
// Check if a Var is either a JavascriptArray* or ES5Array*.
188188
static bool IsAnyArray(const Var aValue);
189189

190+
// Check if a Var is a typedarray.
191+
static bool IsAnyTypedArray(const Var aValue);
192+
190193
bool UsesObjectArrayOrFlagsAsFlags() const
191194
{
192195
return !!(arrayFlags & DynamicObjectFlags::ObjectArrayFlagsTag);
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
7+
this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
8+
this.WScript.LoadScriptFile("util.js");
9+
}
10+
11+
var tests = [
12+
{
13+
name: "Reflect define Property for typedarray can not set writable to false",
14+
body: function () {
15+
const sample = new Float64Array(2)
16+
var result = Reflect.defineProperty(sample, "0", {
17+
value: 42,
18+
configurable: false,
19+
enumerable: true,
20+
writable: false,
21+
});
22+
assert.areEqual(sample[0], 0, "the value should be 0");
23+
assert.areEqual(result, false, "expect false");
24+
}
25+
},
26+
{
27+
name: "Reflect define Property for typedarray can not set configuration to true",
28+
body: function () {
29+
const sample = new Float64Array(2)
30+
var result = Reflect.defineProperty(sample, "0", {
31+
value: 42,
32+
configurable: true,
33+
enumerable: true,
34+
writable: false,
35+
});
36+
assert.areEqual(sample[0], 0, "the value should be 0");
37+
assert.areEqual(result, false, "expect false");
38+
}
39+
},
40+
{
41+
name: "Reflect define Property for typedarray can not set enumerable to false",
42+
body: function () {
43+
const sample = new Float64Array(2)
44+
var result = Reflect.defineProperty(sample, "0", {
45+
value: 42,
46+
configurable: false,
47+
enumerable: false,
48+
writable: true,
49+
});
50+
assert.areEqual(sample[0], 0, "the value should be 0");
51+
assert.areEqual(result, false, "expect false");
52+
}
53+
},
54+
{
55+
name: "Reflect define Property for typedarray can not use index >= length",
56+
body: function () {
57+
const sample = new Float64Array(2)
58+
var result = Reflect.defineProperty(sample, "2", {
59+
value: 42,
60+
configurable: false,
61+
enumerable: true,
62+
writable: true,
63+
});
64+
assert.areEqual(sample[0], 0, "the value should be 0");
65+
assert.areEqual(result, false, "expect false");
66+
}
67+
},
68+
{
69+
name: "Reflect define Property for typedarray can not use neg zero index",
70+
body: function () {
71+
const sample = new Float64Array(2)
72+
var result = Reflect.defineProperty(sample, "-0", {
73+
value: 42,
74+
configurable: false,
75+
enumerable: true,
76+
writable: true,
77+
});
78+
assert.areEqual(sample[0], 0, "the value should be 0");
79+
assert.areEqual(result, false, "expect false");
80+
}
81+
},
82+
{
83+
name: "Reflect define Property for typedarray can not use negative index",
84+
body: function () {
85+
const sample = new Float64Array(2)
86+
var result = Reflect.defineProperty(sample, "-10", {
87+
value: 42,
88+
configurable: false,
89+
enumerable: true,
90+
writable: true,
91+
});
92+
assert.areEqual(sample[0], 0, "the value should be 0");
93+
assert.areEqual(result, false, "expect false");
94+
}
95+
},
96+
{
97+
name: "Reflect define Property for typedarray can not use double index",
98+
body: function () {
99+
const sample = new Float64Array(2)
100+
var result = Reflect.defineProperty(sample, "1.1", {
101+
value: 42,
102+
configurable: false,
103+
enumerable: true,
104+
writable: true,
105+
});
106+
assert.areEqual(sample[0], 0, "the value should be 0");
107+
assert.areEqual(result, false, "expect false");
108+
}
109+
},
110+
{
111+
name: "Reflect define Property for typedarray can not use accessor descriptor",
112+
body: function () {
113+
const sample = new Float64Array(2)
114+
var result = Reflect.defineProperty(sample, "0", {
115+
get: function() {}
116+
});
117+
assert.areEqual(sample[0], 0, "the value should be 0");
118+
assert.areEqual(result, false, "expect false");
119+
}
120+
},
121+
{
122+
name: "Reflect define Property for typedarray support use symbol index",
123+
body: function () {
124+
const sample = new Float64Array(2)
125+
var result = Reflect.defineProperty(sample, Symbol('foo'), {
126+
value: 42,
127+
configurable: false,
128+
enumerable: true,
129+
writable: true,
130+
});
131+
assert.areEqual(sample[0], 0, "the value should be 0");
132+
assert.areEqual(result, true, "expect true");
133+
}
134+
},
135+
{
136+
name: "Reflect define Property for typedarray work with valid descriptor and index",
137+
body: function () {
138+
const sample = new Float64Array(2)
139+
var result = Reflect.defineProperty(sample, "0", {
140+
value: 42,
141+
configurable: false,
142+
enumerable: true,
143+
writable: true,
144+
});
145+
assert.areEqual(sample[0], 42, "the value should be 42");
146+
assert.areEqual(result, true, "expect true");
147+
}
148+
},
149+
];
150+
151+
testRunner.runTests(tests, { verbose: false /*so no need to provide baseline*/ });

test/typedarray/rlexe.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@
112112
<compile-flags>-args summary -endargs</compile-flags>
113113
</default>
114114
</test>
115+
<test>
116+
<default>
117+
<files>reflect_defineProperty.js</files>
118+
<tags>typedarray</tags>
119+
</default>
120+
</test>
115121
<test>
116122
<default>
117123
<files>objectproperty.js</files>

0 commit comments

Comments
 (0)