Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(652)

Unified Diff: src/objects.cc

Issue 2807333003: [api] Add DefineProperty() method that skips interceptors.
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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) \

Powered by Google App Engine
This is Rietveld 408576698