Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f6ae8470da9043dbae68364537bba01a0fd7990f..a41cf79f44de885d41ef1ec310935922aab4b2b4 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1677,6 +1677,76 @@ Maybe<bool> SetPropertyWithInterceptorInternal( |
return Just(result); |
} |
+Maybe<bool> DefinePropertyWithInterceptorInternal( |
+ LookupIterator* it, Handle<InterceptorInfo> interceptor, |
+ Object::ShouldThrow should_throw, PropertyDescriptor& desc) { |
+ Isolate* isolate = it->isolate(); |
+ // Make sure that the top context does not change when doing callbacks or |
+ // interceptor calls. |
+ AssertNoContextChange ncc(isolate); |
+ |
+ if (interceptor->definer()->IsUndefined(isolate)) return Just(false); |
+ |
+ Handle<JSObject> holder = it->GetHolder<JSObject>(); |
+ bool result; |
+ Handle<Object> receiver = it->GetReceiver(); |
+ if (!receiver->IsJSReceiver()) { |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver, |
jochen (gone - plz use gerrit)
2016/08/26 18:18:46
btw, is it a problem for your usecase that our int
Franzi
2016/09/01 06:38:18
So far, nobody has complained about it :)
|
+ Object::ConvertReceiver(isolate, receiver), |
+ Nothing<bool>()); |
+ } |
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, |
+ *holder, should_throw); |
+ |
+ std::unique_ptr<v8::PropertyDescriptor> propDescriptor( |
jochen (gone - plz use gerrit)
2016/08/26 18:18:46
nit. property_descriptor
Franzi
2016/09/01 06:38:18
Done.
|
+ new v8::PropertyDescriptor()); |
+ if (PropertyDescriptor::IsAccessorDescriptor(&desc)) { |
+ Handle<JSReceiver> getter = Handle<JSReceiver>(); |
+ if (desc.has_get() && desc.get()->IsCallable()) { |
+ getter = Handle<JSReceiver>::cast(desc.get()); |
+ } |
+ Handle<JSReceiver> setter = Handle<JSReceiver>(); |
+ if (desc.has_set() && desc.set()->IsCallable()) { |
+ setter = Handle<JSReceiver>::cast(desc.set()); |
+ } |
+ propDescriptor.reset(new v8::PropertyDescriptor( |
+ v8::Utils::CallableToLocal(getter), desc.has_get(), |
+ v8::Utils::CallableToLocal(setter), desc.has_set())); |
+ } else if (PropertyDescriptor::IsDataDescriptor(&desc)) { |
+ propDescriptor.reset(new v8::PropertyDescriptor( |
+ v8::Utils::ToLocal(desc.value()), desc.has_value(), desc.writable(), |
+ desc.has_writable())); |
+ } |
+ if (desc.has_enumerable()) { |
+ propDescriptor->set_enumerable(desc.enumerable()); |
+ } |
+ if (desc.has_configurable()) { |
+ propDescriptor->set_configurable(desc.configurable()); |
+ } |
+ |
+ if (it->IsElement()) { |
+ uint32_t index = it->index(); |
+ v8::IndexedPropertyDefinerCallback definer = |
+ v8::ToCData<v8::IndexedPropertyDefinerCallback>(interceptor->definer()); |
+ result = !args.Call(definer, index, *propDescriptor).is_null(); |
+ } else { |
+ Handle<Name> name = it->name(); |
+ DCHECK(!name->IsPrivate()); |
+ |
+ if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { |
+ return Just(false); |
+ } |
+ |
+ v8::GenericNamedPropertyDefinerCallback definer = |
+ v8::ToCData<v8::GenericNamedPropertyDefinerCallback>( |
+ interceptor->definer()); |
+ result = !args.Call(definer, name, *propDescriptor).is_null(); |
+ } |
+ |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing<bool>()); |
+ return Just(result); |
+} |
+ |
} // namespace |
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( |
@@ -4525,6 +4595,14 @@ Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, |
should_throw, value); |
} |
+Maybe<bool> JSObject::DefinePropertyWithInterceptor(LookupIterator* it, |
+ ShouldThrow should_throw, |
+ PropertyDescriptor& desc) { |
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
+ return DefinePropertyWithInterceptorInternal(it, it->GetInterceptor(), |
jochen (gone - plz use gerrit)
2016/08/26 18:18:46
just inline this method, as it's not used from any
Franzi
2016/09/01 06:38:18
Done.
|
+ should_throw, desc); |
+} |
+ |
MaybeHandle<Object> Object::SetProperty(Handle<Object> object, |
Handle<Name> name, Handle<Object> value, |
LanguageMode language_mode, |
@@ -6542,6 +6620,35 @@ Maybe<bool> JSReceiver::OrdinaryDefineOwnProperty(Isolate* isolate, |
it.Next(); |
} |
+ // Handle interceptor |
+ if (it.state() == LookupIterator::INTERCEPTOR) { |
+ Handle<Map> store_target_map; |
+ if (it.GetReceiver()->IsJSObject()) { |
+ store_target_map = handle(it.GetStoreTarget()->map(), it.isolate()); |
+ } |
+ if (it.HolderIsReceiverOrHiddenPrototype()) { |
+ Maybe<bool> result = |
+ JSObject::DefinePropertyWithInterceptor(&it, should_throw, *desc); |
+ if (result.IsNothing() || result.FromJust()) { |
+ return result; |
+ } |
+ // Interceptor modified the store target but failed to set the |
+ // property. |
+ if (!store_target_map.is_null() && |
+ *store_target_map != it.GetStoreTarget()->map()) { |
+ it.isolate()->PushStackTraceAndDie( |
+ 0xabababaa, v8::ToCData<void*>(it.GetInterceptor()->setter()), |
+ nullptr, 0xabababab); |
+ } |
+ Utils::ApiCheck(store_target_map.is_null() || |
+ *store_target_map == it.GetStoreTarget()->map(), |
+ it.IsElement() ? "v8::IndexedPropertySetterCallback" |
+ : "v8::NamedPropertySetterCallback", |
+ "Interceptor silently changed store target."); |
+ } |
+ it.Next(); |
+ } |
+ |
return OrdinaryDefineOwnProperty(&it, desc, should_throw); |
} |