Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 2901840af92fbe0b1cd995ba1129a4cb4024befa..fc0cd1eabef2410d3bddcca8bf3a950c9aeffef2 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6128,6 +6128,35 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, |
return *object; |
} |
+Object* JSReceiver::DefinePropertyWithoutInterceptors( |
+ Isolate* isolate, Handle<Object> object, Handle<Object> key, |
+ Handle<Object> attributes) { |
+ // 1. If Type(O) is not Object, throw a TypeError exception. |
+ if (!object->IsJSReceiver()) { |
+ Handle<String> fun_name = isolate->factory()->InternalizeUtf8String( |
+ "Object.definePropertyWithoutInterceptors"); |
+ THROW_NEW_ERROR_RETURN_FAILURE( |
+ isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name)); |
+ } |
+ // 2. Let key be ToPropertyKey(P). |
+ // 3. ReturnIfAbrupt(key). |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, ToPropertyKey(isolate, key)); |
+ // 4. Let desc be ToPropertyDescriptor(Attributes). |
+ // 5. ReturnIfAbrupt(desc). |
+ PropertyDescriptor desc; |
+ if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { |
+ return isolate->heap()->exception(); |
+ } |
+ // 6. Let success be DefinePropertyOrThrow(O,key, desc). |
+ Maybe<bool> success = OrdinaryDefineOwnPropertyWithoutIntercept( |
+ isolate, Handle<JSObject>::cast(object), key, &desc, THROW_ON_ERROR); |
+ |
+ // 7. ReturnIfAbrupt(success). |
+ MAYBE_RETURN(success, isolate->heap()->exception()); |
+ CHECK(success.FromJust()); |
+ // 8. Return O. |
+ return *object; |
+} |
// ES6 19.1.2.3.1 |
// static |
@@ -6236,6 +6265,31 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, |
// static |
+Maybe<bool> JSReceiver::DefineOwnPropertyWithoutIntercept( |
+ Isolate* isolate, Handle<JSReceiver> object, Handle<Object> key, |
+ PropertyDescriptor* desc, ShouldThrow should_throw) { |
+ if (object->IsJSArray()) { |
+ return JSArray::DefineOwnPropertyWithoutIntercept( |
+ isolate, Handle<JSArray>::cast(object), key, desc, should_throw); |
+ } |
+ if (object->IsJSProxy()) { |
+ return JSProxy::DefineOwnPropertyWithoutIntercept( |
+ isolate, Handle<JSProxy>::cast(object), key, desc, should_throw); |
+ } |
+ if (object->IsJSTypedArray()) { |
+ return JSTypedArray::DefineOwnPropertyWithoutIntercept( |
+ isolate, Handle<JSTypedArray>::cast(object), key, desc, should_throw); |
+ } |
+ // TODO(neis): Special case for JSModuleNamespace? |
+ |
+ // OrdinaryDefineOwnProperty, by virtue of calling |
+ // DefineOwnPropertyIgnoreAttributes, can handle arguments |
+ // (ES#sec-arguments-exotic-objects-defineownproperty-p-desc). |
+ return OrdinaryDefineOwnPropertyWithoutIntercept( |
+ isolate, Handle<JSObject>::cast(object), key, desc, should_throw); |
+} |
+ |
+// static |
Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, |
Handle<JSObject> object, |
Handle<Object> key, |
@@ -6271,6 +6325,28 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, |
return OrdinaryDefineOwnProperty(&it, desc, should_throw); |
} |
+// static |
+Maybe<bool> JSReceiver::OrdinaryDefineOwnPropertyWithoutIntercept( |
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> key, |
+ PropertyDescriptor* desc, ShouldThrow should_throw) { |
+ bool success = false; |
+ DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey... |
+ LookupIterator it = LookupIterator::PropertyOrElement( |
+ isolate, object, key, &success, LookupIterator::OWN_SKIP_INTERCEPTOR); |
+ DCHECK(success); // ...so creating a LookupIterator can't fail. |
+ |
+ // Deal with access checks first. |
+ if (it.state() == LookupIterator::ACCESS_CHECK) { |
+ if (!it.HasAccess()) { |
+ isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
+ return Just(true); |
+ } |
+ it.Next(); |
+ } |
+ |
+ return OrdinaryDefineOwnProperty(&it, desc, should_throw); |
+} |
// ES6 9.1.6.1 |
// static |
@@ -6700,6 +6776,69 @@ Maybe<bool> JSArray::DefineOwnProperty(Isolate* isolate, Handle<JSArray> o, |
return OrdinaryDefineOwnProperty(isolate, o, name, desc, should_throw); |
} |
+// static |
+Maybe<bool> JSArray::DefineOwnPropertyWithoutIntercept( |
+ Isolate* isolate, Handle<JSArray> o, Handle<Object> name, |
+ PropertyDescriptor* desc, ShouldThrow should_throw) { |
+ // 1. Assert: IsPropertyKey(P) is true. ("P" is |name|.) |
+ // 2. If P is "length", then: |
+ // TODO(jkummerow): Check if we need slow string comparison. |
+ if (*name == isolate->heap()->length_string()) { |
+ // 2a. Return ArraySetLength(A, Desc). |
+ return ArraySetLength(isolate, o, desc, should_throw); |
+ } |
+ // 3. Else if P is an array index, then: |
+ uint32_t index = 0; |
+ if (PropertyKeyToArrayIndex(name, &index)) { |
+ // 3a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). |
+ PropertyDescriptor old_len_desc; |
+ Maybe<bool> success = GetOwnPropertyDescriptor( |
+ isolate, o, isolate->factory()->length_string(), &old_len_desc); |
+ // 3b. (Assert) |
+ DCHECK(success.FromJust()); |
+ USE(success); |
+ // 3c. Let oldLen be oldLenDesc.[[Value]]. |
+ uint32_t old_len = 0; |
+ CHECK(old_len_desc.value()->ToArrayLength(&old_len)); |
+ // 3d. Let index be ToUint32(P). |
+ // (Already done above.) |
+ // 3e. (Assert) |
+ // 3f. If index >= oldLen and oldLenDesc.[[Writable]] is false, |
+ // return false. |
+ if (index >= old_len && old_len_desc.has_writable() && |
+ !old_len_desc.writable()) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kDefineDisallowed, name)); |
+ } |
+ // 3g. Let succeeded be OrdinaryDefineOwnPropertyWithoutIntercept(A, P, |
+ // Desc). |
+ Maybe<bool> succeeded = OrdinaryDefineOwnPropertyWithoutIntercept( |
+ isolate, o, name, desc, should_throw); |
+ // 3h. Assert: succeeded is not an abrupt completion. |
+ // In our case, if should_throw == THROW_ON_ERROR, it can be! |
+ // 3i. If succeeded is false, return false. |
+ if (succeeded.IsNothing() || !succeeded.FromJust()) return succeeded; |
+ // 3j. If index >= oldLen, then: |
+ if (index >= old_len) { |
+ // 3j i. Set oldLenDesc.[[Value]] to index + 1. |
+ old_len_desc.set_value(isolate->factory()->NewNumberFromUint(index + 1)); |
+ // 3j ii. Let succeeded be |
+ // OrdinaryDefineOwnProperty(A, "length", oldLenDesc). |
+ succeeded = OrdinaryDefineOwnPropertyWithoutIntercept( |
+ isolate, o, isolate->factory()->length_string(), &old_len_desc, |
+ should_throw); |
+ // 3j iii. Assert: succeeded is true. |
+ DCHECK(succeeded.FromJust()); |
+ USE(succeeded); |
+ } |
+ // 3k. Return true. |
+ return Just(true); |
+ } |
+ |
+ // 4. Return OrdinaryDefineOwnProperty(A, P, Desc). |
+ return OrdinaryDefineOwnPropertyWithoutIntercept(isolate, o, name, desc, |
+ should_throw); |
+} |
// Part of ES6 9.4.2.4 ArraySetLength. |
// static |
@@ -6939,6 +7078,116 @@ Maybe<bool> JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy, |
// static |
+Maybe<bool> JSProxy::DefineOwnPropertyWithoutIntercept( |
+ Isolate* isolate, Handle<JSProxy> proxy, Handle<Object> key, |
+ PropertyDescriptor* desc, ShouldThrow should_throw) { |
+ STACK_CHECK(isolate, Nothing<bool>()); |
+ if (key->IsSymbol() && Handle<Symbol>::cast(key)->IsPrivate()) { |
+ return SetPrivateProperty(isolate, proxy, Handle<Symbol>::cast(key), desc, |
+ should_throw); |
+ } |
+ Handle<String> trap_name = isolate->factory()->defineProperty_string(); |
+ // 1. Assert: IsPropertyKey(P) is true. |
+ DCHECK(key->IsName() || key->IsNumber()); |
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. |
+ Handle<Object> handler(proxy->handler(), isolate); |
+ // 3. If handler is null, throw a TypeError exception. |
+ // 4. Assert: Type(handler) is Object. |
+ if (proxy->IsRevoked()) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyRevoked, trap_name)); |
+ return Nothing<bool>(); |
+ } |
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. |
+ Handle<JSReceiver> target(proxy->target(), isolate); |
+ // 6. Let trap be ? GetMethod(handler, "defineProperty"). |
+ Handle<Object> trap; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, trap, |
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name), |
+ Nothing<bool>()); |
+ // 7. If trap is undefined, then: |
+ if (trap->IsUndefined(isolate)) { |
+ // 7a. Return target.[[DefineOwnProperty]](P, Desc). |
+ return JSReceiver::DefineOwnPropertyWithoutIntercept(isolate, target, key, |
+ desc, should_throw); |
+ } |
+ // 8. Let descObj be FromPropertyDescriptor(Desc). |
+ Handle<Object> desc_obj = desc->ToObject(isolate); |
+ // 9. Let booleanTrapResult be |
+ // ToBoolean(? Call(trap, handler, «target, P, descObj»)). |
+ Handle<Name> property_name = |
+ key->IsName() |
+ ? Handle<Name>::cast(key) |
+ : Handle<Name>::cast(isolate->factory()->NumberToString(key)); |
+ // Do not leak private property names. |
+ DCHECK(!property_name->IsPrivate()); |
+ Handle<Object> trap_result_obj; |
+ Handle<Object> args[] = {target, property_name, desc_obj}; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, trap_result_obj, |
+ Execution::Call(isolate, trap, handler, arraysize(args), args), |
+ Nothing<bool>()); |
+ // 10. If booleanTrapResult is false, return false. |
+ if (!trap_result_obj->BooleanValue()) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kProxyTrapReturnedFalsishFor, |
+ trap_name, property_name)); |
+ } |
+ // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). |
+ PropertyDescriptor target_desc; |
+ Maybe<bool> target_found = |
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); |
+ MAYBE_RETURN(target_found, Nothing<bool>()); |
+ // 12. Let extensibleTarget be ? IsExtensible(target). |
+ Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); |
+ MAYBE_RETURN(maybe_extensible, Nothing<bool>()); |
+ bool extensible_target = maybe_extensible.FromJust(); |
+ // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] |
+ // is false, then: |
+ // 13a. Let settingConfigFalse be true. |
+ // 14. Else let settingConfigFalse be false. |
+ bool setting_config_false = desc->has_configurable() && !desc->configurable(); |
+ // 15. If targetDesc is undefined, then |
+ if (!target_found.FromJust()) { |
+ // 15a. If extensibleTarget is false, throw a TypeError exception. |
+ if (!extensible_target) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyDefinePropertyNonExtensible, property_name)); |
+ return Nothing<bool>(); |
+ } |
+ // 15b. If settingConfigFalse is true, throw a TypeError exception. |
+ if (setting_config_false) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); |
+ return Nothing<bool>(); |
+ } |
+ } else { |
+ // 16. Else targetDesc is not undefined, |
+ // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, |
+ // targetDesc) is false, throw a TypeError exception. |
+ Maybe<bool> valid = |
+ IsCompatiblePropertyDescriptor(isolate, extensible_target, desc, |
+ &target_desc, property_name, DONT_THROW); |
+ MAYBE_RETURN(valid, Nothing<bool>()); |
+ if (!valid.FromJust()) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyDefinePropertyIncompatible, property_name)); |
+ return Nothing<bool>(); |
+ } |
+ // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is |
+ // true, throw a TypeError exception. |
+ if (setting_config_false && target_desc.configurable()) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyDefinePropertyNonConfigurable, property_name)); |
+ return Nothing<bool>(); |
+ } |
+ } |
+ // 17. Return true. |
+ return Just(true); |
+} |
+ |
+// static |
Maybe<bool> JSProxy::SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, |
Handle<Symbol> private_name, |
PropertyDescriptor* desc, |
@@ -17227,6 +17476,74 @@ Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate, |
return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw); |
} |
+// static |
+Maybe<bool> JSTypedArray::DefineOwnPropertyWithoutIntercept( |
+ 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 OrdinaryDefineOwnPropertyWithoutIntercept(isolate, o, key, desc, |
+ should_throw); |
+} |
+ |
ExternalArrayType JSTypedArray::type() { |
switch (elements()->map()->instance_type()) { |
#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \ |