Commit 37a3a15c authored by Franziska Hinkelmann's avatar Franziska Hinkelmann Committed by Commit Bot

[api] Intercept DefineProperty after Descriptor query

Analog to other interceptors, intercept the DefineProperty
call only after obtaining the property descriptor.

This behavior allows us to mirror calls on a sandboxed object
as it is needed in Node. See for example
https://github.com/nodejs/node/pull/13265

Bug: 
Change-Id: I73b8f8908d13473939b37fb6727858d0bee6bda3
Reviewed-on: https://chromium-review.googlesource.com/725295Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Franziska Hinkelmann <franzih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48683}
parent 8016f309
...@@ -22,7 +22,7 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED { ...@@ -22,7 +22,7 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
kInterceptor = 1 << 0, kInterceptor = 1 << 0,
kPrototypeChain = 1 << 1, kPrototypeChain = 1 << 1,
// Convience combinations of bits. // Convenience combinations of bits.
OWN_SKIP_INTERCEPTOR = 0, OWN_SKIP_INTERCEPTOR = 0,
OWN = kInterceptor, OWN = kInterceptor,
PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain, PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
......
...@@ -6849,17 +6849,6 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, ...@@ -6849,17 +6849,6 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate,
it.Next(); it.Next();
} }
// Handle interceptor
if (it.state() == LookupIterator::INTERCEPTOR) {
if (it.HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result = DefinePropertyWithInterceptorInternal(
&it, it.GetInterceptor(), should_throw, *desc);
if (result.IsNothing() || result.FromJust()) {
return result;
}
}
}
return OrdinaryDefineOwnProperty(&it, desc, should_throw); return OrdinaryDefineOwnProperty(&it, desc, should_throw);
} }
...@@ -6875,6 +6864,20 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it, ...@@ -6875,6 +6864,20 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(LookupIterator* it,
PropertyDescriptor current; PropertyDescriptor current;
MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>()); MAYBE_RETURN(GetOwnPropertyDescriptor(it, &current), Nothing<bool>());
it->Restart();
// Handle interceptor
for (; it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::INTERCEPTOR) {
if (it->HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result = DefinePropertyWithInterceptorInternal(
it, it->GetInterceptor(), should_throw, *desc);
if (result.IsNothing() || result.FromJust()) {
return result;
}
}
}
}
// TODO(jkummerow/verwaest): It would be nice if we didn't have to reset // TODO(jkummerow/verwaest): It would be nice if we didn't have to reset
// the iterator every time. Currently, the reasons why we need it are: // the iterator every time. Currently, the reasons why we need it are:
// - handle interceptors correctly // - handle interceptors correctly
......
...@@ -716,20 +716,21 @@ bool define_was_called_in_order = false; ...@@ -716,20 +716,21 @@ bool define_was_called_in_order = false;
void GetterCallbackOrder(Local<Name> property, void GetterCallbackOrder(Local<Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info) { const v8::PropertyCallbackInfo<v8::Value>& info) {
get_was_called_in_order = true; get_was_called_in_order = true;
CHECK(define_was_called_in_order); CHECK(!define_was_called_in_order);
info.GetReturnValue().Set(property); info.GetReturnValue().Set(property);
} }
void DefinerCallbackOrder(Local<Name> property, void DefinerCallbackOrder(Local<Name> property,
const v8::PropertyDescriptor& desc, const v8::PropertyDescriptor& desc,
const v8::PropertyCallbackInfo<v8::Value>& info) { const v8::PropertyCallbackInfo<v8::Value>& info) {
CHECK(!get_was_called_in_order); // Define called before get. // Get called before DefineProperty because we query the descriptor first.
CHECK(get_was_called_in_order);
define_was_called_in_order = true; define_was_called_in_order = true;
} }
} // namespace } // namespace
// Check that definer callback is called before getter callback. // Check that getter callback is called before definer callback.
THREADED_TEST(DefinerCallbackGetAndDefine) { THREADED_TEST(DefinerCallbackGetAndDefine) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::FunctionTemplate> templ = v8::Local<v8::FunctionTemplate> templ =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment