Commit 4a596cf5 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[ic] Unify handling of Load/StoreHandler objects in load/store IC dispatchers.

This CL also adds support for "lookup on dictionary receivers" to store ICs.

Bug: v8:7206, v8:5561
Change-Id: Icebbc2d52c71f5d25b43f2f2a8adf674e4ec2cbc
Reviewed-on: https://chromium-review.googlesource.com/819232
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50113}
parent a0b9a235
......@@ -20,6 +20,32 @@ using compiler::Node;
//////////////////// Private helpers.
// Loads dataX field from the DataHandler object.
Node* AccessorAssembler::LoadHandlerDataField(Node* handler, int data_index) {
#ifdef DEBUG
Node* handler_map = LoadMap(handler);
Node* instance_type = LoadMapInstanceType(handler_map);
#endif
CSA_ASSERT(this,
Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
InstanceTypeEqual(instance_type, STORE_HANDLER_TYPE)));
int offset = 0;
int minimum_size = 0;
if (data_index == 1) {
offset = DataHandler::kData1Offset;
minimum_size = DataHandler::kSizeWithData1;
} else {
DCHECK_EQ(2, data_index);
offset = DataHandler::kData2Offset;
minimum_size = DataHandler::kSizeWithData2;
}
USE(minimum_size);
CSA_ASSERT(this, UintPtrGreaterThanOrEqual(
LoadMapInstanceSizeInWords(handler_map),
IntPtrConstant(minimum_size / kPointerSize)));
return LoadObjectField(handler, offset);
}
Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector,
Node* receiver_map,
Label* if_handler,
......@@ -152,9 +178,8 @@ void AccessorAssembler::HandleLoadICHandlerCase(
BIND(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point, false,
ic_mode);
HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point, ic_mode);
}
BIND(&call_handler);
......@@ -539,89 +564,145 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
}
void AccessorAssembler::HandleLoadICProtoHandlerCase(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
ExitPoint* exit_point, bool throw_reference_error_if_nonexistent,
// Performs actions common to both load and store handlers:
// 1. Checks prototype validity cell.
// 2. If |on_code_handler| is provided, then it checks if the sub handler is
// a smi or code and if it's a code then it calls |on_code_handler| to
// generate a code that handles Code handlers.
// If |on_code_handler| is not provided, then only smi sub handler are
// expected.
// 3. Does access check on receiver if ICHandler::DoAccessCheckOnReceiverBits
// bit is set in the smi handler.
// 4. Does dictionary lookup on receiver if ICHandler::LookupOnReceiverBits bit
// is set in the smi handler. If |on_found_on_receiver| 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_receiver| is not provided.
// 5. Falls through in a case of a smi handler which is returned from this
// function (tagged!).
// TODO(ishell): Remove templatezation once we move common bits from
// Load/StoreHandler to the base class.
template <typename ICHandler, typename ICParameters>
Node* AccessorAssembler::HandleProtoHandler(
const ICParameters* p, Node* handler, const OnCodeHandler& on_code_handler,
const OnFoundOnReceiver& on_found_on_receiver, Label* miss,
ICMode ic_mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
Label validity_cell_check_done(this);
//
// Check prototype validity cell.
//
{
Label done(this);
Node* validity_cell =
LoadObjectField(handler, LoadHandler::kValidityCellOffset);
GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
&validity_cell_check_done);
LoadObjectField(handler, ICHandler::kValidityCellOffset);
GotoIf(WordEqual(validity_cell, SmiConstant(0)), &done);
Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
GotoIf(WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
miss);
Goto(&validity_cell_check_done);
Goto(&done);
BIND(&done);
}
BIND(&validity_cell_check_done);
Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
Node* handler_flags = SmiUntag(smi_handler);
//
// Check smi handler bits.
//
{
Node* smi_or_code_handler =
LoadObjectField(handler, ICHandler::kSmiHandlerOffset);
if (on_code_handler) {
Label if_smi_handler(this);
GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
CSA_ASSERT(this, IsCodeMap(LoadMap(smi_or_code_handler)));
on_code_handler(smi_or_code_handler);
BIND(&if_smi_handler);
} else {
CSA_ASSERT(this, TaggedIsSmi(smi_or_code_handler));
}
Node* handler_flags = SmiUntag(smi_or_code_handler);
// Lookup on receiver and access checks are not necessary for global ICs
// because in the former case the validity cell check guards modifications
// of the global object and the latter is not applicable to the global object.
int mask = LoadHandler::LookupOnReceiverBits::kMask |
LoadHandler::DoAccessCheckOnReceiverBits::kMask;
// of the global object and the latter is not applicable to the global
// object.
int mask = ICHandler::LookupOnReceiverBits::kMask |
ICHandler::DoAccessCheckOnReceiverBits::kMask;
if (ic_mode == ICMode::kGlobalIC) {
CSA_ASSERT(this, IsClearWord(handler_flags, mask));
} else {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
Label do_load(this), if_do_access_check(this), if_lookup_on_receiver(this);
GotoIf(IsClearWord(handler_flags, mask), &do_load);
Label done(this), if_do_access_check(this), if_lookup_on_receiver(this);
GotoIf(IsClearWord(handler_flags, mask), &done);
// Only one of the bits can be set at a time.
CSA_ASSERT(this, WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
CSA_ASSERT(this,
WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
IntPtrConstant(mask)));
if (ic_mode == ICMode::kGlobalIC) {
Goto(&if_do_access_check);
} else {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
Branch(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&if_do_access_check, &if_lookup_on_receiver);
}
BIND(&if_do_access_check);
{
Node* data2 = LoadObjectField(handler, LoadHandler::kData2Offset);
Node* data2 = LoadHandlerDataField(handler, 2);
Node* expected_native_context = LoadWeakCellValue(data2, miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver,
&do_load, miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver, &done,
miss);
}
// Lookups on receiver are not necessary for LoadGlobalIC.
// Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC
// because prototype validity cell check already guards modifications of
// the global object.
BIND(&if_lookup_on_receiver);
{
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
CSA_ASSERT(this, Word32BinaryNot(HasInstanceType(p->receiver,
JS_GLOBAL_OBJECT_TYPE)));
CSA_ASSERT(this, Word32BinaryNot(HasInstanceType(
p->receiver, JS_GLOBAL_OBJECT_TYPE)));
Node* properties = LoadSlowProperties(p->receiver);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
&var_name_index, &do_load);
&var_name_index, &done);
BIND(&found);
{
if (on_found_on_receiver) {
on_found_on_receiver(properties, var_name_index.value());
} else {
Goto(miss);
}
}
}
BIND(&done);
}
return smi_or_code_handler;
}
}
void AccessorAssembler::HandleLoadICProtoHandler(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
Node* smi_handler = HandleProtoHandler<LoadHandler>(
p, handler,
// Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
nullptr,
// on_found_on_receiver
[=](Node* properties, Node* name_index) {
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_value, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
LoadPropertyFromNameDictionary(properties, name_index, &var_details,
&var_value);
Node* value =
CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context, p->receiver, miss);
exit_point->Return(value);
}
}
BIND(&do_load);
}
},
miss, ic_mode);
Node* maybe_holder_cell = LoadObjectField(handler, LoadHandler::kData1Offset);
Node* maybe_holder_cell = LoadHandlerDataField(handler, 1);
Label load_from_cached_holder(this), done(this);
......@@ -651,8 +732,10 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
}
BIND(&done);
{
var_smi_handler->Bind(smi_handler);
Goto(if_smi_handler);
}
}
void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
......@@ -686,9 +769,9 @@ void AccessorAssembler::HandleLoadGlobalICHandlerCase(
VARIABLE(var_smi_handler, MachineRepresentation::kTagged);
Label if_smi_handler(this);
HandleLoadICProtoHandlerCase(
&p, handler, &var_holder, &var_smi_handler, &if_smi_handler, miss,
exit_point, throw_reference_error_if_nonexistent, ICMode::kGlobalIC);
HandleLoadICProtoHandler(&p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point,
ICMode::kGlobalIC);
BIND(&if_smi_handler);
HandleLoadICSmiHandlerCase(
&p, var_holder.value(), var_smi_handler.value(), miss, exit_point,
......@@ -718,7 +801,7 @@ void AccessorAssembler::HandleStoreICNativeDataProperty(
}
void AccessorAssembler::HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
const StoreICParameters* p, Node* handler, Label* miss, ICMode ic_mode,
ElementSupport support_elements) {
Label if_smi_handler(this), if_nonsmi_handler(this);
Label if_proto_handler(this), if_element_handler(this), call_handler(this),
......@@ -811,7 +894,7 @@ void AccessorAssembler::HandleStoreICHandlerCase(
}
BIND(&if_proto_handler);
HandleStoreICProtoHandler(p, handler, miss, support_elements);
HandleStoreICProtoHandler(p, handler, miss, ic_mode, support_elements);
// |handler| is a heap object. Must be code, call it.
BIND(&call_handler);
......@@ -863,48 +946,39 @@ void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
}
void AccessorAssembler::HandleStoreICProtoHandler(
const StoreICParameters* p, Node* handler, Label* miss,
const StoreICParameters* p, Node* handler, Label* miss, ICMode ic_mode,
ElementSupport support_elements) {
Comment("HandleStoreICProtoHandler");
Label validity_cell_check_done(this);
Node* validity_cell =
LoadObjectField(handler, StoreHandler::kValidityCellOffset);
GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
&validity_cell_check_done);
Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
GotoIf(WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
miss);
Goto(&validity_cell_check_done);
BIND(&validity_cell_check_done);
Node* smi_or_code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
Label do_store(this);
GotoIfNot(TaggedIsSmi(smi_or_code), &do_store);
Label if_do_access_check(this);
{
Node* handler_flags = SmiUntag(smi_or_code);
Branch(IsSetWord<StoreHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&if_do_access_check, &do_store);
}
BIND(&if_do_access_check);
{
Node* data2 = LoadObjectField(handler, StoreHandler::kData2Offset);
Node* expected_native_context = LoadWeakCellValue(data2, miss);
Node* smi_or_code = HandleProtoHandler<StoreHandler>(
p, handler,
// on_code_handler,
[=, &do_store](Node* code) { Goto(&do_store); },
// on_found_on_receiver
[=](Node* properties, Node* name_index) {
// TODO(ishell): combine with |found| case inside |if_store_normal|.
Node* details =
LoadDetailsByKeyIndex<NameDictionary>(properties, name_index);
// Check that the property is a writable data property (no accessor).
const int kTypeAndReadOnlyMask =
PropertyDetails::KindField::kMask |
PropertyDetails::kAttributesReadOnlyMask;
STATIC_ASSERT(kData == 0);
GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver, &do_store,
miss);
}
StoreValueByKeyIndex<NameDictionary>(properties, name_index, p->value);
Return(p->value);
},
miss, ic_mode);
Goto(&do_store);
VARIABLE(var_transition_map_or_holder, MachineRepresentation::kTagged);
Label if_transition_map(this), if_holder_object(this);
BIND(&do_store);
{
Node* maybe_transition_cell =
LoadObjectField(handler, StoreHandler::kData1Offset);
Node* maybe_transition_cell = LoadHandlerDataField(handler, 1);
var_transition_map_or_holder.Bind(maybe_transition_cell);
Label unwrap_cell(this);
......@@ -2553,7 +2627,8 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
BIND(&if_handler);
{
Comment("StoreIC_if_handler");
HandleStoreICHandlerCase(p, var_handler.value(), &miss);
HandleStoreICHandlerCase(p, var_handler.value(), &miss,
ICMode::kNonGlobalIC);
}
BIND(&try_polymorphic);
......@@ -2619,7 +2694,7 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
p.receiver =
LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
HandleStoreICHandlerCase(&p, handler, &miss);
HandleStoreICHandlerCase(&p, handler, &miss, ICMode::kGlobalIC);
}
BIND(&miss);
......@@ -2713,7 +2788,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
BIND(&if_handler);
{
Comment("KeyedStoreIC_if_handler");
HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
HandleStoreICHandlerCase(p, var_handler.value(), &miss,
ICMode::kNonGlobalIC, kSupportElements);
}
BIND(&try_polymorphic);
......
......@@ -82,6 +82,9 @@ class AccessorAssembler : public CodeStubAssembler {
// construction on common paths.
void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
// Loads dataX field from the DataHandler object.
Node* LoadHandlerDataField(Node* handler, int data_index);
protected:
struct StoreICParameters : public LoadICParameters {
StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
......@@ -91,9 +94,10 @@ class AccessorAssembler : public CodeStubAssembler {
Node* value;
};
enum class ICMode { kNonGlobalIC, kGlobalIC };
enum ElementSupport { kOnlyProperties, kSupportElements };
void HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
const StoreICParameters* p, Node* handler, Label* miss, ICMode ic_mode,
ElementSupport support_elements = kOnlyProperties);
void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
......@@ -136,7 +140,6 @@ class AccessorAssembler : public CodeStubAssembler {
// LoadIC implementation.
enum class ICMode { kNonGlobalIC, kGlobalIC };
void HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
......@@ -148,13 +151,10 @@ class AccessorAssembler : public CodeStubAssembler {
bool throw_reference_error_if_nonexistent,
ElementSupport support_elements);
void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
Variable* var_holder,
Variable* var_smi_handler,
void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
Variable* var_holder, Variable* var_smi_handler,
Label* if_smi_handler, Label* miss,
ExitPoint* exit_point,
bool throw_reference_error_if_nonexistent,
ICMode ic_mode);
ExitPoint* exit_point, ICMode ic_mode);
void HandleLoadField(Node* holder, Node* handler_word,
Variable* var_double_value, Label* rebox_double,
......@@ -175,7 +175,8 @@ class AccessorAssembler : public CodeStubAssembler {
Node* handler, Label* miss);
void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
Label* miss, ElementSupport support_elements);
Label* miss, ICMode ic_mode,
ElementSupport support_elements);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
......@@ -208,6 +209,16 @@ class AccessorAssembler : public CodeStubAssembler {
// Low-level helpers.
typedef std::function<void(Node* code_handler)> OnCodeHandler;
typedef std::function<void(Node* properties, Node* name_index)>
OnFoundOnReceiver;
template <typename ICHandler, typename ICParameters>
Node* HandleProtoHandler(const ICParameters* p, Node* handler,
const OnCodeHandler& on_code_handler,
const OnFoundOnReceiver& on_found_on_receiver,
Label* miss, ICMode ic_mode);
Node* GetLanguageMode(Node* vector, Node* slot);
Node* PrepareValueForStore(Node* handler_word, Node* holder,
......
......@@ -83,28 +83,6 @@ Handle<Smi> LoadHandler::LoadModuleExport(Isolate* isolate, int index) {
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::EnableAccessCheckOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler) {
int config = smi_handler->value();
#ifdef DEBUG
Kind kind = KindBits::decode(config);
DCHECK_NE(kElement, kind);
#endif
config = DoAccessCheckOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::EnableLookupOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler) {
int config = smi_handler->value();
#ifdef DEBUG
Kind kind = KindBits::decode(config);
DCHECK_NE(kElement, kind);
#endif
config = LookupOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::LoadNonExistent(Isolate* isolate) {
int config = KindBits::encode(kNonExistent);
return handle(Smi::FromInt(config), isolate);
......@@ -150,13 +128,6 @@ Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> StoreHandler::EnableAccessCheckOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler) {
int config = smi_handler->value();
config = DoAccessCheckOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
......@@ -246,11 +217,6 @@ WeakCell* StoreHandler::GetTransitionCell(Object* handler) {
return cell;
}
// static
bool StoreHandler::IsHandler(Object* maybe_handler) {
return maybe_handler->IsStoreHandler();
}
} // namespace internal
} // namespace v8
......
......@@ -13,16 +13,27 @@ namespace internal {
namespace {
template <bool fill_array = true>
template <typename BitField>
Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler,
typename BitField::FieldType value) {
int config = smi_handler->value();
config = BitField::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
// TODO(ishell): Remove templatezation once we move common bits from
// Load/StoreHandler to the base class.
template <typename ICHandler, bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name,
Handle<DataHandler> handler) {
Handle<ICHandler> handler,
Handle<Smi>* smi_handler = nullptr) {
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
HandleScope scope(isolate);
int checks_count = 0;
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->IsJSGlobalObjectMap());
// The validity cell check for primitive and global proxy receivers does
// not guarantee that certain native context ever had access to other
// native context. However, a handler created for one native context could
......@@ -32,8 +43,19 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
if (fill_array) {
Handle<Context> native_context = isolate->native_context();
handler->set_data2(native_context->self_weak_cell());
} else {
// Enable access checks on receiver.
typedef typename ICHandler::DoAccessCheckOnReceiverBits Bit;
*smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
}
checks_count++;
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
if (!fill_array) {
// Enable lookup on receiver.
typedef typename ICHandler::LookupOnReceiverBits Bit;
*smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
}
}
return checks_count;
}
......@@ -44,10 +66,13 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
template <typename ICHandler>
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
Handle<DataHandler>());
Handle<JSReceiver> holder, Handle<Name> name,
Handle<Smi>* smi_handler) {
DCHECK_NOT_NULL(smi_handler);
return InitPrototypeChecks<ICHandler, false>(
isolate, receiver_map, holder, name, Handle<ICHandler>(), smi_handler);
}
} // namespace
......@@ -59,20 +84,8 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
Handle<Name> name,
Handle<Smi> smi_handler,
MaybeHandle<Object> maybe_data) {
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK_LE(checks_count, 1);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_EQ(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = EnableLookupOnReceiver(isolate, smi_handler);
}
int checks_count = GetPrototypeCheckCount<LoadHandler>(
isolate, receiver_map, holder, name, &smi_handler);
Handle<Cell> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
......@@ -100,19 +113,8 @@ Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<Name> name,
Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle
int checks_count = GetPrototypeCheckCount(isolate, receiver_map, end, name);
DCHECK_LE(0, checks_count);
DCHECK_LE(checks_count, 1);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_EQ(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = EnableLookupOnReceiver(isolate, smi_handler);
}
int checks_count = GetPrototypeCheckCount<LoadHandler>(
isolate, receiver_map, end, name, &smi_handler);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
......@@ -199,16 +201,8 @@ Handle<Object> StoreHandler::StoreThroughPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Name> name, Handle<Smi> smi_handler,
MaybeHandle<Object> maybe_data) {
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
if (receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
}
int checks_count = GetPrototypeCheckCount<StoreHandler>(
isolate, receiver_map, holder, name, &smi_handler);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
......
......@@ -83,7 +83,8 @@ class LoadHandler final : public DataHandler {
//
// Encoding when KindBits contains kElement or kIndexedString.
//
class AllowOutOfBoundsBits : public BitField<bool, KindBits::kNext, 1> {};
class AllowOutOfBoundsBits
: public BitField<bool, LookupOnReceiverBits::kNext, 1> {};
//
// Encoding when KindBits contains kElement.
......@@ -99,8 +100,9 @@ class LoadHandler final : public DataHandler {
//
// Encoding when KindBits contains kModuleExport.
//
class ExportsIndexBits : public BitField<unsigned, KindBits::kNext,
kSmiValueSize - KindBits::kNext> {};
class ExportsIndexBits
: public BitField<unsigned, LookupOnReceiverBits::kNext,
kSmiValueSize - LookupOnReceiverBits::kNext> {};
// Decodes kind from Smi-handler.
static inline Kind GetHandlerKind(Smi* smi_handler);
......@@ -173,17 +175,6 @@ class LoadHandler final : public DataHandler {
// Decodes the KeyedAccessLoadMode from a {handler}.
static KeyedAccessLoadMode GetKeyedAccessLoadMode(Object* handler);
private:
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableAccessCheckOnReceiver(
Isolate* isolate, Handle<Smi> smi_handler);
// Sets LookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler);
};
// A set of bit fields representing Smi handlers for stores and a HeapObject
......@@ -216,20 +207,23 @@ class StoreHandler final : public DataHandler {
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
static inline bool IsHandler(Object* maybe_handler);
// Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object.
class DoAccessCheckOnReceiverBits
: public BitField<bool, KindBits::kNext, 1> {};
// Defines whether a lookup should be done on receiver object before
// proceeding to the prototype chain. Applicable to named property kinds only
// when storing through prototype chain. Ignored when storing to holder.
class LookupOnReceiverBits
: public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {};
// Applicable to kField, kTransitionToField and kTransitionToConstant
// kinds.
// Index of a value entry in the descriptor array.
class DescriptorBits
: public BitField<unsigned, DoAccessCheckOnReceiverBits::kNext,
class DescriptorBits : public BitField<unsigned, LookupOnReceiverBits::kNext,
kDescriptorIndexBitCount> {};
//
// Encoding when KindBits contains kTransitionToConstant.
......@@ -306,11 +300,6 @@ class StoreHandler final : public DataHandler {
static inline Handle<Smi> StoreProxy(Isolate* isolate);
private:
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableAccessCheckOnReceiver(
Isolate* isolate, Handle<Smi> smi_handler);
static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
......
......@@ -824,7 +824,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&found_handler);
{
Comment("KeyedStoreGeneric found transition handler");
HandleStoreICHandlerCase(p, var_handler.value(), notfound);
HandleStoreICHandlerCase(p, var_handler.value(), notfound,
ICMode::kNonGlobalIC);
}
}
}
......@@ -942,7 +943,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&found_handler);
{
Comment("KeyedStoreGeneric found handler");
HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss);
HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss,
ICMode::kNonGlobalIC);
}
BIND(&stub_cache_miss);
{
......
......@@ -17,7 +17,7 @@ void TransitionsAccessor::Initialize() {
encoding_ = kUninitialized;
} else if (HeapObject::cast(raw_transitions_)->IsWeakCell()) {
encoding_ = kWeakCell;
} else if (StoreHandler::IsHandler(raw_transitions_)) {
} else if (HeapObject::cast(raw_transitions_)->IsStoreHandler()) {
encoding_ = kHandler;
} else if (HeapObject::cast(raw_transitions_)->IsTransitionArray()) {
encoding_ = kFullTransitionArray;
......@@ -250,7 +250,7 @@ Object* TransitionsAccessor::SearchHandler(Name* name,
int transition = transitions()->Search(kData, name, NONE);
if (transition == kNotFound) return nullptr;
Object* raw_handler = transitions()->GetRawTarget(transition);
if (StoreHandler::IsHandler(raw_handler)) {
if (raw_handler->IsStoreHandler()) {
return StoreHandler::ValidHandlerOrNull(raw_handler, name,
out_transition);
}
......
// Copyright 2017 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.
// Flags: --allow-natives-syntax
(function TestLookupOnReceiver() {
let log = [];
function f(o, v) {
o.x = v;
return o.x;
}
let p = {};
Object.defineProperty(
p, "x",
{
get: function() { return 153; },
set: function(v) { log.push("set"); },
configurable: true
});
let o = Object.create(p);
// Turn o to dictionary mode.
for (let i = 0; i < 2048; i++) {
o["p"+i] = 0;
}
assertFalse(%HasFastProperties(o));
for (let i = 0; i < 5; i++) {
log.push(f(o, i));
}
Object.defineProperty(o, "x", { value: 0, configurable: true, writable: true});
for (let i = 0; i < 5; i++) {
log.push(f(o, 42 + i));
}
assertEquals(log,
["set", 153, "set", 153, "set", 153, "set", 153, "set", 153,
42, 43, 44, 45, 46]);
})();
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