Commit 4da8a9c7 authored by ishell's avatar ishell Committed by Commit bot

[ic] Support negative lookup on receiver in data handlers.

BUG=v8:5561

Review-Url: https://codereview.chromium.org/2446983002
Cr-Commit-Position: refs/heads/master@{#40565}
parent de52faf9
......@@ -5380,9 +5380,9 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
Variable* vars[] = {&var_holder, &var_smi_handler};
Label if_smi_handler(this, 2, vars);
Label try_proto_cell_handler(this), call_handler(this);
Label try_proto_handler(this), call_handler(this);
Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_cell_handler);
Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
// |handler| is a Smi, encoding what to do. See SmiHandler methods
// for the encoding format.
......@@ -5502,31 +5502,14 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
}
}
Bind(&try_proto_cell_handler);
Bind(&try_proto_handler);
{
GotoIf(WordNotEqual(LoadMap(handler), LoadRoot(Heap::kTuple3MapRootIndex)),
GotoIf(WordEqual(LoadMap(handler), LoadRoot(Heap::kCodeMapRootIndex)),
&call_handler);
Node* validity_cell = LoadObjectField(handler, Tuple3::kValue1Offset);
Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
GotoIf(WordNotEqual(cell_value,
SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
miss);
Node* holder =
LoadWeakCellValue(LoadObjectField(handler, Tuple3::kValue2Offset));
// The |holder| is guaranteed to be alive at this point since we passed
// both the receiver map check and the validity cell check.
CSA_ASSERT(WordNotEqual(holder, IntPtrConstant(0)));
Node* smi_handler = LoadObjectField(handler, Tuple3::kValue3Offset);
CSA_ASSERT(TaggedIsSmi(smi_handler));
var_holder.Bind(holder);
var_smi_handler.Bind(smi_handler);
Goto(&if_smi_handler);
HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss);
}
// |handler| is a heap object. Must be code, call it.
Bind(&call_handler);
{
typedef LoadWithVectorDescriptor Descriptor;
......@@ -5538,6 +5521,49 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
}
}
void CodeStubAssembler::HandleLoadICProtoHandler(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
Node* validity_cell = LoadObjectField(handler, Tuple3::kValue1Offset);
Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
GotoIf(WordNotEqual(cell_value,
SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
miss);
Node* holder =
LoadWeakCellValue(LoadObjectField(handler, Tuple3::kValue2Offset));
// The |holder| is guaranteed to be alive at this point since we passed
// both the receiver map check and the validity cell check.
CSA_ASSERT(WordNotEqual(holder, IntPtrConstant(0)));
Node* smi_handler = LoadObjectField(handler, Tuple3::kValue3Offset);
CSA_ASSERT(TaggedIsSmi(smi_handler));
var_holder->Bind(holder);
var_smi_handler->Bind(smi_handler);
GotoUnless(IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(
SmiUntag(smi_handler)),
if_smi_handler);
NameDictionaryNegativeLookup(p->receiver, p->name, miss);
Goto(if_smi_handler);
}
void CodeStubAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
Label* miss) {
CSA_ASSERT(IsDictionaryMap(LoadMap(object)));
Node* properties = LoadProperties(object);
// Ensure the property does not exist in a dictionary-mode object.
Variable var_name_index(this, MachineType::PointerRepresentation());
Label done(this);
NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
&done);
Bind(&done);
}
void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
......
......@@ -1097,6 +1097,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
const LoadICParameters* p, compiler::Node* handler, Label* miss,
ElementSupport support_elements = kOnlyProperties);
void HandleLoadICProtoHandler(const LoadICParameters* p,
compiler::Node* handler, Variable* var_holder,
Variable* var_smi_handler,
Label* if_smi_handler, Label* miss);
void NameDictionaryNegativeLookup(compiler::Node* object,
compiler::Node* name, Label* miss);
void HandleStoreFieldAndReturn(compiler::Node* handler_word,
compiler::Node* holder,
Representation representation,
......
......@@ -29,6 +29,17 @@ Handle<Object> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
return handle(Smi::FromInt(config), isolate);
}
Handle<Object> LoadHandler::EnableNegativeLookupOnReceiver(
Isolate* isolate, Handle<Object> smi_handler) {
int config = Smi::cast(*smi_handler)->value();
#ifdef DEBUG
Kind kind = KindBits::decode(config);
DCHECK(kind == kForFields || kind == kForConstants);
#endif
config = DoNegativeLookupOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
Handle<Object> LoadHandler::LoadElement(Isolate* isolate,
ElementsKind elements_kind,
bool convert_hole_to_undefined,
......
......@@ -19,13 +19,19 @@ class LoadHandler {
enum Kind { kForElements, kForFields, kForConstants };
class KindBits : public BitField<Kind, 0, 2> {};
// Defines whether negative lookup check should be done on receiver object.
// Applicable to kForFields and kForConstants kinds only when loading value
// from prototype chain. Ignored when loading from holder.
class DoNegativeLookupOnReceiverBits
: public BitField<bool, KindBits::kNext, 1> {};
//
// Encoding when KindBits contains kForConstants.
//
// +2 here is because each descriptor entry occupies 3 slots in array.
class DescriptorValueIndexBits
: public BitField<unsigned, KindBits::kNext,
: public BitField<unsigned, DoNegativeLookupOnReceiverBits::kNext,
kDescriptorIndexBitCount + 2> {};
// Make sure we don't overflow the smi.
STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize);
......@@ -33,7 +39,8 @@ class LoadHandler {
//
// Encoding when KindBits contains kForFields.
//
class IsInobjectBits : public BitField<bool, KindBits::kNext, 1> {};
class IsInobjectBits
: public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {};
class IsDoubleBits : public BitField<bool, IsInobjectBits::kNext, 1> {};
// +1 here is to cover all possible JSObject header sizes.
class FieldOffsetBits
......@@ -59,6 +66,11 @@ class LoadHandler {
// Creates a Smi-handler for loading a constant from fast object.
static inline Handle<Object> LoadConstant(Isolate* isolate, int descriptor);
// Sets DoNegativeLookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Object> EnableNegativeLookupOnReceiver(
Isolate* isolate, Handle<Object> smi_handler);
// Creates a Smi-handler for loading an element.
static inline Handle<Object> LoadElement(Isolate* isolate,
ElementsKind elements_kind,
......
......@@ -852,8 +852,7 @@ bool LoadIC::IsPrototypeValidityCellCheckEnough(Handle<Map> receiver_map,
// The following kinds of receiver maps require custom handler compilation.
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap() ||
receiver_map->IsJSGlobalObjectMap() ||
receiver_map->is_dictionary_map()) {
receiver_map->IsJSGlobalObjectMap()) {
return false;
}
......@@ -863,12 +862,12 @@ bool LoadIC::IsPrototypeValidityCellCheckEnough(Handle<Map> receiver_map,
JSObject* current = iter.GetCurrent<JSObject>();
if (current == *holder) break;
Map* current_map = current->map();
if (current_map->IsJSGlobalObjectMap() ||
current_map->IsJSGlobalProxyMap() || current_map->is_dictionary_map()) {
if (current_map->IsJSGlobalObjectMap()) {
return false;
} else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
return false;
}
// Only objects that do not require access checks are allowed in stubs.
DCHECK(!current_map->is_access_check_needed());
}
return true;
}
......@@ -878,6 +877,14 @@ Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map,
Handle<Object> smi_handler) {
DCHECK(IsPrototypeValidityCellCheckEnough(receiver_map, holder));
if (receiver_map->IsJSGlobalProxyMap() ||
receiver_map->IsJSGlobalObjectMap()) {
UNREACHABLE();
} else if (receiver_map->is_dictionary_map()) {
smi_handler =
LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler);
}
Handle<Cell> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
DCHECK(!validity_cell.is_null());
......
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