Commit 0880d4da authored by dcarney's avatar dcarney Committed by Commit bot

add interceptors which do not mask existing properties

R=verwaest@chromium.org

BUG=

Review URL: https://codereview.chromium.org/962613002

Cr-Commit-Position: refs/heads/master@{#27271}
parent 7f38011a
...@@ -4188,7 +4188,17 @@ class V8_EXPORT FunctionTemplate : public Template { ...@@ -4188,7 +4188,17 @@ class V8_EXPORT FunctionTemplate : public Template {
}; };
enum class PropertyHandlerFlags { kNone = 0, kAllCanRead = 1 }; enum class PropertyHandlerFlags {
kNone = 0,
// See ALL_CAN_READ above.
kAllCanRead = 1,
// Will not call into interceptor for properties on the receiver or prototype
// chain. Currently only valid for named interceptors.
kNonMasking = 1 << 1,
// Will not call into interceptor for symbol lookup. Only meaningful for
// named interceptors.
kOnlyInterceptStrings = 1 << 2,
};
struct NamedPropertyHandlerConfiguration { struct NamedPropertyHandlerConfiguration {
......
...@@ -1280,10 +1280,12 @@ void ObjectTemplate::SetAccessor(v8::Handle<Name> name, ...@@ -1280,10 +1280,12 @@ void ObjectTemplate::SetAccessor(v8::Handle<Name> name,
template <typename Getter, typename Setter, typename Query, typename Deleter, template <typename Getter, typename Setter, typename Query, typename Deleter,
typename Enumerator> typename Enumerator>
static void ObjectTemplateSetNamedPropertyHandler( static void ObjectTemplateSetNamedPropertyHandler(ObjectTemplate* templ,
ObjectTemplate* templ, Getter getter, Setter setter, Query query, Getter getter, Setter setter,
Deleter remover, Enumerator enumerator, Handle<Value> data, Query query, Deleter remover,
bool can_intercept_symbols, PropertyHandlerFlags flags) { Enumerator enumerator,
Handle<Value> data,
PropertyHandlerFlags flags) {
i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate(); i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate();
ENTER_V8(isolate); ENTER_V8(isolate);
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
...@@ -1298,9 +1300,13 @@ static void ObjectTemplateSetNamedPropertyHandler( ...@@ -1298,9 +1300,13 @@ static void ObjectTemplateSetNamedPropertyHandler(
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
obj->set_flags(0); obj->set_flags(0);
obj->set_can_intercept_symbols(can_intercept_symbols); obj->set_can_intercept_symbols(
!(static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kOnlyInterceptStrings)));
obj->set_all_can_read(static_cast<int>(flags) & obj->set_all_can_read(static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kAllCanRead)); static_cast<int>(PropertyHandlerFlags::kAllCanRead));
obj->set_non_masking(static_cast<int>(flags) &
static_cast<int>(PropertyHandlerFlags::kNonMasking));
if (data.IsEmpty()) { if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
...@@ -1314,9 +1320,9 @@ void ObjectTemplate::SetNamedPropertyHandler( ...@@ -1314,9 +1320,9 @@ void ObjectTemplate::SetNamedPropertyHandler(
NamedPropertyGetterCallback getter, NamedPropertySetterCallback setter, NamedPropertyGetterCallback getter, NamedPropertySetterCallback setter,
NamedPropertyQueryCallback query, NamedPropertyDeleterCallback remover, NamedPropertyQueryCallback query, NamedPropertyDeleterCallback remover,
NamedPropertyEnumeratorCallback enumerator, Handle<Value> data) { NamedPropertyEnumeratorCallback enumerator, Handle<Value> data) {
ObjectTemplateSetNamedPropertyHandler(this, getter, setter, query, remover, ObjectTemplateSetNamedPropertyHandler(
enumerator, data, false, this, getter, setter, query, remover, enumerator, data,
PropertyHandlerFlags::kNone); PropertyHandlerFlags::kOnlyInterceptStrings);
} }
...@@ -1324,7 +1330,7 @@ void ObjectTemplate::SetHandler( ...@@ -1324,7 +1330,7 @@ void ObjectTemplate::SetHandler(
const NamedPropertyHandlerConfiguration& config) { const NamedPropertyHandlerConfiguration& config) {
ObjectTemplateSetNamedPropertyHandler( ObjectTemplateSetNamedPropertyHandler(
this, config.getter, config.setter, config.query, config.deleter, this, config.getter, config.setter, config.query, config.deleter,
config.enumerator, config.data, true, config.flags); config.enumerator, config.data, config.flags);
} }
......
...@@ -312,10 +312,32 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( ...@@ -312,10 +312,32 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
Label miss; Label miss;
InterceptorVectorSlotPush(receiver()); InterceptorVectorSlotPush(receiver());
bool lost_holder_register = false;
auto holder_orig = holder();
// non masking interceptors must check the entire chain, so temporarily reset
// the holder to be that last element for the FrontendHeader call.
if (holder()->GetNamedInterceptor()->non_masking()) {
DCHECK(!inline_followup);
JSObject* last = *holder();
PrototypeIterator iter(isolate(), last);
while (!iter.IsAtEnd()) {
lost_holder_register = true;
last = JSObject::cast(iter.GetCurrent());
iter.Advance();
}
auto last_handle = handle(last);
set_holder(last_handle);
}
Register reg = FrontendHeader(receiver(), it->name(), &miss); Register reg = FrontendHeader(receiver(), it->name(), &miss);
// Reset the holder so further calculations are correct.
set_holder(holder_orig);
if (lost_holder_register) {
// Reload lost holder register.
auto cell = isolate()->factory()->NewWeakCell(holder());
__ LoadWeakValue(reg, cell, &miss);
}
FrontendFooter(it->name(), &miss); FrontendFooter(it->name(), &miss);
InterceptorVectorSlotPop(reg); InterceptorVectorSlotPop(reg);
if (inline_followup) { if (inline_followup) {
// TODO(368): Compile in the whole chain: all the interceptors in // TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer. // prototypes and ultimate answer.
......
...@@ -2914,30 +2914,10 @@ RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) { ...@@ -2914,30 +2914,10 @@ RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
Handle<JSObject> holder = Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<InterceptorInfo> interceptor_info(holder->GetNamedInterceptor()); auto res = JSObject::GetPropertyWithInterceptor(holder, receiver, name);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
if (name->IsSymbol() && !interceptor_info->can_intercept_symbols()) Handle<Object> result;
return isolate->heap()->no_interceptor_result_sentinel(); if (res.ToHandle(&result)) return *result;
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
v8::GenericNamedPropertyGetterCallback getter =
FUNCTION_CAST<v8::GenericNamedPropertyGetterCallback>(getter_address);
DCHECK(getter != NULL);
PropertyCallbackArguments callback_args(isolate, interceptor_info->data(),
*receiver, *holder);
{
// Use the interceptor getter.
v8::Handle<v8::Value> r =
callback_args.Call(getter, v8::Utils::ToLocal(name));
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
if (!r.IsEmpty()) {
Handle<Object> result = v8::Utils::OpenHandle(*r);
result->VerifyApiCallResultType();
return *v8::Utils::OpenHandle(*r);
}
}
return isolate->heap()->no_interceptor_result_sentinel(); return isolate->heap()->no_interceptor_result_sentinel();
} }
......
...@@ -31,10 +31,13 @@ JSReceiver* LookupIterator::NextHolder(Map* map) { ...@@ -31,10 +31,13 @@ JSReceiver* LookupIterator::NextHolder(Map* map) {
} }
LookupIterator::State LookupIterator::LookupInHolder(Map* map, LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
JSReceiver* holder) { JSReceiver* const holder) {
STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
return LookupNonMaskingInterceptorInHolder(map, holder);
}
switch (state_) { switch (state_) {
case NOT_FOUND: case NOT_FOUND:
if (map->IsJSProxyMap()) return JSPROXY; if (map->IsJSProxyMap()) return JSPROXY;
...@@ -48,7 +51,8 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map, ...@@ -48,7 +51,8 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
IsIntegerIndexedExotic(holder)) { IsIntegerIndexedExotic(holder)) {
return INTEGER_INDEXED_EXOTIC; return INTEGER_INDEXED_EXOTIC;
} }
if (check_interceptor() && map->has_named_interceptor()) { if (check_interceptor() && map->has_named_interceptor() &&
!SkipInterceptor(JSObject::cast(holder))) {
return INTERCEPTOR; return INTERCEPTOR;
} }
// Fall through. // Fall through.
...@@ -86,6 +90,23 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map, ...@@ -86,6 +90,23 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
UNREACHABLE(); UNREACHABLE();
return state_; return state_;
} }
LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
Map* const map, JSReceiver* const holder) {
switch (state_) {
case NOT_FOUND:
if (check_interceptor() && map->has_named_interceptor() &&
!SkipInterceptor(JSObject::cast(holder))) {
return INTERCEPTOR;
}
// Fall through.
default:
return NOT_FOUND;
}
UNREACHABLE();
return state_;
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -29,7 +29,13 @@ void LookupIterator::Next() { ...@@ -29,7 +29,13 @@ void LookupIterator::Next() {
// Continue lookup if lookup on current holder failed. // Continue lookup if lookup on current holder failed.
do { do {
JSReceiver* maybe_holder = NextHolder(map); JSReceiver* maybe_holder = NextHolder(map);
if (maybe_holder == NULL) break; if (maybe_holder == nullptr) {
if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
RestartLookupForNonMaskingInterceptors();
return;
}
break;
}
holder = maybe_holder; holder = maybe_holder;
map = holder->map(); map = holder->map();
state_ = LookupInHolder(map, holder); state_ = LookupInHolder(map, holder);
...@@ -42,10 +48,21 @@ void LookupIterator::Next() { ...@@ -42,10 +48,21 @@ void LookupIterator::Next() {
} }
Handle<JSReceiver> LookupIterator::GetRoot() const { void LookupIterator::RestartLookupForNonMaskingInterceptors() {
if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_); interceptor_state_ = InterceptorState::kProcessNonMasking;
Handle<Object> root = state_ = NOT_FOUND;
handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_); property_details_ = PropertyDetails::Empty();
number_ = DescriptorArray::kNotFound;
holder_ = initial_holder_;
holder_map_ = handle(holder_->map(), isolate_);
Next();
}
Handle<JSReceiver> LookupIterator::GetRoot(Handle<Object> receiver,
Isolate* isolate) {
if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
CHECK(!root->IsNull()); CHECK(!root->IsNull());
return Handle<JSReceiver>::cast(root); return Handle<JSReceiver>::cast(root);
} }
...@@ -80,6 +97,7 @@ bool LookupIterator::HasAccess() const { ...@@ -80,6 +97,7 @@ bool LookupIterator::HasAccess() const {
void LookupIterator::ReloadPropertyInformation() { void LookupIterator::ReloadPropertyInformation() {
state_ = BEFORE_PROPERTY; state_ = BEFORE_PROPERTY;
interceptor_state_ = InterceptorState::kUninitialized;
state_ = LookupInHolder(*holder_map_, *holder_); state_ = LookupInHolder(*holder_map_, *holder_);
DCHECK(IsFound() || holder_map_->is_dictionary_map()); DCHECK(IsFound() || holder_map_->is_dictionary_map());
} }
...@@ -354,4 +372,22 @@ void LookupIterator::InternalizeName() { ...@@ -354,4 +372,22 @@ void LookupIterator::InternalizeName() {
if (name_->IsUniqueName()) return; if (name_->IsUniqueName()) return;
name_ = factory()->InternalizeString(Handle<String>::cast(name_)); name_ = factory()->InternalizeString(Handle<String>::cast(name_));
} }
bool LookupIterator::SkipInterceptor(JSObject* holder) {
auto info = holder->GetNamedInterceptor();
// TODO(dcarney): check for symbol/can_intercept_symbols here as well.
if (info->non_masking()) {
switch (interceptor_state_) {
case InterceptorState::kUninitialized:
interceptor_state_ = InterceptorState::kSkipNonMasking;
// Fall through.
case InterceptorState::kSkipNonMasking:
return true;
case InterceptorState::kProcessNonMasking:
return false;
}
}
return interceptor_state_ == InterceptorState::kProcessNonMasking;
}
} } // namespace v8::internal } } // namespace v8::internal
...@@ -48,13 +48,15 @@ class LookupIterator FINAL BASE_EMBEDDED { ...@@ -48,13 +48,15 @@ class LookupIterator FINAL BASE_EMBEDDED {
: configuration_(ComputeConfiguration(configuration, name)), : configuration_(ComputeConfiguration(configuration, name)),
state_(NOT_FOUND), state_(NOT_FOUND),
exotic_index_state_(ExoticIndexState::kUninitialized), exotic_index_state_(ExoticIndexState::kUninitialized),
interceptor_state_(InterceptorState::kUninitialized),
property_details_(PropertyDetails::Empty()), property_details_(PropertyDetails::Empty()),
isolate_(name->GetIsolate()), isolate_(name->GetIsolate()),
name_(name), name_(name),
receiver_(receiver), receiver_(receiver),
holder_(GetRoot(receiver_, isolate_)),
holder_map_(holder_->map(), isolate_),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) { number_(DescriptorArray::kNotFound) {
holder_ = GetRoot();
holder_map_ = handle(holder_->map(), isolate_);
Next(); Next();
} }
...@@ -64,12 +66,14 @@ class LookupIterator FINAL BASE_EMBEDDED { ...@@ -64,12 +66,14 @@ class LookupIterator FINAL BASE_EMBEDDED {
: configuration_(ComputeConfiguration(configuration, name)), : configuration_(ComputeConfiguration(configuration, name)),
state_(NOT_FOUND), state_(NOT_FOUND),
exotic_index_state_(ExoticIndexState::kUninitialized), exotic_index_state_(ExoticIndexState::kUninitialized),
interceptor_state_(InterceptorState::kUninitialized),
property_details_(PropertyDetails::Empty()), property_details_(PropertyDetails::Empty()),
isolate_(name->GetIsolate()), isolate_(name->GetIsolate()),
name_(name), name_(name),
holder_map_(holder->map(), isolate_),
receiver_(receiver), receiver_(receiver),
holder_(holder), holder_(holder),
holder_map_(holder_->map(), isolate_),
initial_holder_(holder_),
number_(DescriptorArray::kNotFound) { number_(DescriptorArray::kNotFound) {
Next(); Next();
} }
...@@ -98,7 +102,7 @@ class LookupIterator FINAL BASE_EMBEDDED { ...@@ -98,7 +102,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
DCHECK(IsFound()); DCHECK(IsFound());
return Handle<T>::cast(holder_); return Handle<T>::cast(holder_);
} }
Handle<JSReceiver> GetRoot() const; static Handle<JSReceiver> GetRoot(Handle<Object> receiver, Isolate* isolate);
bool HolderIsReceiverOrHiddenPrototype() const; bool HolderIsReceiverOrHiddenPrototype() const;
/* ACCESS_CHECK */ /* ACCESS_CHECK */
...@@ -146,12 +150,21 @@ class LookupIterator FINAL BASE_EMBEDDED { ...@@ -146,12 +150,21 @@ class LookupIterator FINAL BASE_EMBEDDED {
void InternalizeName(); void InternalizeName();
private: private:
enum class InterceptorState {
kUninitialized,
kSkipNonMasking,
kProcessNonMasking
};
Handle<Map> GetReceiverMap() const; Handle<Map> GetReceiverMap() const;
MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map); MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
inline State LookupInHolder(Map* map, JSReceiver* holder); inline State LookupInHolder(Map* map, JSReceiver* holder);
void RestartLookupForNonMaskingInterceptors();
State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
Handle<Object> FetchValue() const; Handle<Object> FetchValue() const;
void ReloadPropertyInformation(); void ReloadPropertyInformation();
bool SkipInterceptor(JSObject* holder);
bool IsBootstrapping() const; bool IsBootstrapping() const;
...@@ -188,18 +201,19 @@ class LookupIterator FINAL BASE_EMBEDDED { ...@@ -188,18 +201,19 @@ class LookupIterator FINAL BASE_EMBEDDED {
// If configuration_ becomes mutable, update // If configuration_ becomes mutable, update
// HolderIsReceiverOrHiddenPrototype. // HolderIsReceiverOrHiddenPrototype.
Configuration configuration_; const Configuration configuration_;
State state_; State state_;
bool has_property_; bool has_property_;
ExoticIndexState exotic_index_state_; ExoticIndexState exotic_index_state_;
InterceptorState interceptor_state_;
PropertyDetails property_details_; PropertyDetails property_details_;
Isolate* isolate_; Isolate* const isolate_;
Handle<Name> name_; Handle<Name> name_;
Handle<Map> holder_map_;
Handle<Object> transition_; Handle<Object> transition_;
Handle<Object> receiver_; const Handle<Object> receiver_;
Handle<JSReceiver> holder_; Handle<JSReceiver> holder_;
Handle<Map> holder_map_;
const Handle<JSReceiver> initial_holder_;
int number_; int number_;
}; };
......
...@@ -5452,6 +5452,7 @@ SMI_ACCESSORS(InterceptorInfo, flags, kFlagsOffset) ...@@ -5452,6 +5452,7 @@ SMI_ACCESSORS(InterceptorInfo, flags, kFlagsOffset)
BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols, BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols,
kCanInterceptSymbolsBit) kCanInterceptSymbolsBit)
BOOL_ACCESSORS(InterceptorInfo, flags, all_can_read, kAllCanReadBit) BOOL_ACCESSORS(InterceptorInfo, flags, all_can_read, kAllCanReadBit)
BOOL_ACCESSORS(InterceptorInfo, flags, non_masking, kNonMasking)
ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
......
...@@ -10573,6 +10573,7 @@ class InterceptorInfo: public Struct { ...@@ -10573,6 +10573,7 @@ class InterceptorInfo: public Struct {
DECL_ACCESSORS(data, Object) DECL_ACCESSORS(data, Object)
DECL_BOOLEAN_ACCESSORS(can_intercept_symbols) DECL_BOOLEAN_ACCESSORS(can_intercept_symbols)
DECL_BOOLEAN_ACCESSORS(all_can_read) DECL_BOOLEAN_ACCESSORS(all_can_read)
DECL_BOOLEAN_ACCESSORS(non_masking)
inline int flags() const; inline int flags() const;
inline void set_flags(int flags); inline void set_flags(int flags);
...@@ -10594,6 +10595,7 @@ class InterceptorInfo: public Struct { ...@@ -10594,6 +10595,7 @@ class InterceptorInfo: public Struct {
static const int kCanInterceptSymbolsBit = 0; static const int kCanInterceptSymbolsBit = 0;
static const int kAllCanReadBit = 1; static const int kAllCanReadBit = 1;
static const int kNonMasking = 2;
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
......
...@@ -3100,3 +3100,130 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { ...@@ -3100,3 +3100,130 @@ THREADED_TEST(IndexedAllCanReadInterceptor) {
ExpectInt32("checked[15]", intercept_data_1.value); ExpectInt32("checked[15]", intercept_data_1.value);
CHECK_EQ(3, access_check_data.count); CHECK_EQ(3, access_check_data.count);
} }
THREADED_TEST(NonMaskingInterceptorOwnProperty) {
auto isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext context;
ShouldInterceptData intercept_data;
intercept_data.value = 239;
intercept_data.should_intercept = true;
auto interceptor_templ = v8::ObjectTemplate::New(isolate);
v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
conf.flags = v8::PropertyHandlerFlags::kNonMasking;
conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
interceptor_templ->SetHandler(conf);
auto interceptor = interceptor_templ->NewInstance();
context->Global()->Set(v8_str("obj"), interceptor);
ExpectInt32("obj.whatever", 239);
CompileRun("obj.whatever = 4;");
ExpectInt32("obj.whatever", 4);
CompileRun("delete obj.whatever;");
ExpectInt32("obj.whatever", 239);
}
THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
auto isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext context;
ShouldInterceptData intercept_data;
intercept_data.value = 239;
intercept_data.should_intercept = true;
auto interceptor_templ = v8::ObjectTemplate::New(isolate);
v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
conf.flags = v8::PropertyHandlerFlags::kNonMasking;
conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
interceptor_templ->SetHandler(conf);
auto interceptor = interceptor_templ->NewInstance();
context->Global()->Set(v8_str("obj"), interceptor);
ExpectInt32("obj.whatever", 239);
CompileRun("obj.__proto__ = {'whatever': 4};");
ExpectInt32("obj.whatever", 4);
CompileRun("delete obj.__proto__.whatever;");
ExpectInt32("obj.whatever", 239);
}
THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
auto isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
LocalContext context;
ShouldInterceptData intercept_data;
intercept_data.value = 239;
intercept_data.should_intercept = true;
auto interceptor_templ = v8::ObjectTemplate::New(isolate);
v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
conf.flags = v8::PropertyHandlerFlags::kNonMasking;
conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
interceptor_templ->SetHandler(conf);
auto interceptor = interceptor_templ->NewInstance();
context->Global()->Set(v8_str("obj"), interceptor);
CompileRun(
"outer = {};"
"outer.__proto__ = obj;"
"function f(obj) {"
" var x;"
" for (var i = 0; i < 4; i++) {"
" x = obj.whatever;"
" }"
" return x;"
"}");
// Receiver == holder.
CompileRun("obj.__proto__ = null;");
ExpectInt32("f(obj)", 239);
ExpectInt32("f(outer)", 239);
// Receiver != holder.
CompileRun("Object.setPrototypeOf(obj, {});");
ExpectInt32("f(obj)", 239);
ExpectInt32("f(outer)", 239);
// Masked value on prototype.
CompileRun("obj.__proto__.whatever = 4;");
CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
ExpectInt32("f(obj)", 4);
ExpectInt32("f(outer)", 4);
// Masked value on prototype prototype.
CompileRun("delete obj.__proto__.whatever;");
ExpectInt32("f(obj)", 5);
ExpectInt32("f(outer)", 5);
// Reset.
CompileRun("delete obj.__proto__.__proto__.whatever;");
ExpectInt32("f(obj)", 239);
ExpectInt32("f(outer)", 239);
// Masked value on self.
CompileRun("obj.whatever = 4;");
ExpectInt32("f(obj)", 4);
ExpectInt32("f(outer)", 4);
// Reset.
CompileRun("delete obj.whatever;");
ExpectInt32("f(obj)", 239);
ExpectInt32("f(outer)", 239);
CompileRun("outer.whatever = 4;");
ExpectInt32("f(obj)", 239);
ExpectInt32("f(outer)", 4);
}
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