[ic] Don't check full prototype chain if name is a private symbol.

BUG=chromium:664974, chromium:664802, v8:5561

Review-Url: https://codereview.chromium.org/2513893003
Cr-Commit-Position: refs/heads/master@{#41133}
This commit is contained in:
ishell 2016-11-21 03:21:30 -08:00 committed by Commit bot
parent 416e423fdb
commit 4513532f63
4 changed files with 67 additions and 24 deletions

View File

@ -855,8 +855,8 @@ namespace {
template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<FixedArray> array,
Handle<Name> name, int first_index) {
Handle<JSObject> holder, Handle<Name> name,
Handle<FixedArray> array, int first_index) {
DCHECK(holder.is_null() || holder->HasFastProperties());
// We don't encode the requirement to check access rights because we already
@ -894,7 +894,11 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// Create/count entries for each global or dictionary prototype appeared in
// the prototype chain contains from receiver till holder.
for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) {
PrototypeIterator::WhereToEnd end = name->IsPrivate()
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
iter.Advance()) {
Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
if (holder.is_identical_to(current)) break;
Handle<Map> current_map(current->map(), isolate);
@ -932,9 +936,9 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder,
Handle<FixedArray>(), Handle<Name>(), 0);
Handle<JSObject> holder, Handle<Name> name) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
Handle<FixedArray>(), 0);
}
} // namespace
@ -943,7 +947,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Name> name,
Handle<Object> smi_handler) {
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
@ -973,7 +978,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
@ -981,7 +986,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<Name> name) {
Handle<JSObject> holder; // null handle
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
bool do_negative_lookup_on_receiver =
@ -999,9 +1005,6 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
// This must be a case when receiver's prototype is null.
DCHECK_EQ(*isolate()->factory()->null_value(),
receiver_map->GetPrototypeChainRootMap(isolate())->prototype());
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate());
}
@ -1016,7 +1019,7 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value());
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
@ -1893,17 +1896,20 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
smi_handler = StoreHandler::TransitionToField(
isolate(), descriptor, index, representation, extend_storage);
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
DCHECK(!holder.is_null());
bool is_nonexistent = holder->map() == transition->GetBackPointer();
if (is_nonexistent) holder = Handle<JSObject>::null();
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder);
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
// This must be a case when receiver's prototype is null.
DCHECK_EQ(*isolate()->factory()->null_value(),
receiver_map->GetPrototypeChainRootMap(isolate())->prototype());
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate());
}
@ -1919,7 +1925,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name,
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
StoreHandler::kFirstPrototypeIndex);
return handler_array;
}

View File

@ -53,21 +53,35 @@ class PrototypeIterator {
if (where_to_start == kStartAtPrototype) Advance();
}
explicit PrototypeIterator(Map* receiver_map)
explicit PrototypeIterator(Map* receiver_map,
WhereToEnd where_to_end = END_AT_NULL)
: isolate_(receiver_map->GetIsolate()),
object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
where_to_end_(END_AT_NULL),
where_to_end_(where_to_end),
is_at_end_(object_->IsNull(isolate_)),
seen_proxies_(0) {}
seen_proxies_(0) {
if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
DCHECK(object_->IsJSReceiver());
Map* map = JSReceiver::cast(object_)->map();
is_at_end_ = !map->has_hidden_prototype();
}
}
explicit PrototypeIterator(Handle<Map> receiver_map)
explicit PrototypeIterator(Handle<Map> receiver_map,
WhereToEnd where_to_end = END_AT_NULL)
: isolate_(receiver_map->GetIsolate()),
object_(NULL),
handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
isolate_),
where_to_end_(END_AT_NULL),
where_to_end_(where_to_end),
is_at_end_(handle_->IsNull(isolate_)),
seen_proxies_(0) {}
seen_proxies_(0) {
if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) {
DCHECK(handle_->IsJSReceiver());
Map* map = JSReceiver::cast(*handle_)->map();
is_at_end_ = !map->has_hidden_prototype();
}
}
~PrototypeIterator() {}

View File

@ -0,0 +1,10 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var o = {};
o.__proto__ = new Proxy({}, {});
var m = new Map();
m.set({});
m.set(o);

View File

@ -0,0 +1,13 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
for (var i = 0; i < 2000; i++) {
Object.prototype['X'+i] = true;
}
var m = new Map();
m.set(Object.prototype, 23);
var o = {};
m.set(o, 42);