Commit ab7e6df0 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[super ic] Fix more receiver vs lookup start object vs holder confusion

The actual fix is in LoadIC::ComputeHandler (checking
lookup_start_object == holder instead of receiver == holder) + the
LookupIterator changes for preserving lookup_start_object.

The rest is renaming / refactoring.

Bug: v8:9237, chromium:1127653
Change-Id: Ieef46fb46ababa79623951c48639429c5b552d2d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2414039
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70045}
parent 5b7cb7f4
...@@ -200,7 +200,8 @@ void AccessorAssembler::HandleLoadAccessor( ...@@ -200,7 +200,8 @@ void AccessorAssembler::HandleLoadAccessor(
// Context is stored either in data2 or data3 field depending on whether // Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not. // the access check is enabled for this handler or not.
TNode<MaybeObject> maybe_context = Select<MaybeObject>( TNode<MaybeObject> maybe_context = Select<MaybeObject>(
IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word), IsSetWord<LoadHandler::DoAccessCheckOnLookupStartObjectBits>(
handler_word),
[=] { return LoadHandlerDataField(handler, 3); }, [=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); }); [=] { return LoadHandlerDataField(handler, 2); });
...@@ -790,12 +791,14 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( ...@@ -790,12 +791,14 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
// generate a code that handles Code handlers. // generate a code that handles Code handlers.
// If |on_code_handler| is not provided, then only smi sub handler are // If |on_code_handler| is not provided, then only smi sub handler are
// expected. // expected.
// 3. Does access check on receiver if ICHandler::DoAccessCheckOnReceiverBits // 3. Does access check on lookup start object if
// bit is set in the smi handler. // ICHandler::DoAccessCheckOnLookupStartObjectBits bit is set in the smi
// 4. Does dictionary lookup on receiver if ICHandler::LookupOnReceiverBits bit // handler.
// is set in the smi handler. If |on_found_on_receiver| is provided then // 4. Does dictionary lookup on receiver if
// it calls it to generate a code that handles the "found on receiver case" // ICHandler::LookupOnLookupStartObjectBits bit is set in the smi handler. If
// or just misses if the |on_found_on_receiver| is not provided. // |on_found_on_lookup_start_object| is provided then it calls it to
// generate a code that handles the "found on receiver case" or just misses
// if the |on_found_on_lookup_start_object| is not provided.
// 5. Falls through in a case of a smi handler which is returned from this // 5. Falls through in a case of a smi handler which is returned from this
// function (tagged!). // function (tagged!).
// TODO(ishell): Remove templatezation once we move common bits from // TODO(ishell): Remove templatezation once we move common bits from
...@@ -804,8 +807,8 @@ template <typename ICHandler, typename ICParameters> ...@@ -804,8 +807,8 @@ template <typename ICHandler, typename ICParameters>
TNode<Object> AccessorAssembler::HandleProtoHandler( TNode<Object> AccessorAssembler::HandleProtoHandler(
const ICParameters* p, TNode<DataHandler> handler, const ICParameters* p, TNode<DataHandler> handler,
const OnCodeHandler& on_code_handler, const OnCodeHandler& on_code_handler,
const OnFoundOnReceiver& on_found_on_receiver, Label* miss, const OnFoundOnLookupStartObject& on_found_on_lookup_start_object,
ICMode ic_mode) { Label* miss, ICMode ic_mode) {
// //
// Check prototype validity cell. // Check prototype validity cell.
// //
...@@ -835,21 +838,24 @@ TNode<Object> AccessorAssembler::HandleProtoHandler( ...@@ -835,21 +838,24 @@ TNode<Object> AccessorAssembler::HandleProtoHandler(
// because in the former case the validity cell check guards modifications // because in the former case the validity cell check guards modifications
// of the global object and the latter is not applicable to the global // of the global object and the latter is not applicable to the global
// object. // object.
int mask = ICHandler::LookupOnReceiverBits::kMask | int mask = ICHandler::LookupOnLookupStartObjectBits::kMask |
ICHandler::DoAccessCheckOnReceiverBits::kMask; ICHandler::DoAccessCheckOnLookupStartObjectBits::kMask;
if (ic_mode == ICMode::kGlobalIC) { if (ic_mode == ICMode::kGlobalIC) {
CSA_ASSERT(this, IsClearWord(handler_flags, mask)); CSA_ASSERT(this, IsClearWord(handler_flags, mask));
} else { } else {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode); DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
Label done(this), if_do_access_check(this), if_lookup_on_receiver(this); Label done(this), if_do_access_check(this),
if_lookup_on_lookup_start_object(this);
GotoIf(IsClearWord(handler_flags, mask), &done); GotoIf(IsClearWord(handler_flags, mask), &done);
// Only one of the bits can be set at a time. // Only one of the bits can be set at a time.
CSA_ASSERT(this, CSA_ASSERT(this,
WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)), WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
IntPtrConstant(mask))); IntPtrConstant(mask)));
Branch(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags), Branch(
&if_do_access_check, &if_lookup_on_receiver); IsSetWord<typename ICHandler::DoAccessCheckOnLookupStartObjectBits>(
handler_flags),
&if_do_access_check, &if_lookup_on_lookup_start_object);
BIND(&if_do_access_check); BIND(&if_do_access_check);
{ {
...@@ -857,29 +863,39 @@ TNode<Object> AccessorAssembler::HandleProtoHandler( ...@@ -857,29 +863,39 @@ TNode<Object> AccessorAssembler::HandleProtoHandler(
CSA_ASSERT(this, IsWeakOrCleared(data2)); CSA_ASSERT(this, IsWeakOrCleared(data2));
TNode<Context> expected_native_context = TNode<Context> expected_native_context =
CAST(GetHeapObjectAssumeWeak(data2, miss)); CAST(GetHeapObjectAssumeWeak(data2, miss));
EmitAccessCheck(expected_native_context, p->context(), p->receiver(), EmitAccessCheck(expected_native_context, p->context(),
&done, miss); p->lookup_start_object(), &done, miss);
} }
// Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC BIND(&if_lookup_on_lookup_start_object);
// because prototype validity cell check already guards modifications of
// the global object.
BIND(&if_lookup_on_receiver);
{ {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode); // Assert that the LookupOnLookupStartObjectBits is never set for
CSA_ASSERT(this, Word32BinaryNot(HasInstanceType( // Load/StoreSuperIC case (which is when receiver !=
CAST(p->receiver()), JS_GLOBAL_OBJECT_TYPE))); // lookup_start_object). For the super IC case the lookup start object
// is guaranteed to be a prototype of a home object and thus the
// prototype validity cell check already guards modifications of the
// lookup start object.
CSA_ASSERT(this, TaggedEqual(p->receiver(), p->lookup_start_object()));
// Dictionary lookup on lookup start object is not necessary for
// Load/StoreGlobalIC (which is the only case when the
// lookup_start_object can be a JSGlobalObject) because prototype
// validity cell check already guards modifications of the global
// object.
CSA_ASSERT(this,
Word32BinaryNot(HasInstanceType(
CAST(p->lookup_start_object()), JS_GLOBAL_OBJECT_TYPE)));
TNode<NameDictionary> properties = TNode<NameDictionary> properties =
CAST(LoadSlowProperties(CAST(p->receiver()))); CAST(LoadSlowProperties(CAST(p->lookup_start_object())));
TVARIABLE(IntPtrT, var_name_index); TVARIABLE(IntPtrT, var_name_index);
Label found(this, &var_name_index); Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()),
&found, &var_name_index, &done); &found, &var_name_index, &done);
BIND(&found); BIND(&found);
{ {
if (on_found_on_receiver) { if (on_found_on_lookup_start_object) {
on_found_on_receiver(properties, var_name_index.value()); on_found_on_lookup_start_object(properties, var_name_index.value());
} else { } else {
Goto(miss); Goto(miss);
} }
...@@ -901,7 +917,7 @@ void AccessorAssembler::HandleLoadICProtoHandler( ...@@ -901,7 +917,7 @@ void AccessorAssembler::HandleLoadICProtoHandler(
p, handler, p, handler,
// Code sub-handlers are not expected in LoadICs, so no |on_code_handler|. // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
nullptr, nullptr,
// on_found_on_receiver // on_found_on_lookup_start_object
[=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) { [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
if (access_mode == LoadAccessMode::kHas) { if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant()); exit_point->Return(TrueConstant());
...@@ -1542,7 +1558,7 @@ void AccessorAssembler::HandleStoreICProtoHandler( ...@@ -1542,7 +1558,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
TNode<Object> smi_handler = HandleProtoHandler<StoreHandler>( TNode<Object> smi_handler = HandleProtoHandler<StoreHandler>(
p, handler, on_code_handler, p, handler, on_code_handler,
// on_found_on_receiver // on_found_on_lookup_start_object
[=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) { [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
TNode<Uint32T> details = LoadDetailsByKeyIndex(properties, name_index); TNode<Uint32T> details = LoadDetailsByKeyIndex(properties, name_index);
// Check that the property is a writable data property (no accessor). // Check that the property is a writable data property (no accessor).
...@@ -1618,7 +1634,8 @@ void AccessorAssembler::HandleStoreICProtoHandler( ...@@ -1618,7 +1634,8 @@ void AccessorAssembler::HandleStoreICProtoHandler(
{ {
// This is a case of "transitioning store" to a dictionary mode object // This is a case of "transitioning store" to a dictionary mode object
// when the property does not exist. The "existing property" case is // when the property does not exist. The "existing property" case is
// covered above by LookupOnReceiver bit handling of the smi handler. // covered above by LookupOnLookupStartObject bit handling of the smi
// handler.
Label slow(this); Label slow(this);
TNode<Map> receiver_map = LoadMap(CAST(p->receiver())); TNode<Map> receiver_map = LoadMap(CAST(p->receiver()));
InvalidateValidityCellIfPrototype(receiver_map); InvalidateValidityCellIfPrototype(receiver_map);
...@@ -1648,7 +1665,8 @@ void AccessorAssembler::HandleStoreICProtoHandler( ...@@ -1648,7 +1665,8 @@ void AccessorAssembler::HandleStoreICProtoHandler(
// Context is stored either in data2 or data3 field depending on whether // Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not. // the access check is enabled for this handler or not.
TNode<MaybeObject> maybe_context = Select<MaybeObject>( TNode<MaybeObject> maybe_context = Select<MaybeObject>(
IsSetWord32<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word), IsSetWord32<StoreHandler::DoAccessCheckOnLookupStartObjectBits>(
handler_word),
[=] { return LoadHandlerDataField(handler, 3); }, [=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); }); [=] { return LoadHandlerDataField(handler, 2); });
......
...@@ -199,6 +199,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -199,6 +199,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<TaggedIndex> slot() const { return slot_; } TNode<TaggedIndex> slot() const { return slot_; }
TNode<HeapObject> vector() const { return vector_; } TNode<HeapObject> vector() const { return vector_; }
TNode<Object> lookup_start_object() const { return receiver(); }
bool receiver_is_null() const { return !receiver_.has_value(); } bool receiver_is_null() const { return !receiver_.has_value(); }
private: private:
...@@ -415,15 +417,15 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -415,15 +417,15 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
// Low-level helpers. // Low-level helpers.
using OnCodeHandler = std::function<void(TNode<Code> code_handler)>; using OnCodeHandler = std::function<void(TNode<Code> code_handler)>;
using OnFoundOnReceiver = std::function<void(TNode<NameDictionary> properties, using OnFoundOnLookupStartObject = std::function<void(
TNode<IntPtrT> name_index)>; TNode<NameDictionary> properties, TNode<IntPtrT> name_index)>;
template <typename ICHandler, typename ICParameters> template <typename ICHandler, typename ICParameters>
TNode<Object> HandleProtoHandler( TNode<Object> HandleProtoHandler(
const ICParameters* p, TNode<DataHandler> handler, const ICParameters* p, TNode<DataHandler> handler,
const OnCodeHandler& on_code_handler, const OnCodeHandler& on_code_handler,
const OnFoundOnReceiver& on_found_on_receiver, Label* miss, const OnFoundOnLookupStartObject& on_found_on_lookup_start_object,
ICMode ic_mode); Label* miss, ICMode ic_mode);
void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word, void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word,
TNode<JSObject> holder, TNode<JSObject> holder,
......
...@@ -27,16 +27,20 @@ Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler, ...@@ -27,16 +27,20 @@ Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler,
// Load/StoreHandler to the base class. // Load/StoreHandler to the base class.
template <typename ICHandler, bool fill_handler = true> template <typename ICHandler, bool fill_handler = true>
int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler, int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
Handle<Smi>* smi_handler, Handle<Map> receiver_map, Handle<Smi>* smi_handler,
Handle<Map> lookup_start_object_map,
Handle<JSReceiver> holder, MaybeObjectHandle data1, Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2) { MaybeObjectHandle maybe_data2) {
int data_size = 1; int data_size = 1;
// Holder-is-receiver case itself does not add entries unless there is an // Holder-is-receiver case itself does not add entries unless there is an
// optional data2 value provided. // optional data2 value provided.
if (receiver_map->IsPrimitiveMap() || DCHECK_IMPLIES(lookup_start_object_map->IsJSGlobalObjectMap(),
receiver_map->is_access_check_needed()) { lookup_start_object_map->is_prototype_map());
DCHECK(!receiver_map->IsJSGlobalObjectMap());
if (lookup_start_object_map->IsPrimitiveMap() ||
lookup_start_object_map->is_access_check_needed()) {
DCHECK(!lookup_start_object_map->IsJSGlobalObjectMap());
// The validity cell check for primitive and global proxy receivers does // The validity cell check for primitive and global proxy receivers does
// not guarantee that certain native context ever had access to other // not guarantee that certain native context ever had access to other
// native context. However, a handler created for one native context could // native context. However, a handler created for one native context could
...@@ -47,17 +51,23 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler, ...@@ -47,17 +51,23 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
Handle<Context> native_context = isolate->native_context(); Handle<Context> native_context = isolate->native_context();
handler->set_data2(HeapObjectReference::Weak(*native_context)); handler->set_data2(HeapObjectReference::Weak(*native_context));
} else { } else {
// Enable access checks on receiver. // Enable access checks on the lookup start object.
using Bit = typename ICHandler::DoAccessCheckOnReceiverBits; *smi_handler = SetBitFieldValue<
*smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true); typename ICHandler::DoAccessCheckOnLookupStartObjectBits>(
isolate, *smi_handler, true);
} }
data_size++; data_size++;
} else if (receiver_map->is_dictionary_map() && } else if (lookup_start_object_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) { !lookup_start_object_map->is_prototype_map()) {
if (!fill_handler) { if (!fill_handler) {
// Enable lookup on receiver. // The lookup on lookup start object is only required for dictionary mode
using Bit = typename ICHandler::LookupOnReceiverBits; // objects which are not prototypes. When we start lookup from a prototype
*smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true); // object, the prototype validity cell guards modifications of the lookup
// start object. This includes both Load/StoreGlobalIC and
// Load/StoreSuperIC cases.
*smi_handler =
SetBitFieldValue<typename ICHandler::LookupOnLookupStartObjectBits>(
isolate, *smi_handler, true);
} }
} }
if (fill_handler) { if (fill_handler) {
...@@ -80,40 +90,39 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler, ...@@ -80,40 +90,39 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
} }
// Returns 0 if the validity cell check is enough to ensure that the // Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change. // prototype chain from |lookup_start_object_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is // If the |holder| is an empty handle then the full prototype chain is
// checked. // checked.
// 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.
template <typename ICHandler> template <typename ICHandler>
int GetHandlerDataSize(Isolate* isolate, Handle<Smi>* smi_handler, int GetHandlerDataSize(Isolate* isolate, Handle<Smi>* smi_handler,
Handle<Map> receiver_map, Handle<JSReceiver> holder, Handle<Map> lookup_start_object_map,
MaybeObjectHandle data1, Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) { MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
DCHECK_NOT_NULL(smi_handler); DCHECK_NOT_NULL(smi_handler);
return InitPrototypeChecksImpl<ICHandler, false>(isolate, Handle<ICHandler>(), return InitPrototypeChecksImpl<ICHandler, false>(
smi_handler, receiver_map, isolate, Handle<ICHandler>(), smi_handler, lookup_start_object_map,
holder, data1, maybe_data2); holder, data1, maybe_data2);
} }
template <typename ICHandler> template <typename ICHandler>
void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler, void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler,
Handle<Map> receiver_map, Handle<JSReceiver> holder, Handle<Map> lookup_start_object_map,
MaybeObjectHandle data1, Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) { MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
InitPrototypeChecksImpl<ICHandler, true>( InitPrototypeChecksImpl<ICHandler, true>(isolate, handler, nullptr,
isolate, handler, nullptr, receiver_map, holder, data1, maybe_data2); lookup_start_object_map, holder,
data1, maybe_data2);
} }
} // namespace } // namespace
// static // static
Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate, Handle<Object> LoadHandler::LoadFromPrototype(
Handle<Map> receiver_map, Isolate* isolate, Handle<Map> lookup_start_object_map,
Handle<JSReceiver> holder, Handle<JSReceiver> holder, Handle<Smi> smi_handler,
Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1, MaybeObjectHandle maybe_data2) {
MaybeObjectHandle maybe_data1,
MaybeObjectHandle maybe_data2) {
MaybeObjectHandle data1; MaybeObjectHandle data1;
if (maybe_data1.is_null()) { if (maybe_data1.is_null()) {
data1 = MaybeObjectHandle::Weak(holder); data1 = MaybeObjectHandle::Weak(holder);
...@@ -121,44 +130,48 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate, ...@@ -121,44 +130,48 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
data1 = maybe_data1; data1 = maybe_data1;
} }
int data_size = GetHandlerDataSize<LoadHandler>( int data_size = GetHandlerDataSize<LoadHandler>(isolate, &smi_handler,
isolate, &smi_handler, receiver_map, holder, data1, maybe_data2); lookup_start_object_map,
holder, data1, maybe_data2);
Handle<Object> validity_cell = Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate); lookup_start_object_map, isolate);
Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size); Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
handler->set_smi_handler(*smi_handler); handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell); handler->set_validity_cell(*validity_cell);
InitPrototypeChecks(isolate, handler, receiver_map, holder, data1, InitPrototypeChecks(isolate, handler, lookup_start_object_map, holder, data1,
maybe_data2); maybe_data2);
return handler; return handler;
} }
// static // static
Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate, Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<Map> receiver_map, Handle<Map> lookup_start_object_map,
const MaybeObjectHandle& holder, const MaybeObjectHandle& holder,
Handle<Smi> smi_handler) { Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle, means full prototype chain lookup. Handle<JSReceiver> end; // null handle, means full prototype chain lookup.
MaybeObjectHandle data1 = holder; MaybeObjectHandle data1 = holder;
int data_size = GetHandlerDataSize<LoadHandler>(isolate, &smi_handler, int data_size = GetHandlerDataSize<LoadHandler>(
receiver_map, end, data1); isolate, &smi_handler, lookup_start_object_map, end, data1);
Handle<Object> validity_cell = Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate); lookup_start_object_map, isolate);
if (validity_cell->IsSmi()) { if (validity_cell->IsSmi()) {
DCHECK_EQ(1, data_size); DCHECK_EQ(1, data_size);
// Lookup on receiver isn't supported in case of a simple smi handler. // Lookup on lookup start object isn't supported in case of a simple smi
if (!LookupOnReceiverBits::decode(smi_handler->value())) return smi_handler; // handler.
if (!LookupOnLookupStartObjectBits::decode(smi_handler->value())) {
return smi_handler;
}
} }
Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size); Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
handler->set_smi_handler(*smi_handler); handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell); handler->set_validity_cell(*validity_cell);
InitPrototypeChecks(isolate, handler, receiver_map, end, data1); InitPrototypeChecks(isolate, handler, lookup_start_object_map, end, data1);
return handler; return handler;
} }
...@@ -247,7 +260,8 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate, ...@@ -247,7 +260,8 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
DCHECK(!transition_map->IsJSGlobalObjectMap()); DCHECK(!transition_map->IsJSGlobalObjectMap());
Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0); Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
// Store normal with enabled lookup on receiver. // Store normal with enabled lookup on receiver.
int config = KindBits::encode(kNormal) | LookupOnReceiverBits::encode(true); int config =
KindBits::encode(kNormal) | LookupOnLookupStartObjectBits::encode(true);
handler->set_smi_handler(Smi::FromInt(config)); handler->set_smi_handler(Smi::FromInt(config));
handler->set_validity_cell(*validity_cell); handler->set_validity_cell(*validity_cell);
return MaybeObjectHandle(handler); return MaybeObjectHandle(handler);
......
...@@ -50,15 +50,17 @@ class LoadHandler final : public DataHandler { ...@@ -50,15 +50,17 @@ class LoadHandler final : public DataHandler {
}; };
using KindBits = base::BitField<Kind, 0, 4>; using KindBits = base::BitField<Kind, 0, 4>;
// Defines whether access rights check should be done on receiver object. // Defines whether access rights check should be done on lookup start object.
// Applicable to named property kinds only when loading value from prototype // Applicable to named property kinds only when loading value from prototype
// chain. Ignored when loading from holder. // chain. Ignored when loading from lookup start object.
using DoAccessCheckOnReceiverBits = KindBits::Next<bool, 1>; using DoAccessCheckOnLookupStartObjectBits = KindBits::Next<bool, 1>;
// Defines whether a lookup should be done on receiver object before // Defines whether a lookup should be done on lookup start object before
// proceeding to the prototype chain. Applicable to named property kinds only // proceeding to the prototype chain. Applicable to named property kinds only
// when loading value from prototype chain. Ignored when loading from holder. // when loading value from prototype chain. Ignored when loading from lookup
using LookupOnReceiverBits = DoAccessCheckOnReceiverBits::Next<bool, 1>; // start object.
using LookupOnLookupStartObjectBits =
DoAccessCheckOnLookupStartObjectBits::Next<bool, 1>;
// //
// Encoding when KindBits contains kForConstants. // Encoding when KindBits contains kForConstants.
...@@ -66,14 +68,14 @@ class LoadHandler final : public DataHandler { ...@@ -66,14 +68,14 @@ class LoadHandler final : public DataHandler {
// Index of a value entry in the descriptor array. // Index of a value entry in the descriptor array.
using DescriptorBits = using DescriptorBits =
LookupOnReceiverBits::Next<unsigned, kDescriptorIndexBitCount>; LookupOnLookupStartObjectBits::Next<unsigned, kDescriptorIndexBitCount>;
// Make sure we don't overflow the smi. // Make sure we don't overflow the smi.
STATIC_ASSERT(DescriptorBits::kLastUsedBit < kSmiValueSize); STATIC_ASSERT(DescriptorBits::kLastUsedBit < kSmiValueSize);
// //
// Encoding when KindBits contains kField. // Encoding when KindBits contains kField.
// //
using IsInobjectBits = LookupOnReceiverBits::Next<bool, 1>; using IsInobjectBits = LookupOnLookupStartObjectBits::Next<bool, 1>;
using IsDoubleBits = IsInobjectBits::Next<bool, 1>; using IsDoubleBits = IsInobjectBits::Next<bool, 1>;
// +1 here is to cover all possible JSObject header sizes. // +1 here is to cover all possible JSObject header sizes.
using FieldIndexBits = using FieldIndexBits =
...@@ -85,7 +87,7 @@ class LoadHandler final : public DataHandler { ...@@ -85,7 +87,7 @@ class LoadHandler final : public DataHandler {
// //
// Encoding when KindBits contains kElement or kIndexedString. // Encoding when KindBits contains kElement or kIndexedString.
// //
using AllowOutOfBoundsBits = LookupOnReceiverBits::Next<bool, 1>; using AllowOutOfBoundsBits = LookupOnLookupStartObjectBits::Next<bool, 1>;
// //
// Encoding when KindBits contains kElement. // Encoding when KindBits contains kElement.
...@@ -99,8 +101,9 @@ class LoadHandler final : public DataHandler { ...@@ -99,8 +101,9 @@ class LoadHandler final : public DataHandler {
// //
// Encoding when KindBits contains kModuleExport. // Encoding when KindBits contains kModuleExport.
// //
using ExportsIndexBits = LookupOnReceiverBits::Next< using ExportsIndexBits = LookupOnLookupStartObjectBits::Next<
unsigned, kSmiValueSize - LookupOnReceiverBits::kLastUsedBit - 1>; unsigned,
kSmiValueSize - LookupOnLookupStartObjectBits::kLastUsedBit - 1>;
// Decodes kind from Smi-handler. // Decodes kind from Smi-handler.
static inline Kind GetHandlerKind(Smi smi_handler); static inline Kind GetHandlerKind(Smi smi_handler);
...@@ -213,20 +216,21 @@ class StoreHandler final : public DataHandler { ...@@ -213,20 +216,21 @@ class StoreHandler final : public DataHandler {
// Applicable to kGlobalProxy, kProxy kinds. // Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object. // Defines whether access rights check should be done on lookup start object.
using DoAccessCheckOnReceiverBits = KindBits::Next<bool, 1>; using DoAccessCheckOnLookupStartObjectBits = KindBits::Next<bool, 1>;
// Defines whether a lookup should be done on receiver object before // Defines whether a lookup should be done on lookup start object before
// proceeding to the prototype chain. Applicable to named property kinds only // proceeding to the prototype chain. Applicable to named property kinds only
// when storing through prototype chain. Ignored when storing to holder. // when storing through prototype chain. Ignored when storing to holder.
using LookupOnReceiverBits = DoAccessCheckOnReceiverBits::Next<bool, 1>; using LookupOnLookupStartObjectBits =
DoAccessCheckOnLookupStartObjectBits::Next<bool, 1>;
// Applicable to kField, kTransitionToField and kTransitionToConstant // Applicable to kField, kTransitionToField and kTransitionToConstant
// kinds. // kinds.
// Index of a value entry in the descriptor array. // Index of a value entry in the descriptor array.
using DescriptorBits = using DescriptorBits =
LookupOnReceiverBits::Next<unsigned, kDescriptorIndexBitCount>; LookupOnLookupStartObjectBits::Next<unsigned, kDescriptorIndexBitCount>;
// //
// Encodes the bits when StoreSlow contains KeyedAccessStoreMode. // Encodes the bits when StoreSlow contains KeyedAccessStoreMode.
......
...@@ -16,11 +16,12 @@ ...@@ -16,11 +16,12 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void IC::update_receiver_map(Handle<Object> receiver) { void IC::update_lookup_start_object_map(Handle<Object> object) {
if (receiver->IsSmi()) { if (object->IsSmi()) {
receiver_map_ = isolate_->factory()->heap_number_map(); lookup_start_object_map_ = isolate_->factory()->heap_number_map();
} else { } else {
receiver_map_ = handle(HeapObject::cast(*receiver).map(), isolate_); lookup_start_object_map_ =
handle(HeapObject::cast(*object).map(), isolate_);
} }
} }
......
...@@ -97,7 +97,7 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state, ...@@ -97,7 +97,7 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
State new_state) { State new_state) {
if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return; if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return;
Handle<Map> map = receiver_map(); // Might be empty. Handle<Map> map = lookup_start_object_map(); // Might be empty.
const char* modifier = ""; const char* modifier = "";
if (state() == NO_FEEDBACK) { if (state() == NO_FEEDBACK) {
...@@ -217,7 +217,8 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) { ...@@ -217,7 +217,8 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// monomorphic. // monomorphic.
if (IsGlobalIC()) return true; if (IsGlobalIC()) return true;
MaybeObjectHandle maybe_handler = nexus()->FindHandlerForMap(receiver_map()); MaybeObjectHandle maybe_handler =
nexus()->FindHandlerForMap(lookup_start_object_map());
// The current map wasn't handled yet. There's no reason to stay monomorphic, // The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or // *unless* we're moving from a deprecated map to its replacement, or
...@@ -225,13 +226,13 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) { ...@@ -225,13 +226,13 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// TODO(verwaest): Check if the current map is actually what the old map // TODO(verwaest): Check if the current map is actually what the old map
// would transition to. // would transition to.
if (maybe_handler.is_null()) { if (maybe_handler.is_null()) {
if (!receiver_map()->IsJSObjectMap()) return false; if (!lookup_start_object_map()->IsJSObjectMap()) return false;
Map first_map = FirstTargetMap(); Map first_map = FirstTargetMap();
if (first_map.is_null()) return false; if (first_map.is_null()) return false;
Handle<Map> old_map(first_map, isolate()); Handle<Map> old_map(first_map, isolate());
if (old_map->is_deprecated()) return true; if (old_map->is_deprecated()) return true;
return IsMoreGeneralElementsKindTransition(old_map->elements_kind(), return IsMoreGeneralElementsKindTransition(
receiver_map()->elements_kind()); old_map->elements_kind(), lookup_start_object_map()->elements_kind());
} }
return true; return true;
...@@ -248,12 +249,12 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) { ...@@ -248,12 +249,12 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) {
return true; return true;
} }
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { void IC::UpdateState(Handle<Object> lookup_start_object, Handle<Object> name) {
if (state() == NO_FEEDBACK) return; if (state() == NO_FEEDBACK) return;
update_receiver_map(receiver); update_lookup_start_object_map(lookup_start_object);
if (!name->IsString()) return; if (!name->IsString()) return;
if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
if (receiver->IsNullOrUndefined(isolate())) return; if (lookup_start_object->IsNullOrUndefined(isolate())) return;
// Remove the target from the code cache if it became invalid // Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it // because of changes in the prototype chain to avoid hitting it
...@@ -399,7 +400,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name, ...@@ -399,7 +400,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name,
if (use_ic) { if (use_ic) {
// Ensure the IC state progresses. // Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
update_receiver_map(object); update_lookup_start_object_map(object);
SetCache(name, LoadHandler::LoadSlow(isolate())); SetCache(name, LoadHandler::LoadSlow(isolate()));
TraceIC("LoadIC", name); TraceIC("LoadIC", name);
} }
...@@ -421,11 +422,10 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name, ...@@ -421,11 +422,10 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name,
if (MigrateDeprecated(isolate(), object)) use_ic = false; if (MigrateDeprecated(isolate(), object)) use_ic = false;
JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate()); JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
update_receiver_map(object); update_lookup_start_object_map(object);
LookupIterator::Key key(isolate(), name); LookupIterator::Key key(isolate(), name);
LookupIterator it = LookupIterator it = LookupIterator(isolate(), receiver, key, object);
LookupIterator::LookupWithReceiver(isolate(), receiver, key, object);
// Named lookup in the object. // Named lookup in the object.
LookupForRead(&it, IsAnyHas()); LookupForRead(&it, IsAnyHas());
...@@ -570,7 +570,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, ...@@ -570,7 +570,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
if (is_keyed() && state() != RECOMPUTE_HANDLER) { if (is_keyed() && state() != RECOMPUTE_HANDLER) {
if (nexus()->GetName() != *name) return false; if (nexus()->GetName() != *name) return false;
} }
Handle<Map> map = receiver_map(); Handle<Map> map = lookup_start_object_map();
std::vector<MapAndHandler> maps_and_handlers; std::vector<MapAndHandler> maps_and_handlers;
maps_and_handlers.reserve(FLAG_max_valid_polymorphic_map_count); maps_and_handlers.reserve(FLAG_max_valid_polymorphic_map_count);
...@@ -642,7 +642,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, ...@@ -642,7 +642,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
number_of_valid_maps++; number_of_valid_maps++;
if (number_of_valid_maps == 1) { if (number_of_valid_maps == 1) {
ConfigureVectorState(name, receiver_map(), handler); ConfigureVectorState(name, lookup_start_object_map(), handler);
} else { } else {
if (is_keyed() && nexus()->GetName() != *name) return false; if (is_keyed() && nexus()->GetName() != *name) return false;
if (handler_to_overwrite >= 0) { if (handler_to_overwrite >= 0) {
...@@ -664,7 +664,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, ...@@ -664,7 +664,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler, void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
Handle<Name> name) { Handle<Name> name) {
DCHECK(IsHandler(*handler)); DCHECK(IsHandler(*handler));
ConfigureVectorState(name, receiver_map(), handler); ConfigureVectorState(name, lookup_start_object_map(), handler);
} }
void IC::CopyICToMegamorphicCache(Handle<Name> name) { void IC::CopyICToMegamorphicCache(Handle<Name> name) {
...@@ -721,7 +721,7 @@ void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) { ...@@ -721,7 +721,7 @@ void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) {
ConfigureVectorState(MEGAMORPHIC, name); ConfigureVectorState(MEGAMORPHIC, name);
V8_FALLTHROUGH; V8_FALLTHROUGH;
case MEGAMORPHIC: case MEGAMORPHIC:
UpdateMegamorphicCache(receiver_map(), name, handler); UpdateMegamorphicCache(lookup_start_object_map(), name, handler);
// Indicate that we've handled this case. // Indicate that we've handled this case.
vector_set_ = true; vector_set_ = true;
break; break;
...@@ -738,7 +738,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { ...@@ -738,7 +738,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate()); Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
code = LoadHandler::LoadFullChain( code = LoadHandler::LoadFullChain(
isolate(), receiver_map(), isolate(), lookup_start_object_map(),
MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler); MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
} else if (IsLoadGlobalIC() && lookup->state() == LookupIterator::JSPROXY) { } else if (IsLoadGlobalIC() && lookup->state() == LookupIterator::JSPROXY) {
// If there is proxy just install the slow stub since we need to call the // If there is proxy just install the slow stub since we need to call the
...@@ -746,8 +746,8 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { ...@@ -746,8 +746,8 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
// handle this case. // handle this case.
Handle<Smi> slow_handler = LoadHandler::LoadSlow(isolate()); Handle<Smi> slow_handler = LoadHandler::LoadSlow(isolate());
Handle<JSProxy> holder = lookup->GetHolder<JSProxy>(); Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
code = LoadHandler::LoadFromPrototype(isolate(), receiver_map(), holder, code = LoadHandler::LoadFromPrototype(isolate(), lookup_start_object_map(),
slow_handler); holder, slow_handler);
} else { } else {
if (IsLoadGlobalIC()) { if (IsLoadGlobalIC()) {
if (lookup->TryLookupCachedProperty()) { if (lookup->TryLookupCachedProperty()) {
...@@ -816,12 +816,13 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -816,12 +816,13 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
} }
} }
Handle<Map> map = receiver_map(); Handle<Map> map = lookup_start_object_map();
Handle<JSObject> holder; Handle<JSObject> holder;
bool receiver_is_holder; bool holder_is_lookup_start_object;
if (lookup->state() != LookupIterator::JSPROXY) { if (lookup->state() != LookupIterator::JSPROXY) {
holder = lookup->GetHolder<JSObject>(); holder = lookup->GetHolder<JSObject>();
receiver_is_holder = receiver.is_identical_to(holder); holder_is_lookup_start_object =
lookup->lookup_start_object().is_identical_to(holder);
} }
switch (lookup->state()) { switch (lookup->state()) {
...@@ -830,7 +831,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -830,7 +831,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (holder->GetNamedInterceptor().non_masking()) { if (holder->GetNamedInterceptor().non_masking()) {
MaybeObjectHandle holder_ref(isolate()->factory()->null_value()); MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
if (!receiver_is_holder || IsLoadGlobalIC()) { if (!holder_is_lookup_start_object || IsLoadGlobalIC()) {
holder_ref = MaybeObjectHandle::Weak(holder); holder_ref = MaybeObjectHandle::Weak(holder);
} }
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
...@@ -838,7 +839,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -838,7 +839,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
smi_handler); smi_handler);
} }
if (receiver_is_holder) { if (holder_is_lookup_start_object) {
DCHECK(map->has_named_interceptor()); DCHECK(map->has_named_interceptor());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
return smi_handler; return smi_handler;
...@@ -852,7 +853,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -852,7 +853,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
case LookupIterator::ACCESSOR: { case LookupIterator::ACCESSOR: {
// Use simple field loads for some well-known callback properties. // Use simple field loads for some well-known callback properties.
// The method will only return true for absolute truths based on the // The method will only return true for absolute truths based on the
// receiver maps. // lookup start object maps.
FieldIndex index; FieldIndex index;
if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(), if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(),
&index)) { &index)) {
...@@ -926,7 +927,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -926,7 +927,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex()); LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
if (receiver_is_holder) return smi_handler; if (holder_is_lookup_start_object) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
} else if (holder->IsJSGlobalObject()) { } else if (holder->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
...@@ -938,7 +939,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -938,7 +939,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
smi_handler = LoadHandler::LoadNormal(isolate()); smi_handler = LoadHandler::LoadNormal(isolate());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
if (receiver_is_holder) return smi_handler; if (holder_is_lookup_start_object) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
} }
...@@ -959,7 +960,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -959,7 +960,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty( Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
isolate(), lookup->GetAccessorIndex()); isolate(), lookup->GetAccessorIndex());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH);
if (receiver_is_holder) return smi_handler; if (holder_is_lookup_start_object) return smi_handler;
TRACE_HANDLER_STATS(isolate(), TRACE_HANDLER_STATS(isolate(),
LoadIC_LoadNativeDataPropertyFromPrototypeDH); LoadIC_LoadNativeDataPropertyFromPrototypeDH);
return LoadHandler::LoadFromPrototype(isolate(), map, holder, return LoadHandler::LoadFromPrototype(isolate(), map, holder,
...@@ -982,7 +983,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -982,7 +983,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
smi_handler = LoadHandler::LoadNormal(isolate()); smi_handler = LoadHandler::LoadNormal(isolate());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
if (receiver_is_holder) return smi_handler; if (holder_is_lookup_start_object) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
} else if (lookup->IsElement(*holder)) { } else if (lookup->IsElement(*holder)) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
...@@ -993,11 +994,11 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -993,11 +994,11 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
smi_handler = smi_handler =
LoadHandler::LoadField(isolate(), field, map->elements_kind()); LoadHandler::LoadField(isolate(), field, map->elements_kind());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
if (receiver_is_holder) return smi_handler; if (holder_is_lookup_start_object) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
} }
if (lookup->constness() == PropertyConstness::kConst && if (lookup->constness() == PropertyConstness::kConst &&
!receiver_is_holder) { !holder_is_lookup_start_object) {
DCHECK(!lookup->is_dictionary_holder()); DCHECK(!lookup->is_dictionary_holder());
Handle<Object> value = lookup->GetDataValue(); Handle<Object> value = lookup->GetDataValue();
...@@ -1032,9 +1033,10 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1032,9 +1033,10 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
return LoadHandler::LoadNonExistent(isolate()); return LoadHandler::LoadNonExistent(isolate());
case LookupIterator::JSPROXY: { case LookupIterator::JSPROXY: {
Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>(); Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy); bool holder_proxy_is_lookup_start_object =
lookup->lookup_start_object().is_identical_to(holder_proxy);
Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate()); Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
if (receiver_is_holder_proxy) { if (holder_proxy_is_lookup_start_object) {
return smi_handler; return smi_handler;
} }
return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy, return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
...@@ -1442,7 +1444,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, ...@@ -1442,7 +1444,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
it->PrepareForDataProperty(value); it->PrepareForDataProperty(value);
// The previous receiver map might just have been deprecated, // The previous receiver map might just have been deprecated,
// so reload it. // so reload it.
update_receiver_map(receiver); update_lookup_start_object_map(receiver);
return true; return true;
} }
...@@ -1565,7 +1567,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, ...@@ -1565,7 +1567,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (use_ic) { if (use_ic) {
// Ensure the IC state progresses. // Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver); TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
update_receiver_map(object); update_lookup_start_object_map(object);
SetCache(name, StoreHandler::StoreSlow(isolate())); SetCache(name, StoreHandler::StoreSlow(isolate()));
TraceIC("StoreIC", name); TraceIC("StoreIC", name);
} }
...@@ -1635,7 +1637,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1635,7 +1637,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
if (store_target->IsJSGlobalObject()) { if (store_target->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
if (receiver_map()->IsJSGlobalObject()) { if (lookup_start_object_map()->IsJSGlobalObject()) {
DCHECK(IsStoreGlobalIC()); DCHECK(IsStoreGlobalIC());
#ifdef DEBUG #ifdef DEBUG
Handle<JSObject> holder = lookup->GetHolder<JSObject>(); Handle<JSObject> holder = lookup->GetHolder<JSObject>();
...@@ -1647,13 +1649,13 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1647,13 +1649,13 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate()); Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
Handle<Object> handler = StoreHandler::StoreThroughPrototype( Handle<Object> handler = StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), store_target, smi_handler, isolate(), lookup_start_object_map(), store_target, smi_handler,
MaybeObjectHandle::Weak(lookup->transition_cell())); MaybeObjectHandle::Weak(lookup->transition_cell()));
return MaybeObjectHandle(handler); return MaybeObjectHandle(handler);
} }
// Dictionary-to-fast transitions are not expected and not supported. // Dictionary-to-fast transitions are not expected and not supported.
DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(), DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(),
!receiver_map()->is_dictionary_map()); !lookup_start_object_map()->is_dictionary_map());
DCHECK(lookup->IsCacheableTransition()); DCHECK(lookup->IsCacheableTransition());
...@@ -1680,7 +1682,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1680,7 +1682,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
DCHECK(!info.getter().IsUndefined(isolate()) || DCHECK(!info.getter().IsUndefined(isolate()) ||
!info.query().IsUndefined(isolate())); !info.query().IsUndefined(isolate()));
Handle<Object> handler = StoreHandler::StoreThroughPrototype( Handle<Object> handler = StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, isolate(), lookup_start_object_map(), holder,
StoreHandler::StoreSlow(isolate())); StoreHandler::StoreSlow(isolate()));
return MaybeObjectHandle(handler); return MaybeObjectHandle(handler);
} }
...@@ -1712,7 +1714,8 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1712,7 +1714,8 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
} }
if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) { if (!AccessorInfo::IsCompatibleReceiverMap(info,
lookup_start_object_map())) {
set_slow_stub_reason("incompatible receiver type"); set_slow_stub_reason("incompatible receiver type");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
...@@ -1727,7 +1730,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1727,7 +1730,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), TRACE_HANDLER_STATS(isolate(),
StoreIC_StoreNativeDataPropertyOnPrototypeDH); StoreIC_StoreNativeDataPropertyOnPrototypeDH);
return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, smi_handler)); isolate(), lookup_start_object_map(), holder, smi_handler));
} else if (accessors->IsAccessorPair()) { } else if (accessors->IsAccessorPair()) {
Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
...@@ -1751,8 +1754,8 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1751,8 +1754,8 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
if (call_optimization.is_simple_api_call()) { if (call_optimization.is_simple_api_call()) {
if (call_optimization.IsCompatibleReceiver(receiver, holder)) { if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
CallOptimization::HolderLookup holder_lookup; CallOptimization::HolderLookup holder_lookup;
call_optimization.LookupHolderOfExpectedType(receiver_map(), call_optimization.LookupHolderOfExpectedType(
&holder_lookup); lookup_start_object_map(), &holder_lookup);
Handle<Smi> smi_handler = StoreHandler::StoreApiSetter( Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
isolate(), isolate(),
...@@ -1762,7 +1765,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1762,7 +1765,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
call_optimization.GetAccessorContext(holder->map()), isolate()); call_optimization.GetAccessorContext(holder->map()), isolate());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, smi_handler, isolate(), lookup_start_object_map(), holder, smi_handler,
MaybeObjectHandle::Weak(call_optimization.api_call_info()), MaybeObjectHandle::Weak(call_optimization.api_call_info()),
MaybeObjectHandle::Weak(context))); MaybeObjectHandle::Weak(context)));
} }
...@@ -1785,7 +1788,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1785,7 +1788,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH); TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH);
return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, smi_handler)); isolate(), lookup_start_object_map(), holder, smi_handler));
} }
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
...@@ -1844,7 +1847,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1844,7 +1847,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
Handle<JSReceiver>::cast(lookup->GetReceiver()); Handle<JSReceiver>::cast(lookup->GetReceiver());
Handle<JSProxy> holder = lookup->GetHolder<JSProxy>(); Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
return MaybeObjectHandle(StoreHandler::StoreProxy( return MaybeObjectHandle(StoreHandler::StoreProxy(
isolate(), receiver_map(), holder, receiver)); isolate(), lookup_start_object_map(), holder, receiver));
} }
case LookupIterator::INTEGER_INDEXED_EXOTIC: case LookupIterator::INTEGER_INDEXED_EXOTIC:
......
...@@ -37,8 +37,9 @@ class IC { ...@@ -37,8 +37,9 @@ class IC {
State state() const { return state_; } State state() const { return state_; }
// Compute the current IC state based on the target stub, receiver and name. // Compute the current IC state based on the target stub, lookup_start_object
void UpdateState(Handle<Object> receiver, Handle<Object> name); // and name.
void UpdateState(Handle<Object> lookup_start_object, Handle<Object> name);
bool RecomputeHandlerForName(Handle<Object> name); bool RecomputeHandlerForName(Handle<Object> name);
void MarkRecomputeHandler(Handle<Object> name) { void MarkRecomputeHandler(Handle<Object> name) {
...@@ -121,8 +122,8 @@ class IC { ...@@ -121,8 +122,8 @@ class IC {
} }
bool ShouldRecomputeHandler(Handle<String> name); bool ShouldRecomputeHandler(Handle<String> name);
Handle<Map> receiver_map() { return receiver_map_; } Handle<Map> lookup_start_object_map() { return lookup_start_object_map_; }
inline void update_receiver_map(Handle<Object> receiver); inline void update_lookup_start_object_map(Handle<Object> object);
void TargetMaps(MapHandles* list) { void TargetMaps(MapHandles* list) {
FindTargetMaps(); FindTargetMaps();
...@@ -152,7 +153,7 @@ class IC { ...@@ -152,7 +153,7 @@ class IC {
State old_state_; // For saving if we marked as prototype failure. State old_state_; // For saving if we marked as prototype failure.
State state_; State state_;
FeedbackSlotKind kind_; FeedbackSlotKind kind_;
Handle<Map> receiver_map_; Handle<Map> lookup_start_object_map_;
MapHandles target_maps_; MapHandles target_maps_;
bool target_maps_set_; bool target_maps_set_;
......
...@@ -20,67 +20,60 @@ namespace internal { ...@@ -20,67 +20,60 @@ namespace internal {
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, Configuration configuration) Handle<Name> name, Configuration configuration)
: LookupIterator(isolate, receiver, name, kInvalidIndex, : LookupIterator(isolate, receiver, name, kInvalidIndex, receiver,
GetRoot(isolate, receiver, kInvalidIndex), configuration) { configuration) {}
}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, Handle<JSReceiver> holder, Handle<Name> name,
Handle<Object> lookup_start_object,
Configuration configuration) Configuration configuration)
: LookupIterator(isolate, receiver, name, kInvalidIndex, holder, : LookupIterator(isolate, receiver, name, kInvalidIndex,
configuration) {} lookup_start_object, configuration) {}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
size_t index, Configuration configuration) size_t index, Configuration configuration)
: LookupIterator(isolate, receiver, Handle<Name>(), index, : LookupIterator(isolate, receiver, Handle<Name>(), index, receiver,
GetRoot(isolate, receiver, index), configuration) { configuration) {
DCHECK_NE(index, kInvalidIndex); DCHECK_NE(index, kInvalidIndex);
} }
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
size_t index, Handle<JSReceiver> holder, size_t index, Handle<Object> lookup_start_object,
Configuration configuration) Configuration configuration)
: LookupIterator(isolate, receiver, Handle<Name>(), index, holder, : LookupIterator(isolate, receiver, Handle<Name>(), index,
configuration) { lookup_start_object, configuration) {
DCHECK_NE(index, kInvalidIndex); DCHECK_NE(index, kInvalidIndex);
} }
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key, Configuration configuration) const Key& key, Configuration configuration)
: LookupIterator(isolate, receiver, key.name(), key.index(), : LookupIterator(isolate, receiver, key.name(), key.index(), receiver,
GetRoot(isolate, receiver, key.index()), configuration) {}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key, Handle<JSReceiver> holder,
Configuration configuration)
: LookupIterator(isolate, receiver, key.name(), key.index(), holder,
configuration) {} configuration) {}
LookupIterator LookupIterator::LookupWithReceiver(Isolate* isolate, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Object> receiver,
const Key& key, const Key& key,
Handle<Object> holder, Handle<Object> lookup_start_object,
Configuration configuration) { Configuration configuration)
return LookupIterator(isolate, receiver, key, : LookupIterator(isolate, receiver, key.name(), key.index(),
GetRoot(isolate, holder, key.index()), configuration); lookup_start_object, configuration) {}
}
// This private constructor is the central bottleneck that all the other // This private constructor is the central bottleneck that all the other
// constructors use. // constructors use.
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, size_t index, Handle<Name> name, size_t index,
Handle<JSReceiver> holder, Handle<Object> lookup_start_object,
Configuration configuration) Configuration configuration)
: configuration_(ComputeConfiguration(isolate, configuration, name)), : configuration_(ComputeConfiguration(isolate, configuration, name)),
isolate_(isolate), isolate_(isolate),
name_(name), name_(name),
receiver_(receiver), receiver_(receiver),
initial_holder_(holder), lookup_start_object_(lookup_start_object),
index_(index) { index_(index) {
if (IsElement()) { if (IsElement()) {
// If we're not looking at a TypedArray, we will need the key represented // If we're not looking at a TypedArray, we will need the key represented
// as an internalized string. // as an internalized string.
if (index_ > JSArray::kMaxArrayIndex && !holder->IsJSTypedArray()) { if (index_ > JSArray::kMaxArrayIndex &&
!lookup_start_object->IsJSTypedArray()) {
if (name_.is_null()) { if (name_.is_null()) {
name_ = isolate->factory()->SizeToString(index_); name_ = isolate->factory()->SizeToString(index_);
} }
...@@ -94,10 +87,10 @@ LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, ...@@ -94,10 +87,10 @@ LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
name_ = isolate->factory()->InternalizeName(name_); name_ = isolate->factory()->InternalizeName(name_);
#ifdef DEBUG #ifdef DEBUG
// Assert that the name is not an index. // Assert that the name is not an index.
// If we're not looking at the prototype chain and the initial holder is // If we're not looking at the prototype chain and the lookup start object
// not a typed array, then this means "array index", otherwise we need to // is not a typed array, then this means "array index", otherwise we need to
// ensure the full generality so that typed arrays are handled correctly. // ensure the full generality so that typed arrays are handled correctly.
if (!check_prototype_chain() && !holder->IsJSTypedArray()) { if (!check_prototype_chain() && !lookup_start_object->IsJSTypedArray()) {
uint32_t index; uint32_t index;
DCHECK(!name_->AsArrayIndex(&index)); DCHECK(!name_->AsArrayIndex(&index));
} else { } else {
...@@ -251,12 +244,12 @@ LookupIterator::Configuration LookupIterator::ComputeConfiguration( ...@@ -251,12 +244,12 @@ LookupIterator::Configuration LookupIterator::ComputeConfiguration(
// static // static
Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate, Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
Handle<Object> receiver, Handle<Object> lookup_start_object,
size_t index) { size_t index) {
if (receiver->IsJSReceiver(isolate)) { if (lookup_start_object->IsJSReceiver(isolate)) {
return Handle<JSReceiver>::cast(receiver); return Handle<JSReceiver>::cast(lookup_start_object);
} }
return GetRootForNonJSReceiver(isolate, receiver, index); return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
} }
template <class T> template <class T>
......
...@@ -49,18 +49,21 @@ LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, ...@@ -49,18 +49,21 @@ LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
name_(name), name_(name),
transition_(transition_map), transition_(transition_map),
receiver_(receiver), receiver_(receiver),
initial_holder_(GetRoot(isolate, receiver)), lookup_start_object_(receiver),
index_(kInvalidIndex) { index_(kInvalidIndex) {
holder_ = initial_holder_; holder_ = GetRoot(isolate, lookup_start_object_);
} }
template <bool is_element> template <bool is_element>
void LookupIterator::Start() { void LookupIterator::Start() {
// GetRoot might allocate if lookup_start_object_ is a string.
holder_ = GetRoot(isolate_, lookup_start_object_, index_);
{
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
has_property_ = false; has_property_ = false;
state_ = NOT_FOUND; state_ = NOT_FOUND;
holder_ = initial_holder_;
JSReceiver holder = *holder_; JSReceiver holder = *holder_;
Map map = holder.map(isolate_); Map map = holder.map(isolate_);
...@@ -69,6 +72,7 @@ void LookupIterator::Start() { ...@@ -69,6 +72,7 @@ void LookupIterator::Start() {
if (IsFound()) return; if (IsFound()) return;
NextInternal<is_element>(map, holder); NextInternal<is_element>(map, holder);
}
} }
template void LookupIterator::Start<true>(); template void LookupIterator::Start<true>();
...@@ -127,22 +131,25 @@ template void LookupIterator::RestartInternal<false>(InterceptorState); ...@@ -127,22 +131,25 @@ template void LookupIterator::RestartInternal<false>(InterceptorState);
// static // static
Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
Isolate* isolate, Handle<Object> receiver, size_t index) { Isolate* isolate, Handle<Object> lookup_start_object, size_t index) {
// Strings are the only objects with properties (only elements) directly on // Strings are the only objects with properties (only elements) directly on
// the wrapper. Hence we can skip generating the wrapper for all other cases. // the wrapper. Hence we can skip generating the wrapper for all other cases.
if (receiver->IsString(isolate) && if (lookup_start_object->IsString(isolate) &&
index < static_cast<size_t>(String::cast(*receiver).length())) { index <
static_cast<size_t>(String::cast(*lookup_start_object).length())) {
// TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
// context, ensuring that we don't leak it into JS? // context, ensuring that we don't leak it into JS?
Handle<JSFunction> constructor = isolate->string_function(); Handle<JSFunction> constructor = isolate->string_function();
Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
Handle<JSPrimitiveWrapper>::cast(result)->set_value(*receiver); Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
return result; return result;
} }
Handle<HeapObject> root( Handle<HeapObject> root(
receiver->GetPrototypeChainRootMap(isolate).prototype(isolate), isolate); lookup_start_object->GetPrototypeChainRootMap(isolate).prototype(isolate),
isolate);
if (root->IsNull(isolate)) { if (root->IsNull(isolate)) {
isolate->PushStackTraceAndDie(reinterpret_cast<void*>(receiver->ptr())); isolate->PushStackTraceAndDie(
reinterpret_cast<void*>(lookup_start_object->ptr()));
} }
return Handle<JSReceiver>::cast(root); return Handle<JSReceiver>::cast(root);
} }
......
...@@ -70,27 +70,21 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -70,27 +70,21 @@ class V8_EXPORT_PRIVATE LookupIterator final {
Handle<Name> name, Handle<Name> name,
Configuration configuration = DEFAULT); Configuration configuration = DEFAULT);
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, Handle<JSReceiver> holder, Handle<Name> name, Handle<Object> lookup_start_object,
Configuration configuration = DEFAULT); Configuration configuration = DEFAULT);
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index, inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
Configuration configuration = DEFAULT); Configuration configuration = DEFAULT);
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index, inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
Handle<JSReceiver> holder, Handle<Object> lookup_start_object,
Configuration configuration = DEFAULT); Configuration configuration = DEFAULT);
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key, Configuration configuration = DEFAULT); const Key& key, Configuration configuration = DEFAULT);
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
const Key& key, Handle<JSReceiver> holder, const Key& key, Handle<Object> lookup_start_object,
Configuration configuration = DEFAULT); Configuration configuration = DEFAULT);
// Usable for cases where "holder" is not necessarily a JSReceiver (a separate
// overloaded constructor is not possible).
static inline LookupIterator LookupWithReceiver(
Isolate* isolate, Handle<Object> receiver, const Key& key,
Handle<Object> holder, Configuration configuration = DEFAULT);
void Restart() { void Restart() {
InterceptorState state = InterceptorState::kUninitialized; InterceptorState state = InterceptorState::kUninitialized;
IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state); IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
...@@ -134,6 +128,8 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -134,6 +128,8 @@ class V8_EXPORT_PRIVATE LookupIterator final {
template <class T> template <class T>
inline Handle<T> GetHolder() const; inline Handle<T> GetHolder() const;
Handle<Object> lookup_start_object() const { return lookup_start_object_; }
bool HolderIsReceiver() const; bool HolderIsReceiver() const;
bool HolderIsReceiverOrHiddenPrototype() const; bool HolderIsReceiverOrHiddenPrototype() const;
...@@ -202,7 +198,8 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -202,7 +198,8 @@ class V8_EXPORT_PRIVATE LookupIterator final {
inline LookupIterator(Isolate* isolate, Handle<Object> receiver, inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, size_t index, Handle<Name> name, size_t index,
Handle<JSReceiver> holder, Configuration configuration); Handle<Object> lookup_start_object,
Configuration configuration);
// For |ForTransitionHandler|. // For |ForTransitionHandler|.
LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
...@@ -267,9 +264,10 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -267,9 +264,10 @@ class V8_EXPORT_PRIVATE LookupIterator final {
Handle<Name> name); Handle<Name> name);
static Handle<JSReceiver> GetRootForNonJSReceiver( static Handle<JSReceiver> GetRootForNonJSReceiver(
Isolate* isolate, Handle<Object> receiver, size_t index = kInvalidIndex); Isolate* isolate, Handle<Object> lookup_start_object,
size_t index = kInvalidIndex);
static inline Handle<JSReceiver> GetRoot(Isolate* isolate, static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
Handle<Object> receiver, Handle<Object> lookup_start_object,
size_t index = kInvalidIndex); size_t index = kInvalidIndex);
State NotFound(JSReceiver const holder) const; State NotFound(JSReceiver const holder) const;
...@@ -286,7 +284,7 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -286,7 +284,7 @@ class V8_EXPORT_PRIVATE LookupIterator final {
Handle<Object> transition_; Handle<Object> transition_;
const Handle<Object> receiver_; const Handle<Object> receiver_;
Handle<JSReceiver> holder_; Handle<JSReceiver> holder_;
const Handle<JSReceiver> initial_holder_; const Handle<Object> lookup_start_object_;
const size_t index_; const size_t index_;
InternalIndex number_ = InternalIndex::NotFound(); InternalIndex number_ = InternalIndex::NotFound();
}; };
......
...@@ -39,8 +39,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, ...@@ -39,8 +39,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
bool success = false; bool success = false;
LookupIterator::Key lookup_key(isolate, key, &success); LookupIterator::Key lookup_key(isolate, key, &success);
if (!success) return MaybeHandle<Object>(); if (!success) return MaybeHandle<Object>();
LookupIterator it = LookupIterator it = LookupIterator(isolate, receiver, lookup_key, holder);
LookupIterator::LookupWithReceiver(isolate, receiver, lookup_key, holder);
MaybeHandle<Object> result = Object::GetProperty(&it); MaybeHandle<Object> result = Object::GetProperty(&it);
if (is_found) *is_found = it.IsFound(); if (is_found) *is_found = it.IsFound();
......
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
// Flags: --allow-natives-syntax --super-ic // Flags: --allow-natives-syntax --super-ic
function forceDictionaryMode(obj) {
for (let i = 0; i < 2000; ++i) {
obj["prop" + i] = "prop_value";
}
}
(function TestHomeObjectPrototypeNull() { (function TestHomeObjectPrototypeNull() {
class A {} class A {}
...@@ -303,10 +309,7 @@ ...@@ -303,10 +309,7 @@
// Create a "home object proto" object which is a bound function. // Create a "home object proto" object which is a bound function.
let home_object_proto = (function() {}).bind({}); let home_object_proto = (function() {}).bind({});
// Force home_object_proto to dictionary mode. forceDictionaryMode(home_object_proto);
for (let i = 0; i < 2000; ++i) {
home_object_proto["prop" + i] = "prop_value";
}
B.prototype.__proto__ = home_object_proto; B.prototype.__proto__ = home_object_proto;
assertEquals(0, home_object_proto.length); assertEquals(0, home_object_proto.length);
...@@ -342,3 +345,98 @@ ...@@ -342,3 +345,98 @@
assertEquals(A.prototype.foo, (new B).m()); assertEquals(A.prototype.foo, (new B).m());
assertEquals(A.prototype.foo, (new B).n()()); assertEquals(A.prototype.foo, (new B).n()());
})(); })();
// Regression test for a receiver vs lookup start object confusion.
(function TestProxyAsLookupStartObject1() {
class A {}
class B extends A {
bar() {
return super.foo;
}
}
const o = new B();
B.prototype.__proto__ = new Proxy({}, {});
for (let i = 0; i < 1000; ++i) {
assertEquals(undefined, o.bar());
}
})();
(function TestProxyAsLookupStartObject2() {
class A {}
class B extends A {
bar() {
return super.foo;
}
}
const o = new B();
forceDictionaryMode(o);
o.foo = "wrong value";
B.prototype.__proto__ = new Proxy({}, {});
for (let i = 0; i < 1000; ++i) {
assertEquals(undefined, o.bar());
}
})();
(function TestProxyAsLookupStartObject3() {
class A {}
class B extends A {
bar() {
return super.foo;
}
}
const o = new B();
B.prototype.__proto__ = new Proxy({}, {});
B.prototype.__proto__.foo = "correct value";
for (let i = 0; i < 1000; ++i) {
assertEquals(B.prototype.__proto__.foo, o.bar());
}
})();
(function TestDictionaryModeHomeObjectProto1() {
class A {}
forceDictionaryMode(A.prototype);
A.prototype.foo = "correct value";
class B extends A {
bar() {
return super.foo;
}
}
const o = new B();
for (let i = 0; i < 1000; ++i) {
assertEquals(A.prototype.foo, o.bar());
}
})();
(function TestDictionaryModeHomeObjectProto2() {
class A {}
A.prototype.foo = "correct value";
class B extends A {};
forceDictionaryMode(B.prototype);
class C extends B {
bar() {
return super.foo;
}
}
const o = new C();
for (let i = 0; i < 1000; ++i) {
assertEquals(A.prototype.foo, o.bar());
}
})();
(function TestHomeObjectProtoIsGlobalThis() {
class A {};
class B extends A {
bar() { return super.foo; }
}
B.prototype.__proto__ = globalThis;
const o = new B();
for (let i = 0; i < 1000; ++i) {
assertEquals(undefined, o.bar());
}
})();
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