Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f852ca0de39dee015d82e03b5f7f326910688c56..65fcad34afdf34bdb2ffead2b6a751ba9b660c11 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6542,12 +6542,15 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, |
return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), |
key, desc, should_throw); |
} |
+ if (object->IsJSTypedArray()) { |
+ return JSTypedArray::DefineOwnProperty( |
+ isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw); |
+ } |
// TODO(neis): Special case for JSModuleNamespace? |
// OrdinaryDefineOwnProperty, by virtue of calling |
- // DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2) |
- // and IntegerIndexedExotics (ES6 9.4.5.3), with one exception: |
- // TODO(jkummerow): Setting an indexed accessor on a typed array should throw. |
+ // DefineOwnPropertyIgnoreAttributes, can handle arguments |
+ // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc). |
return OrdinaryDefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, |
desc, should_throw); |
} |
@@ -17434,6 +17437,98 @@ Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, |
return isolate->factory()->NewNumberFromUint(result); |
} |
+namespace { |
+ |
+bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s, |
+ Handle<Object>* index) { |
+ DCHECK(s->IsString() || s->IsSmi()); |
+ |
+ Handle<Object> result; |
+ if (s->IsSmi()) { |
+ result = s; |
+ } else { |
+ result = String::ToNumber(Handle<String>::cast(s)); |
+ if (!result->IsMinusZero()) { |
+ Handle<String> str = Object::ToString(isolate, result).ToHandleChecked(); |
+ // Avoid treating strings like "2E1" and "20" as the same key. |
+ if (!str->SameValue(*s)) return false; |
+ } |
+ } |
+ *index = result; |
+ return true; |
+} |
+ |
+} // anonymous namespace |
+ |
+// ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc |
+// static |
+Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate, |
+ Handle<JSTypedArray> o, |
+ Handle<Object> key, |
+ PropertyDescriptor* desc, |
+ ShouldThrow should_throw) { |
+ // 1. Assert: IsPropertyKey(P) is true. |
+ DCHECK(key->IsName() || key->IsNumber()); |
+ // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot. |
+ // 3. If Type(P) is String, then |
+ if (key->IsString() || key->IsSmi()) { |
+ // 3a. Let numericIndex be ! CanonicalNumericIndexString(P) |
+ // 3b. If numericIndex is not undefined, then |
+ Handle<Object> numeric_index; |
+ if (CanonicalNumericIndexString(isolate, key, &numeric_index)) { |
+ // 3b i. If IsInteger(numericIndex) is false, return false. |
+ // 3b ii. If numericIndex = -0, return false. |
+ // 3b iii. If numericIndex < 0, return false. |
+ // FIXME: the standard allows up to 2^53 elements. |
+ uint32_t index; |
+ if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kInvalidTypedArrayIndex)); |
+ } |
+ // 3b iv. Let length be O.[[ArrayLength]]. |
+ uint32_t length = o->length()->Number(); |
+ // 3b v. If numericIndex ≥ length, return false. |
+ if (index >= length) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kInvalidTypedArrayIndex)); |
+ } |
+ // 3b vi. If IsAccessorDescriptor(Desc) is true, return false. |
+ if (PropertyDescriptor::IsAccessorDescriptor(desc)) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kRedefineDisallowed, key)); |
+ } |
+ // 3b vii. If Desc has a [[Configurable]] field and if |
+ // Desc.[[Configurable]] is true, return false. |
+ // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] |
+ // is false, return false. |
+ // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is |
+ // false, return false. |
+ if ((desc->has_configurable() && desc->configurable()) || |
+ (desc->has_enumerable() && !desc->enumerable()) || |
+ (desc->has_writable() && !desc->writable())) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kRedefineDisallowed, key)); |
+ } |
+ // 3b x. If Desc has a [[Value]] field, then |
+ // 3b x 1. Let value be Desc.[[Value]]. |
+ // 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value). |
+ if (desc->has_value()) { |
+ if (!desc->has_configurable()) desc->set_configurable(false); |
+ if (!desc->has_enumerable()) desc->set_enumerable(true); |
+ if (!desc->has_writable()) desc->set_writable(true); |
+ Handle<Object> value = desc->value(); |
+ RETURN_ON_EXCEPTION_VALUE(isolate, |
+ SetOwnElementIgnoreAttributes( |
+ o, index, value, desc->ToAttributes()), |
+ Nothing<bool>()); |
+ } |
+ // 3b xi. Return true. |
+ return Just(true); |
+ } |
+ } |
+ // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc). |
+ return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw); |
+} |
ExternalArrayType JSTypedArray::type() { |
switch (elements()->map()->instance_type()) { |