Commit 4513532f authored by ishell's avatar ishell Committed by Commit bot

[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}
parent 416e423f
...@@ -855,8 +855,8 @@ namespace { ...@@ -855,8 +855,8 @@ namespace {
template <bool fill_array = true> template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<FixedArray> array, Handle<JSObject> holder, Handle<Name> name,
Handle<Name> name, int first_index) { Handle<FixedArray> array, int first_index) {
DCHECK(holder.is_null() || holder->HasFastProperties()); DCHECK(holder.is_null() || holder->HasFastProperties());
// We don't encode the requirement to check access rights because we already // 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, ...@@ -894,7 +894,11 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// Create/count entries for each global or dictionary prototype appeared in // Create/count entries for each global or dictionary prototype appeared in
// the prototype chain contains from receiver till holder. // 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); Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
if (holder.is_identical_to(current)) break; if (holder.is_identical_to(current)) break;
Handle<Map> current_map(current->map(), isolate); Handle<Map> current_map(current->map(), isolate);
...@@ -932,9 +936,9 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, ...@@ -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 // Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise. // checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map, int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder) { Handle<JSObject> holder, Handle<Name> name) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder, return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
Handle<FixedArray>(), Handle<Name>(), 0); Handle<FixedArray>(), 0);
} }
} // namespace } // namespace
...@@ -943,7 +947,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, ...@@ -943,7 +947,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<Name> name, Handle<Name> name,
Handle<Object> smi_handler) { 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); DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
...@@ -973,7 +978,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, ...@@ -973,7 +978,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *holder_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); LoadHandler::kFirstPrototypeIndex);
return handler_array; return handler_array;
} }
...@@ -981,7 +986,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, ...@@ -981,7 +986,8 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<Name> name) { Handle<Name> name) {
Handle<JSObject> holder; // null handle 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); DCHECK_LE(0, checks_count);
bool do_negative_lookup_on_receiver = bool do_negative_lookup_on_receiver =
...@@ -999,9 +1005,6 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, ...@@ -999,9 +1005,6 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
Handle<Object> validity_cell = Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) { 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); DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate()); validity_cell = handle(Smi::FromInt(0), isolate());
} }
...@@ -1016,7 +1019,7 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, ...@@ -1016,7 +1019,7 @@ Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); 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); LoadHandler::kFirstPrototypeIndex);
return handler_array; return handler_array;
} }
...@@ -1893,17 +1896,20 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, ...@@ -1893,17 +1896,20 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
smi_handler = StoreHandler::TransitionToField( smi_handler = StoreHandler::TransitionToField(
isolate(), descriptor, index, representation, extend_storage); 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_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap()); DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> validity_cell = Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) { 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); DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate()); validity_cell = handle(Smi::FromInt(0), isolate());
} }
...@@ -1919,7 +1925,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map, ...@@ -1919,7 +1925,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell); handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
handler_array->set(StoreHandler::kTransitionCellIndex, *transition_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); StoreHandler::kFirstPrototypeIndex);
return handler_array; return handler_array;
} }
......
...@@ -53,21 +53,35 @@ class PrototypeIterator { ...@@ -53,21 +53,35 @@ class PrototypeIterator {
if (where_to_start == kStartAtPrototype) Advance(); 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()), : isolate_(receiver_map->GetIsolate()),
object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()), object_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype()),
where_to_end_(END_AT_NULL), where_to_end_(where_to_end),
is_at_end_(object_->IsNull(isolate_)), 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()), : isolate_(receiver_map->GetIsolate()),
object_(NULL), object_(NULL),
handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(), handle_(receiver_map->GetPrototypeChainRootMap(isolate_)->prototype(),
isolate_), isolate_),
where_to_end_(END_AT_NULL), where_to_end_(where_to_end),
is_at_end_(handle_->IsNull(isolate_)), 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() {} ~PrototypeIterator() {}
......
// 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);
// 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);
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