[api] Add interceptor for getOwnPropertyDescriptor().
The existing PropertyQueryCallback intercepts getOwnPropertyDescriptor, but it returns only value and attributes, not the accessors. This PropertyDescriptorCallback returns a descriptor similar to Ecma-262 6.2.4. You can either set a PropertyQueryCallback or a PropertyDescriptorCallback, but not both. When you set a callback for DefineProperty(), you can set a PropertyDescriptorCallback but not a PropertyQueryCallback. BUG=v8:5359 Review-Url: https://codereview.chromium.org/2311873002 Cr-Commit-Position: refs/heads/master@{#39279}
This commit is contained in:
parent
212624b757
commit
b0a7738a5f
40
include/v8.h
40
include/v8.h
@ -4740,6 +4740,28 @@ typedef void (*GenericNamedPropertyDefinerCallback)(
|
||||
Local<Name> property, const PropertyDescriptor& desc,
|
||||
const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
/**
|
||||
* Interceptor for getOwnPropertyDescriptor requests on an object.
|
||||
*
|
||||
* Use `info.GetReturnValue().Set()` to set the return value of the
|
||||
* intercepted request. The return value must be an object that
|
||||
* can be converted to a PropertyDescriptor, e.g., a `v8::value` returned from
|
||||
* `v8::Object::getOwnPropertyDescriptor`.
|
||||
*
|
||||
* \param property The name of the property for which the request was
|
||||
* intercepted.
|
||||
* \info Information about the intercepted request, such as
|
||||
* isolate, receiver, return value, or whether running in `'use strict'` mode.
|
||||
* See `PropertyCallbackInfo`.
|
||||
*
|
||||
* \note If GetOwnPropertyDescriptor is intercepted, it will
|
||||
* always return true, i.e., indicate that the property was found.
|
||||
*
|
||||
* See also `ObjectTemplate::SetNamedPropertyHandler`.
|
||||
*/
|
||||
typedef void (*GenericNamedPropertyDescriptorCallback)(
|
||||
Local<Name> property, const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
/**
|
||||
* Returns the value of the property if the getter intercepts the
|
||||
* request. Otherwise, returns an empty handle.
|
||||
@ -4789,6 +4811,9 @@ typedef void (*IndexedPropertyDefinerCallback)(
|
||||
uint32_t index, const PropertyDescriptor& desc,
|
||||
const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
typedef void (*IndexedPropertyDescriptorCallback)(
|
||||
uint32_t index, const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
/**
|
||||
* Access type specification.
|
||||
*/
|
||||
@ -5050,13 +5075,14 @@ struct NamedPropertyHandlerConfiguration {
|
||||
deleter(deleter),
|
||||
enumerator(enumerator),
|
||||
definer(0),
|
||||
descriptor(0),
|
||||
data(data),
|
||||
flags(flags) {}
|
||||
|
||||
NamedPropertyHandlerConfiguration(
|
||||
GenericNamedPropertyGetterCallback getter,
|
||||
GenericNamedPropertySetterCallback setter,
|
||||
GenericNamedPropertyQueryCallback query,
|
||||
GenericNamedPropertyDescriptorCallback descriptor,
|
||||
GenericNamedPropertyDeleterCallback deleter,
|
||||
GenericNamedPropertyEnumeratorCallback enumerator,
|
||||
GenericNamedPropertyDefinerCallback definer,
|
||||
@ -5064,10 +5090,11 @@ struct NamedPropertyHandlerConfiguration {
|
||||
PropertyHandlerFlags flags = PropertyHandlerFlags::kNone)
|
||||
: getter(getter),
|
||||
setter(setter),
|
||||
query(query),
|
||||
query(0),
|
||||
deleter(deleter),
|
||||
enumerator(enumerator),
|
||||
definer(definer),
|
||||
descriptor(descriptor),
|
||||
data(data),
|
||||
flags(flags) {}
|
||||
|
||||
@ -5077,6 +5104,7 @@ struct NamedPropertyHandlerConfiguration {
|
||||
GenericNamedPropertyDeleterCallback deleter;
|
||||
GenericNamedPropertyEnumeratorCallback enumerator;
|
||||
GenericNamedPropertyDefinerCallback definer;
|
||||
GenericNamedPropertyDescriptorCallback descriptor;
|
||||
Local<Value> data;
|
||||
PropertyHandlerFlags flags;
|
||||
};
|
||||
@ -5098,12 +5126,14 @@ struct IndexedPropertyHandlerConfiguration {
|
||||
deleter(deleter),
|
||||
enumerator(enumerator),
|
||||
definer(0),
|
||||
descriptor(0),
|
||||
data(data),
|
||||
flags(flags) {}
|
||||
|
||||
IndexedPropertyHandlerConfiguration(
|
||||
IndexedPropertyGetterCallback getter,
|
||||
IndexedPropertySetterCallback setter, IndexedPropertyQueryCallback query,
|
||||
IndexedPropertySetterCallback setter,
|
||||
IndexedPropertyDescriptorCallback descriptor,
|
||||
IndexedPropertyDeleterCallback deleter,
|
||||
IndexedPropertyEnumeratorCallback enumerator,
|
||||
IndexedPropertyDefinerCallback definer,
|
||||
@ -5111,10 +5141,11 @@ struct IndexedPropertyHandlerConfiguration {
|
||||
PropertyHandlerFlags flags = PropertyHandlerFlags::kNone)
|
||||
: getter(getter),
|
||||
setter(setter),
|
||||
query(query),
|
||||
query(0),
|
||||
deleter(deleter),
|
||||
enumerator(enumerator),
|
||||
definer(definer),
|
||||
descriptor(descriptor),
|
||||
data(data),
|
||||
flags(flags) {}
|
||||
|
||||
@ -5124,6 +5155,7 @@ struct IndexedPropertyHandlerConfiguration {
|
||||
IndexedPropertyDeleterCallback deleter;
|
||||
IndexedPropertyEnumeratorCallback enumerator;
|
||||
IndexedPropertyDefinerCallback definer;
|
||||
IndexedPropertyDescriptorCallback descriptor;
|
||||
Local<Value> data;
|
||||
PropertyHandlerFlags flags;
|
||||
};
|
||||
|
50
src/api.cc
50
src/api.cc
@ -1503,12 +1503,17 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name,
|
||||
signature, i::FLAG_disable_old_api_accessors);
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter, typename Query, typename Deleter,
|
||||
typename Enumerator, typename Definer>
|
||||
template <typename Getter, typename Setter, typename Query, typename Descriptor,
|
||||
typename Deleter, typename Enumerator, typename Definer>
|
||||
static i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
|
||||
i::Isolate* isolate, Getter getter, Setter setter, Query query,
|
||||
Deleter remover, Enumerator enumerator, Definer definer, Local<Value> data,
|
||||
PropertyHandlerFlags flags) {
|
||||
Descriptor descriptor, Deleter remover, Enumerator enumerator,
|
||||
Definer definer, Local<Value> data, PropertyHandlerFlags flags) {
|
||||
DCHECK(query == nullptr ||
|
||||
descriptor == nullptr); // Either intercept attributes or descriptor.
|
||||
DCHECK(query == nullptr ||
|
||||
definer ==
|
||||
nullptr); // Only use descriptor callback with definer callback.
|
||||
auto obj = i::Handle<i::InterceptorInfo>::cast(
|
||||
isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE));
|
||||
obj->set_flags(0);
|
||||
@ -1516,6 +1521,7 @@ static i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
|
||||
if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
|
||||
if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
|
||||
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
|
||||
if (descriptor != 0) SET_FIELD_WRAPPED(obj, set_descriptor, descriptor);
|
||||
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
|
||||
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
|
||||
if (definer != 0) SET_FIELD_WRAPPED(obj, set_definer, definer);
|
||||
@ -1534,19 +1540,19 @@ static i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter, typename Query, typename Deleter,
|
||||
typename Enumerator, typename Definer>
|
||||
template <typename Getter, typename Setter, typename Query, typename Descriptor,
|
||||
typename Deleter, typename Enumerator, typename Definer>
|
||||
static void ObjectTemplateSetNamedPropertyHandler(
|
||||
ObjectTemplate* templ, Getter getter, Setter setter, Query query,
|
||||
Deleter remover, Enumerator enumerator, Definer definer, Local<Value> data,
|
||||
PropertyHandlerFlags flags) {
|
||||
Descriptor descriptor, Deleter remover, Enumerator enumerator,
|
||||
Definer definer, Local<Value> data, PropertyHandlerFlags flags) {
|
||||
i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate();
|
||||
ENTER_V8(isolate);
|
||||
i::HandleScope scope(isolate);
|
||||
auto cons = EnsureConstructor(isolate, templ);
|
||||
EnsureNotInstantiated(cons, "ObjectTemplateSetNamedPropertyHandler");
|
||||
auto obj = CreateInterceptorInfo(isolate, getter, setter, query, remover,
|
||||
enumerator, definer, data, flags);
|
||||
auto obj = CreateInterceptorInfo(isolate, getter, setter, query, descriptor,
|
||||
remover, enumerator, definer, data, flags);
|
||||
cons->set_named_property_handler(*obj);
|
||||
}
|
||||
|
||||
@ -1555,15 +1561,16 @@ void ObjectTemplate::SetNamedPropertyHandler(
|
||||
NamedPropertyQueryCallback query, NamedPropertyDeleterCallback remover,
|
||||
NamedPropertyEnumeratorCallback enumerator, Local<Value> data) {
|
||||
ObjectTemplateSetNamedPropertyHandler(
|
||||
this, getter, setter, query, remover, enumerator, nullptr, data,
|
||||
this, getter, setter, query, nullptr, remover, enumerator, nullptr, data,
|
||||
PropertyHandlerFlags::kOnlyInterceptStrings);
|
||||
}
|
||||
|
||||
void ObjectTemplate::SetHandler(
|
||||
const NamedPropertyHandlerConfiguration& config) {
|
||||
ObjectTemplateSetNamedPropertyHandler(
|
||||
this, config.getter, config.setter, config.query, config.deleter,
|
||||
config.enumerator, config.definer, config.data, config.flags);
|
||||
this, config.getter, config.setter, config.query, config.descriptor,
|
||||
config.deleter, config.enumerator, config.definer, config.data,
|
||||
config.flags);
|
||||
}
|
||||
|
||||
|
||||
@ -1623,14 +1630,14 @@ void ObjectTemplate::SetAccessCheckCallbackAndHandler(
|
||||
SET_FIELD_WRAPPED(info, set_callback, callback);
|
||||
auto named_interceptor = CreateInterceptorInfo(
|
||||
isolate, named_handler.getter, named_handler.setter, named_handler.query,
|
||||
named_handler.deleter, named_handler.enumerator, named_handler.definer,
|
||||
named_handler.data, named_handler.flags);
|
||||
named_handler.descriptor, named_handler.deleter, named_handler.enumerator,
|
||||
named_handler.definer, named_handler.data, named_handler.flags);
|
||||
info->set_named_interceptor(*named_interceptor);
|
||||
auto indexed_interceptor = CreateInterceptorInfo(
|
||||
isolate, indexed_handler.getter, indexed_handler.setter,
|
||||
indexed_handler.query, indexed_handler.deleter,
|
||||
indexed_handler.enumerator, indexed_handler.definer, indexed_handler.data,
|
||||
indexed_handler.flags);
|
||||
indexed_handler.query, indexed_handler.descriptor,
|
||||
indexed_handler.deleter, indexed_handler.enumerator,
|
||||
indexed_handler.definer, indexed_handler.data, indexed_handler.flags);
|
||||
info->set_indexed_interceptor(*indexed_interceptor);
|
||||
|
||||
if (data.IsEmpty()) {
|
||||
@ -1649,9 +1656,10 @@ void ObjectTemplate::SetHandler(
|
||||
i::HandleScope scope(isolate);
|
||||
auto cons = EnsureConstructor(isolate, this);
|
||||
EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetHandler");
|
||||
auto obj = CreateInterceptorInfo(
|
||||
isolate, config.getter, config.setter, config.query, config.deleter,
|
||||
config.enumerator, config.definer, config.data, config.flags);
|
||||
auto obj = CreateInterceptorInfo(isolate, config.getter, config.setter,
|
||||
config.query, config.descriptor,
|
||||
config.deleter, config.enumerator,
|
||||
config.definer, config.data, config.flags);
|
||||
cons->set_indexed_property_handler(*obj);
|
||||
}
|
||||
|
||||
|
@ -682,10 +682,12 @@ class RuntimeCallTimer {
|
||||
V(GC) \
|
||||
V(GenericNamedPropertyDefinerCallback) \
|
||||
V(GenericNamedPropertyDeleterCallback) \
|
||||
V(GenericNamedPropertyDescriptorCallback) \
|
||||
V(GenericNamedPropertyQueryCallback) \
|
||||
V(GenericNamedPropertySetterCallback) \
|
||||
V(IndexedPropertyDefinerCallback) \
|
||||
V(IndexedPropertyDeleterCallback) \
|
||||
V(IndexedPropertyDescriptorCallback) \
|
||||
V(IndexedPropertyGetterCallback) \
|
||||
V(IndexedPropertyQueryCallback) \
|
||||
V(IndexedPropertySetterCallback) \
|
||||
|
@ -5708,6 +5708,7 @@ ACCESSORS(AccessCheckInfo, data, Object, kDataOffset)
|
||||
ACCESSORS(InterceptorInfo, getter, Object, kGetterOffset)
|
||||
ACCESSORS(InterceptorInfo, setter, Object, kSetterOffset)
|
||||
ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
|
||||
ACCESSORS(InterceptorInfo, descriptor, Object, kDescriptorOffset)
|
||||
ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
|
||||
ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
|
||||
ACCESSORS(InterceptorInfo, definer, Object, kDefinerOffset)
|
||||
|
@ -7336,6 +7336,57 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate,
|
||||
return GetOwnPropertyDescriptor(&it, desc);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
|
||||
PropertyDescriptor* desc) {
|
||||
if (it->state() == LookupIterator::INTERCEPTOR) {
|
||||
Isolate* isolate = it->isolate();
|
||||
Handle<InterceptorInfo> interceptor = it->GetInterceptor();
|
||||
if (!interceptor->descriptor()->IsUndefined(isolate)) {
|
||||
Handle<Object> result;
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
|
||||
Handle<Object> receiver = it->GetReceiver();
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, receiver, Object::ConvertReceiver(isolate, receiver),
|
||||
Nothing<bool>());
|
||||
}
|
||||
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, Object::DONT_THROW);
|
||||
if (it->IsElement()) {
|
||||
uint32_t index = it->index();
|
||||
v8::IndexedPropertyDescriptorCallback descriptorCallback =
|
||||
v8::ToCData<v8::IndexedPropertyDescriptorCallback>(
|
||||
interceptor->descriptor());
|
||||
|
||||
result = args.Call(descriptorCallback, index);
|
||||
} else {
|
||||
Handle<Name> name = it->name();
|
||||
DCHECK(!name->IsPrivate());
|
||||
v8::GenericNamedPropertyDescriptorCallback descriptorCallback =
|
||||
v8::ToCData<v8::GenericNamedPropertyDescriptorCallback>(
|
||||
interceptor->descriptor());
|
||||
result = args.Call(descriptorCallback, name);
|
||||
}
|
||||
if (!result.is_null()) {
|
||||
// Request successfully intercepted, try to set the property
|
||||
// descriptor.
|
||||
Utils::ApiCheck(
|
||||
PropertyDescriptor::ToPropertyDescriptor(isolate, result, desc),
|
||||
it->IsElement() ? "v8::IndexedPropertyDescriptorCallback"
|
||||
: "v8::NamedPropertyDescriptorCallback",
|
||||
"Invalid property descriptor.");
|
||||
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Just(false);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ES6 9.1.5.1
|
||||
// Returns true on success, false if the property didn't exist, nothing if
|
||||
@ -7350,6 +7401,13 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
|
||||
it->GetName(), desc);
|
||||
}
|
||||
|
||||
Maybe<bool> intercepted = GetPropertyDescriptorWithInterceptor(it, desc);
|
||||
MAYBE_RETURN(intercepted, Nothing<bool>());
|
||||
if (intercepted.FromJust()) {
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
// Request was not intercepted, continue as normal.
|
||||
// 1. (Assert)
|
||||
// 2. If O does not have an own property with key P, return undefined.
|
||||
Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(it);
|
||||
|
@ -2062,7 +2062,7 @@ class JSObject: public JSReceiver {
|
||||
// [elements]: The elements (properties with names that are integers).
|
||||
//
|
||||
// Elements can be in two general modes: fast and slow. Each mode
|
||||
// corrensponds to a set of object representations of elements that
|
||||
// corresponds to a set of object representations of elements that
|
||||
// have something in common.
|
||||
//
|
||||
// In the fast mode elements is a FixedArray and so each element can
|
||||
@ -10810,6 +10810,7 @@ class InterceptorInfo: public Struct {
|
||||
DECL_ACCESSORS(getter, Object)
|
||||
DECL_ACCESSORS(setter, Object)
|
||||
DECL_ACCESSORS(query, Object)
|
||||
DECL_ACCESSORS(descriptor, Object)
|
||||
DECL_ACCESSORS(deleter, Object)
|
||||
DECL_ACCESSORS(enumerator, Object)
|
||||
DECL_ACCESSORS(definer, Object)
|
||||
@ -10830,7 +10831,8 @@ class InterceptorInfo: public Struct {
|
||||
static const int kGetterOffset = HeapObject::kHeaderSize;
|
||||
static const int kSetterOffset = kGetterOffset + kPointerSize;
|
||||
static const int kQueryOffset = kSetterOffset + kPointerSize;
|
||||
static const int kDeleterOffset = kQueryOffset + kPointerSize;
|
||||
static const int kDescriptorOffset = kQueryOffset + kPointerSize;
|
||||
static const int kDeleterOffset = kDescriptorOffset + kPointerSize;
|
||||
static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
|
||||
static const int kDefinerOffset = kEnumeratorOffset + kPointerSize;
|
||||
static const int kDataOffset = kDefinerOffset + kPointerSize;
|
||||
|
@ -268,6 +268,23 @@ void CheckThisIndexedPropertySetter(
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
void CheckThisIndexedPropertyDescriptor(
|
||||
uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDescriptor));
|
||||
ApiTestFuzzer::Fuzz();
|
||||
CHECK(info.This()
|
||||
->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
void CheckThisNamedPropertyDescriptor(
|
||||
Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDescriptor));
|
||||
ApiTestFuzzer::Fuzz();
|
||||
CHECK(info.This()
|
||||
->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
void CheckThisNamedPropertySetter(
|
||||
Local<Name> property, Local<Value> value,
|
||||
@ -1309,13 +1326,13 @@ namespace {
|
||||
void NotInterceptingPropertyDefineCallback(
|
||||
Local<Name> name, const v8::PropertyDescriptor& desc,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
// Do not intercept by not calling info.GetReturnValue().Set()
|
||||
// Do not intercept by not calling info.GetReturnValue().Set().
|
||||
}
|
||||
|
||||
void InterceptingPropertyDefineCallback(
|
||||
Local<Name> name, const v8::PropertyDescriptor& desc,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
// intercept the callback by setting a non-empty handle
|
||||
// Intercept the callback by setting a non-empty handle
|
||||
info.GetReturnValue().Set(name);
|
||||
}
|
||||
|
||||
@ -1735,6 +1752,74 @@ THREADED_TEST(PropertyDefinerCallbackWithSetter) {
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
namespace {
|
||||
void EmptyPropertyDescriptorCallback(
|
||||
Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
// Do not intercept by not calling info.GetReturnValue().Set().
|
||||
}
|
||||
|
||||
void InterceptingPropertyDescriptorCallback(
|
||||
Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
// Intercept the callback by setting a different descriptor.
|
||||
const char* code =
|
||||
"var desc = {value: 42};"
|
||||
"desc;";
|
||||
Local<Value> descriptor = v8_compile(code)
|
||||
->Run(info.GetIsolate()->GetCurrentContext())
|
||||
.ToLocalChecked();
|
||||
info.GetReturnValue().Set(descriptor);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
THREADED_TEST(PropertyDescriptorCallback) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
LocalContext env;
|
||||
|
||||
{ // Normal behavior of getOwnPropertyDescriptor() with empty callback.
|
||||
v8::Local<v8::FunctionTemplate> templ =
|
||||
v8::FunctionTemplate::New(CcTest::isolate());
|
||||
templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
||||
0, 0, EmptyPropertyDescriptorCallback, 0, 0, 0));
|
||||
env->Global()
|
||||
->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(env.local())
|
||||
.ToLocalChecked())
|
||||
.FromJust();
|
||||
const char* code =
|
||||
"obj.x = 17; "
|
||||
"var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
|
||||
"desc.value;";
|
||||
CHECK_EQ(17, v8_compile(code)
|
||||
->Run(env.local())
|
||||
.ToLocalChecked()
|
||||
->Int32Value(env.local())
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
{ // Intercept getOwnPropertyDescriptor().
|
||||
v8::Local<v8::FunctionTemplate> templ =
|
||||
v8::FunctionTemplate::New(CcTest::isolate());
|
||||
templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
||||
0, 0, InterceptingPropertyDescriptorCallback, 0, 0, 0));
|
||||
env->Global()
|
||||
->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(env.local())
|
||||
.ToLocalChecked())
|
||||
.FromJust();
|
||||
const char* code =
|
||||
"obj.x = 17; "
|
||||
"var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
|
||||
"desc.value;";
|
||||
CHECK_EQ(42, v8_compile(code)
|
||||
->Run(env.local())
|
||||
.ToLocalChecked()
|
||||
->Int32Value(env.local())
|
||||
.FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
int echo_indexed_call_count = 0;
|
||||
|
||||
|
||||
@ -1776,17 +1861,16 @@ THREADED_TEST(PropertyHandlerInPrototype) {
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
// Set up a prototype chain with three interceptors.
|
||||
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
||||
templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
|
||||
CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
|
||||
CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
|
||||
CheckThisIndexedPropertyEnumerator, CheckThisIndexedPropertyDefiner));
|
||||
CheckThisIndexedPropertyEnumerator));
|
||||
|
||||
templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
||||
CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
|
||||
CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
|
||||
CheckThisNamedPropertyEnumerator, CheckThisNamedPropertyDefiner));
|
||||
CheckThisNamedPropertyEnumerator));
|
||||
|
||||
bottom = templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
@ -1823,10 +1907,63 @@ THREADED_TEST(PropertyHandlerInPrototype) {
|
||||
|
||||
// Enumerators.
|
||||
CompileRun("for (var p in obj) ;");
|
||||
}
|
||||
|
||||
TEST(PropertyHandlerInPrototypeWithDefine) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
||||
templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
|
||||
CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
|
||||
CheckThisIndexedPropertyDescriptor, CheckThisIndexedPropertyDeleter,
|
||||
CheckThisIndexedPropertyEnumerator, CheckThisIndexedPropertyDefiner));
|
||||
|
||||
templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
||||
CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
|
||||
CheckThisNamedPropertyDescriptor, CheckThisNamedPropertyDeleter,
|
||||
CheckThisNamedPropertyEnumerator, CheckThisNamedPropertyDefiner));
|
||||
|
||||
bottom = templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(env.local())
|
||||
.ToLocalChecked();
|
||||
Local<v8::Object> top = templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(env.local())
|
||||
.ToLocalChecked();
|
||||
Local<v8::Object> middle = templ->GetFunction(env.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(env.local())
|
||||
.ToLocalChecked();
|
||||
|
||||
bottom->SetPrototype(env.local(), middle).FromJust();
|
||||
middle->SetPrototype(env.local(), top).FromJust();
|
||||
env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
|
||||
|
||||
// Indexed and named get.
|
||||
CompileRun("obj[0]");
|
||||
CompileRun("obj.x");
|
||||
|
||||
// Indexed and named set.
|
||||
CompileRun("obj[1] = 42");
|
||||
CompileRun("obj.y = 42");
|
||||
|
||||
// Indexed and named deleter.
|
||||
CompileRun("delete obj[0]");
|
||||
CompileRun("delete obj.x");
|
||||
|
||||
// Enumerators.
|
||||
CompileRun("for (var p in obj) ;");
|
||||
|
||||
// Indexed and named definer.
|
||||
CompileRun("Object.defineProperty(obj, 2, {});");
|
||||
CompileRun("Object.defineProperty(obj, 'z', {});");
|
||||
|
||||
// Indexed and named propertyDescriptor.
|
||||
CompileRun("Object.getOwnPropertyDescriptor(obj, 2);");
|
||||
CompileRun("Object.getOwnPropertyDescriptor(obj, 'z');");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user