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

[ic] Prototype-only dictionaries, step 0.

- When a dictionary mode prototype changes, invalidate the validity cell.
- The dictionary mode prototypes don't need to be gathered into an array in InitPrototypeChecks.

Bug: v8:7159
Change-Id: I1c7bbaf4b20556f44df18be1463d38fa4fbabe05
Reviewed-on: https://chromium-review.googlesource.com/793732Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49857}
parent 3ef6e45e
......@@ -1524,6 +1524,12 @@ ExternalReference ExternalReference::runtime_function_table_address(
const_cast<Runtime::Function*>(Runtime::RuntimeFunctionTable(isolate)));
}
ExternalReference ExternalReference::invalidate_prototype_chains_function(
Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(JSObject::InvalidatePrototypeChains)));
}
double power_helper(Isolate* isolate, double x, double y) {
int y_int = static_cast<int>(y);
if (y == y_int) {
......
......@@ -1016,6 +1016,9 @@ class ExternalReference BASE_EMBEDDED {
V8_EXPORT_PRIVATE static ExternalReference runtime_function_table_address(
Isolate* isolate);
static ExternalReference invalidate_prototype_chains_function(
Isolate* isolate);
Address address() const { return reinterpret_cast<Address>(address_); }
// Used to read out the last step action of the debugger.
......
......@@ -345,6 +345,10 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"IncrementalMarking::RecordWrite");
Add(ExternalReference::store_buffer_overflow_function(isolate).address(),
"StoreBuffer::StoreBufferOverflow");
Add(ExternalReference::invalidate_prototype_chains_function(isolate)
.address(),
"JSObject::InvalidatePrototypeChains()");
}
void ExternalReferenceTable::AddBuiltins(Isolate* isolate) {
......
......@@ -1085,6 +1085,9 @@ void AccessorAssembler::HandleStoreICProtoHandler(
BIND(&not_found);
{
Label slow(this);
Node* receiver_map = LoadMap(p->receiver);
InvalidateValidityCellIfPrototype(receiver_map);
Add<NameDictionary>(properties, p->name, p->value, &slow);
Return(p->value);
......@@ -1819,6 +1822,25 @@ void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
if_strict);
}
void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
Node* bitfield2) {
Label is_prototype(this), cont(this);
if (bitfield2 == nullptr) {
bitfield2 = LoadMapBitField2(map);
}
Branch(IsSetWord32(bitfield2, Map::IsPrototypeMapBits::kMask), &is_prototype,
&cont);
BIND(&is_prototype);
Node* function = ExternalConstant(
ExternalReference::invalidate_prototype_chains_function(isolate()));
CallCFunction1(MachineType::AnyTagged(), MachineType::AnyTagged(), function,
map);
Goto(&cont);
BIND(&cont);
}
void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
Node* instance_type, Node* index,
Label* slow) {
......
......@@ -99,6 +99,8 @@ class AccessorAssembler : public CodeStubAssembler {
void BranchIfStrictMode(Node* vector, Node* slot, Label* if_strict);
void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
private:
// Stub generation entry points.
......
......@@ -71,17 +71,6 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
} else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (fill_array) {
DCHECK_EQ(NameDictionary::kNotFound,
current->property_dictionary()->FindEntry(name));
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
}
return checks_count;
......
......@@ -882,8 +882,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
{
CheckForAssociatedProtector(p->name, slow);
Label extensible(this);
GotoIf(IsPrivateSymbol(p->name), &extensible);
Node* bitfield2 = LoadMapBitField2(receiver_map);
GotoIf(IsPrivateSymbol(p->name), &extensible);
Branch(IsSetWord32(bitfield2, 1 << Map::kIsExtensible), &extensible,
slow);
......@@ -892,6 +892,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
&var_accessor_pair, &var_accessor_holder,
&readonly, slow);
Label add_dictionary_property_slow(this);
InvalidateValidityCellIfPrototype(receiver_map, bitfield2);
Add<NameDictionary>(properties, p->name, p->value,
&add_dictionary_property_slow);
Return(p->value);
......
......@@ -495,6 +495,9 @@ void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
Handle<NameDictionary> dictionary(receiver->property_dictionary(),
isolate_);
int entry;
if (receiver->map()->is_prototype_map()) {
JSObject::InvalidatePrototypeChains(receiver->map());
}
dictionary = NameDictionary::Add(dictionary, name(),
isolate_->factory()->uninitialized_value(),
property_details_, &entry);
......@@ -638,9 +641,12 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
ReloadPropertyInformation<true>();
} else {
PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
? KEEP_INOBJECT_PROPERTIES
: CLEAR_INOBJECT_PROPERTIES;
PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
if (receiver->map()->is_prototype_map()) {
JSObject::InvalidatePrototypeChains(receiver->map());
mode = KEEP_INOBJECT_PROPERTIES;
}
// Normalize object to make this operation simple.
JSObject::NormalizeProperties(receiver, mode, 0,
"TransitionToAccessorPair");
......
......@@ -2187,6 +2187,8 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
int entry = dictionary->FindEntry(name);
if (entry == NameDictionary::kNotFound) {
DCHECK_IMPLIES(object->map()->is_prototype_map(),
Map::IsPrototypeChainInvalidated(object->map()));
dictionary = NameDictionary::Add(dictionary, name, value, details);
object->SetProperties(*dictionary);
} else {
......@@ -4213,6 +4215,9 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map,
// JSGlobalProxy must never be normalized
DCHECK(!object->IsJSGlobalProxy());
DCHECK_IMPLIES(new_map->is_prototype_map(),
Map::IsPrototypeChainInvalidated(*new_map));
Isolate* isolate = object->GetIsolate();
HandleScope scope(isolate);
Handle<Map> map(object->map());
......@@ -12561,9 +12566,10 @@ static void InvalidatePrototypeChainsInternal(Map* map) {
// static
void JSObject::InvalidatePrototypeChains(Map* map) {
Map* JSObject::InvalidatePrototypeChains(Map* map) {
DisallowHeapAllocation no_gc;
InvalidatePrototypeChainsInternal(map);
return map;
}
......@@ -12643,6 +12649,21 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
return cell;
}
// static
bool Map::IsPrototypeChainInvalidated(Map* map) {
DCHECK(map->is_prototype_map());
Object* maybe_proto_info = map->prototype_info();
if (maybe_proto_info->IsPrototypeInfo()) {
PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info);
Object* maybe_cell = proto_info->validity_cell();
if (maybe_cell->IsCell()) {
Cell* cell = Cell::cast(maybe_cell);
return cell->value() == Smi::FromInt(Map::kPrototypeChainInvalid);
}
}
return true;
}
// static
Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,
Isolate* isolate) {
......
......@@ -2340,7 +2340,7 @@ class JSObject: public JSReceiver {
Handle<Map> new_map,
Isolate* isolate);
static bool UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate);
static void InvalidatePrototypeChains(Map* map);
static Map* InvalidatePrototypeChains(Map* map);
// Updates prototype chain tracking information when an object changes its
// map from |old_map| to |new_map|.
......
......@@ -407,6 +407,8 @@ class Map : public HeapObject {
static const int kPrototypeChainValid = 0;
static const int kPrototypeChainInvalid = 1;
static bool IsPrototypeChainInvalidated(Map* map);
// Return the map of the root of object's prototype chain.
Map* GetPrototypeChainRootMap(Isolate* isolate) const;
......
This diff is collapsed.
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