[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:
parent
416e423fdb
commit
4513532f63
42
src/ic/ic.cc
42
src/ic/ic.cc
@ -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;
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
||||
|
10
test/mjsunit/regress/regress-crbug-664802.js
Normal file
10
test/mjsunit/regress/regress-crbug-664802.js
Normal 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);
|
13
test/mjsunit/regress/regress-crbug-664974.js
Normal file
13
test/mjsunit/regress/regress-crbug-664974.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user