Commit 800c294c authored by Mythri A's avatar Mythri A Committed by Commit Bot

[ic] Use the existing prototype validity cell when recomputing handlers

For keyed stores we recompute handlers based on the receiver maps
we have seen. This is done so that we can transition to the most generic
elements kind we have seen so far. When we recompute this handlers we
get a new prototype validity cell and ignore the existing cell. This
leads to incorrect behaviour if the cell was invalid. Recomputing the
handler may be extra work which is not worth doing at this point. So
we just reuse the existing validity cell and let the IC recompute the
handler if we see the map again.

Bug: chromium:1053939
Change-Id: Ifc891d70f5a4b8b774238e12fb40e29b4d174e37
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2122032
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66963}
parent b8f14fc3
......@@ -200,11 +200,14 @@ KeyedAccessStoreMode StoreHandler::GetKeyedAccessStoreMode(
// static
Handle<Object> StoreHandler::StoreElementTransition(
Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
KeyedAccessStoreMode store_mode) {
KeyedAccessStoreMode store_mode, MaybeHandle<Object> prev_validity_cell) {
Handle<Code> stub =
CodeFactory::ElementsTransitionAndStore(isolate, store_mode).code();
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
Handle<Object> validity_cell;
if (!prev_validity_cell.ToHandle(&validity_cell)) {
validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
}
Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
handler->set_smi_handler(*stub);
handler->set_validity_cell(*validity_cell);
......
......@@ -275,10 +275,10 @@ class StoreHandler final : public DataHandler {
MaybeObjectHandle maybe_data1 = MaybeObjectHandle(),
MaybeObjectHandle maybe_data2 = MaybeObjectHandle());
static Handle<Object> StoreElementTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<Map> transition,
KeyedAccessStoreMode store_mode);
static Handle<Object> StoreElementTransition(
Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
KeyedAccessStoreMode store_mode,
MaybeHandle<Object> prev_validity_cell = MaybeHandle<Object>());
static Handle<Object> StoreProxy(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSProxy> proxy,
......
......@@ -364,9 +364,20 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
MaybeObjectHandles* handlers) {
DCHECK(!IsGlobalIC());
std::vector<MapAndHandler> maps_and_handlers;
DCHECK_EQ(maps.size(), handlers->size());
for (size_t i = 0; i < maps.size(); i++) {
maps_and_handlers.push_back(MapAndHandler(maps[i], handlers->at(i)));
}
ConfigureVectorState(name, maps_and_handlers);
}
void IC::ConfigureVectorState(
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
DCHECK(!IsGlobalIC());
// Non-keyed ICs don't track the name explicitly.
if (!is_keyed()) name = Handle<Name>::null();
nexus()->ConfigurePolymorphic(name, maps, handlers);
nexus()->ConfigurePolymorphic(name, maps_and_handlers);
OnFeedbackChanged("Polymorphic");
}
......@@ -530,6 +541,22 @@ static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
return true;
}
static bool AddOneReceiverMapIfMissing(
std::vector<MapAndHandler>* receiver_maps_and_handlers,
Handle<Map> new_receiver_map) {
DCHECK(!new_receiver_map.is_null());
if (new_receiver_map->is_deprecated()) return false;
for (MapAndHandler map_and_handler : *receiver_maps_and_handlers) {
Handle<Map> map = map_and_handler.first;
if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
return false;
}
}
receiver_maps_and_handlers->push_back(
MapAndHandler(new_receiver_map, MaybeObjectHandle()));
return true;
}
bool IC::UpdatePolymorphicIC(Handle<Name> name,
const MaybeObjectHandle& handler) {
DCHECK(IsHandler(*handler));
......@@ -537,16 +564,16 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
if (nexus()->GetName() != *name) return false;
}
Handle<Map> map = receiver_map();
MapHandles maps;
MaybeObjectHandles handlers;
nexus()->ExtractMapsAndHandlers(&maps, &handlers);
int number_of_maps = static_cast<int>(maps.size());
std::vector<MapAndHandler> maps_and_handlers;
nexus()->ExtractMapsAndHandlers(&maps_and_handlers);
int number_of_maps = static_cast<int>(maps_and_handlers.size());
int deprecated_maps = 0;
int handler_to_overwrite = -1;
for (int i = 0; i < number_of_maps; i++) {
Handle<Map> current_map = maps.at(i);
Handle<Map> current_map = maps_and_handlers.at(i).first;
MaybeObjectHandle current_handler = maps_and_handlers.at(i).second;
if (current_map->is_deprecated()) {
// Filter out deprecated maps to ensure their instances get migrated.
++deprecated_maps;
......@@ -556,7 +583,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
// in the lattice and need to go MEGAMORPHIC instead. There's one
// exception to this rule, which is when we're in RECOMPUTE_HANDLER
// state, there we allow to migrate to a new handler.
if (handler.is_identical_to(handlers[i]) &&
if (handler.is_identical_to(current_handler) &&
state() != RECOMPUTE_HANDLER) {
return false;
}
......@@ -584,16 +611,16 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
} else {
if (is_keyed() && nexus()->GetName() != *name) return false;
if (handler_to_overwrite >= 0) {
handlers[handler_to_overwrite] = handler;
if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
maps[handler_to_overwrite] = map;
maps_and_handlers[handler_to_overwrite].second = handler;
if (!map.is_identical_to(
maps_and_handlers.at(handler_to_overwrite).first)) {
maps_and_handlers[handler_to_overwrite].first = map;
}
} else {
maps.push_back(map);
handlers.push_back(handler);
maps_and_handlers.push_back(MapAndHandler(map, handler));
}
ConfigureVectorState(name, maps, &handlers);
ConfigureVectorState(name, maps_and_handlers);
}
return true;
......@@ -606,11 +633,10 @@ void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
}
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
MapHandles maps;
MaybeObjectHandles handlers;
nexus()->ExtractMapsAndHandlers(&maps, &handlers);
for (size_t i = 0; i < maps.size(); ++i) {
UpdateMegamorphicCache(maps.at(i), name, handlers.at(i));
std::vector<MapAndHandler> maps_and_handlers;
nexus()->ExtractMapsAndHandlers(&maps_and_handlers);
for (const MapAndHandler& map_and_handler : maps_and_handlers) {
UpdateMegamorphicCache(map_and_handler.first, name, map_and_handler.second);
}
}
......@@ -1768,9 +1794,9 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
KeyedAccessStoreMode store_mode,
Handle<Map> new_receiver_map) {
MapHandles target_receiver_maps;
TargetMaps(&target_receiver_maps);
if (target_receiver_maps.empty()) {
std::vector<MapAndHandler> target_maps_and_handlers;
nexus()->ExtractMapsAndHandlers(&target_maps_and_handlers, true);
if (target_maps_and_handlers.empty()) {
Handle<Map> monomorphic_map = receiver_map;
// If we transitioned to a map that is a more general map than incoming
// then use the new map.
......@@ -1781,7 +1807,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
}
for (Handle<Map> map : target_receiver_maps) {
for (const MapAndHandler& map_and_handler : target_maps_and_handlers) {
Handle<Map> map = map_and_handler.first;
if (!map.is_null() && map->instance_type() == JS_PRIMITIVE_WRAPPER_TYPE) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
set_slow_stub_reason("JSPrimitiveWrapper");
......@@ -1794,7 +1821,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// Handle those here if the receiver map hasn't changed or it has transitioned
// to a more general kind.
KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
Handle<Map> previous_receiver_map = target_maps_and_handlers.at(0).first;
if (state() == MONOMORPHIC) {
Handle<Map> transitioned_receiver_map = new_receiver_map;
if (IsTransitionOfMonomorphicTarget(*previous_receiver_map,
......@@ -1823,11 +1850,11 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
DCHECK(state() != GENERIC);
bool map_added =
AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
AddOneReceiverMapIfMissing(&target_maps_and_handlers, receiver_map);
if (IsTransitionOfMonomorphicTarget(*receiver_map, *new_receiver_map)) {
map_added |=
AddOneReceiverMapIfMissing(&target_receiver_maps, new_receiver_map);
AddOneReceiverMapIfMissing(&target_maps_and_handlers, new_receiver_map);
}
if (!map_added) {
......@@ -1839,7 +1866,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// If the maximum number of receiver maps has been exceeded, use the
// megamorphic version of the IC.
if (static_cast<int>(target_receiver_maps.size()) >
if (static_cast<int>(target_maps_and_handlers.size()) >
FLAG_max_polymorphic_map_count) {
return;
}
......@@ -1860,14 +1887,15 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
// use the megamorphic stub.
if (store_mode != STANDARD_STORE) {
size_t external_arrays = 0;
for (Handle<Map> map : target_receiver_maps) {
for (MapAndHandler map_and_handler : target_maps_and_handlers) {
Handle<Map> map = map_and_handler.first;
if (map->has_typed_array_elements()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
external_arrays++;
}
}
if (external_arrays != 0 &&
external_arrays != target_receiver_maps.size()) {
external_arrays != target_maps_and_handlers.size()) {
DCHECK(!IsStoreInArrayLiteralICKind(kind()));
set_slow_stub_reason(
"unsupported combination of external and normal arrays");
......@@ -1875,21 +1903,21 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
}
MaybeObjectHandles handlers;
handlers.reserve(target_receiver_maps.size());
StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
if (target_receiver_maps.size() == 0) {
StoreElementPolymorphicHandlers(&target_maps_and_handlers, store_mode);
if (target_maps_and_handlers.size() == 0) {
Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
ConfigureVectorState(Handle<Name>(), receiver_map, handler);
} else if (target_receiver_maps.size() == 1) {
ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
} else if (target_maps_and_handlers.size() == 1) {
ConfigureVectorState(Handle<Name>(), target_maps_and_handlers[0].first,
target_maps_and_handlers[0].second);
} else {
ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
ConfigureVectorState(Handle<Name>(), target_maps_and_handlers);
}
}
Handle<Object> KeyedStoreIC::StoreElementHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode,
MaybeHandle<Object> prev_validity_cell) {
DCHECK_IMPLIES(
receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()),
IsStoreInArrayLiteralICKind(kind()));
......@@ -1925,8 +1953,11 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
}
if (IsStoreInArrayLiteralICKind(kind())) return code;
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
Handle<Object> validity_cell;
if (!prev_validity_cell.ToHandle(&validity_cell)) {
validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
}
if (validity_cell->IsSmi()) {
// There's no prototype validity cell to check, so we can just use the stub.
return code;
......@@ -1938,16 +1969,17 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
}
void KeyedStoreIC::StoreElementPolymorphicHandlers(
MapHandles* receiver_maps, MaybeObjectHandles* handlers,
std::vector<MapAndHandler>* receiver_maps_and_handlers,
KeyedAccessStoreMode store_mode) {
// Filter out deprecated maps to ensure their instances get migrated.
receiver_maps->erase(
std::remove_if(
receiver_maps->begin(), receiver_maps->end(),
[](const Handle<Map>& map) { return map->is_deprecated(); }),
receiver_maps->end());
std::vector<Handle<Map>> receiver_maps;
for (size_t i = 0; i < receiver_maps_and_handlers->size(); i++) {
receiver_maps.push_back(receiver_maps_and_handlers->at(i).first);
}
for (Handle<Map> receiver_map : *receiver_maps) {
for (size_t i = 0; i < receiver_maps_and_handlers->size(); i++) {
Handle<Map> receiver_map = receiver_maps_and_handlers->at(i).first;
DCHECK(!receiver_map->is_deprecated());
MaybeObjectHandle old_handler = receiver_maps_and_handlers->at(i).second;
Handle<Object> handler;
Handle<Map> transition;
......@@ -1960,8 +1992,8 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
} else {
{
Map tmap = receiver_map->FindElementsKindTransitionedMap(
isolate(), *receiver_maps);
Map tmap = receiver_map->FindElementsKindTransitionedMap(isolate(),
receiver_maps);
if (!tmap.is_null()) {
if (receiver_map->is_stable()) {
receiver_map->NotifyLeafMapLayoutChange(isolate());
......@@ -1970,6 +2002,16 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
}
}
MaybeHandle<Object> validity_cell;
HeapObject old_handler_obj;
if (!old_handler.is_null() &&
old_handler->GetHeapObject(&old_handler_obj) &&
old_handler_obj.IsDataHandler()) {
validity_cell = MaybeHandle<Object>(
DataHandler::cast(old_handler_obj).validity_cell(), isolate());
}
// TODO(mythria): Do not recompute the handler if we know there is no
// change in the handler.
// TODO(mvstanton): The code below is doing pessimistic elements
// transitions. I would like to stop doing that and rely on Allocation
// Site Tracking to do a better job of ensuring the data types are what
......@@ -1978,14 +2020,15 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
if (!transition.is_null()) {
TRACE_HANDLER_STATS(isolate(),
KeyedStoreIC_ElementsTransitionAndStoreStub);
handler = StoreHandler::StoreElementTransition(isolate(), receiver_map,
transition, store_mode);
handler = StoreHandler::StoreElementTransition(
isolate(), receiver_map, transition, store_mode, validity_cell);
} else {
handler = StoreElementHandler(receiver_map, store_mode);
handler = StoreElementHandler(receiver_map, store_mode, validity_cell);
}
}
DCHECK(!handler.is_null());
handlers->push_back(MaybeObjectHandle(handler));
receiver_maps_and_handlers->at(i) =
MapAndHandler(receiver_map, MaybeObjectHandle(handler));
}
}
......
......@@ -82,6 +82,8 @@ class IC {
// Configure the vector for POLYMORPHIC.
void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
MaybeObjectHandles* handlers);
void ConfigureVectorState(
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
char TransitionMarkFromState(IC::State state);
void TraceIC(const char* type, Handle<Object> name);
......@@ -312,12 +314,13 @@ class KeyedStoreIC : public StoreIC {
Handle<Map> ComputeTransitionedMap(Handle<Map> map,
TransitionMode transition_mode);
Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
KeyedAccessStoreMode store_mode);
Handle<Object> StoreElementHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode,
MaybeHandle<Object> prev_validity_cell = MaybeHandle<Object>());
void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
MaybeObjectHandles* handlers,
KeyedAccessStoreMode store_mode);
void StoreElementPolymorphicHandlers(
std::vector<MapAndHandler>* receiver_maps_and_handlers,
KeyedAccessStoreMode store_mode);
friend class IC;
};
......
......@@ -916,11 +916,9 @@ void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
}
}
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
MapHandles const& maps,
MaybeObjectHandles* handlers) {
DCHECK_EQ(handlers->size(), maps.size());
int receiver_count = static_cast<int>(maps.size());
void FeedbackNexus::ConfigurePolymorphic(
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
int receiver_count = static_cast<int>(maps_and_handlers.size());
DCHECK_GT(receiver_count, 1);
Handle<WeakFixedArray> array;
if (name.is_null()) {
......@@ -933,10 +931,11 @@ void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
}
for (int current = 0; current < receiver_count; ++current) {
Handle<Map> map = maps[current];
Handle<Map> map = maps_and_handlers[current].first;
array->Set(current * 2, HeapObjectReference::Weak(*map));
DCHECK(IC::IsHandler(*handlers->at(current)));
array->Set(current * 2 + 1, *handlers->at(current));
MaybeObjectHandle handler = maps_and_handlers[current].second;
DCHECK(IC::IsHandler(*handler));
array->Set(current * 2 + 1, *handler);
}
}
......@@ -982,11 +981,13 @@ int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
return 0;
}
int FeedbackNexus::ExtractMapsAndHandlers(MapHandles* maps,
MaybeObjectHandles* handlers) const {
DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
int FeedbackNexus::ExtractMapsAndHandlers(
std::vector<std::pair<Handle<Map>, MaybeObjectHandle>>* maps_and_handlers,
bool drop_deprecated) const {
DCHECK(IsLoadICKind(kind()) ||
IsStoreICKind(kind()) | IsKeyedLoadICKind(kind()) ||
IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) ||
IsStoreDataPropertyInLiteralKind(kind()) ||
IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
DisallowHeapAllocation no_gc;
......@@ -1007,6 +1008,7 @@ int FeedbackNexus::ExtractMapsAndHandlers(MapHandles* maps,
}
const int increment = 2;
HeapObject heap_object;
maps_and_handlers->reserve(array.length() / increment);
for (int i = 0; i < array.length(); i += increment) {
DCHECK(array.Get(i)->IsWeakOrCleared());
if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
......@@ -1014,8 +1016,9 @@ int FeedbackNexus::ExtractMapsAndHandlers(MapHandles* maps,
if (!handler->IsCleared()) {
DCHECK(IC::IsHandler(handler));
Map map = Map::cast(heap_object);
maps->push_back(handle(map, isolate));
handlers->push_back(handle(handler, isolate));
if (drop_deprecated && map.is_deprecated()) continue;
maps_and_handlers->push_back(
MapAndHandler(handle(map, isolate), handle(handler, isolate)));
found++;
}
}
......@@ -1026,8 +1029,9 @@ int FeedbackNexus::ExtractMapsAndHandlers(MapHandles* maps,
if (!handler->IsCleared()) {
DCHECK(IC::IsHandler(handler));
Map map = Map::cast(heap_object);
maps->push_back(handle(map, isolate));
handlers->push_back(handle(handler, isolate));
if (drop_deprecated && map.is_deprecated()) return 0;
maps_and_handlers->push_back(
MapAndHandler(handle(map, isolate), handle(handler, isolate)));
return 1;
}
}
......@@ -1099,14 +1103,14 @@ Name FeedbackNexus::GetName() const {
KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
MapHandles maps;
MaybeObjectHandles handlers;
if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
ExtractMapsAndHandlers(&maps, &handlers);
for (MaybeObjectHandle const& handler : handlers) {
KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
std::vector<MapAndHandler> maps_and_handlers;
ExtractMapsAndHandlers(&maps_and_handlers);
for (MapAndHandler map_and_handler : maps_and_handlers) {
KeyedAccessLoadMode mode =
LoadHandler::GetKeyedAccessLoadMode(*map_and_handler.second);
if (mode != STANDARD_LOAD) return mode;
}
......@@ -1167,13 +1171,13 @@ KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()) ||
IsStoreDataPropertyInLiteralKind(kind()));
KeyedAccessStoreMode mode = STANDARD_STORE;
MapHandles maps;
MaybeObjectHandles handlers;
if (GetKeyType() == PROPERTY) return mode;
ExtractMapsAndHandlers(&maps, &handlers);
for (const MaybeObjectHandle& maybe_code_handler : handlers) {
std::vector<MapAndHandler> maps_and_handlers;
ExtractMapsAndHandlers(&maps_and_handlers);
for (const MapAndHandler& map_and_handler : maps_and_handlers) {
const MaybeObjectHandle maybe_code_handler = map_and_handler.second;
// The first handler that isn't the slow handler will have the bits we need.
Handle<Code> handler;
if (maybe_code_handler.object()->IsStoreHandler()) {
......
......@@ -59,6 +59,8 @@ enum class FeedbackSlotKind {
kKindsNumber // Last value indicating number of kinds.
};
using MapAndHandler = std::pair<Handle<Map>, MaybeObjectHandle>;
inline bool IsCallICKind(FeedbackSlotKind kind) {
return kind == FeedbackSlotKind::kCall;
}
......@@ -648,8 +650,8 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
Map GetFirstMap() const;
int ExtractMaps(MapHandles* maps) const;
int ExtractMapsAndHandlers(MapHandles* maps,
MaybeObjectHandles* handlers) const;
int ExtractMapsAndHandlers(std::vector<MapAndHandler>* maps_and_handlers,
bool drop_deprecated = false) const;
MaybeObjectHandle FindHandlerForMap(Handle<Map> map) const;
bool IsCleared() const {
......@@ -673,8 +675,8 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
const MaybeObjectHandle& handler);
void ConfigurePolymorphic(Handle<Name> name, MapHandles const& maps,
MaybeObjectHandles* handlers);
void ConfigurePolymorphic(
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
BinaryOperationHint GetBinaryOperationFeedback() const;
CompareOperationHint GetCompareOperationFeedback() const;
......
// Copyright 2019 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: --no-lazy-feedback-allocation
function foo(a, b) {
a[b] = 1;
return a[b];
}
v = [];
assertEquals(foo(v, 1), 1);
v.__proto__.__proto__ = new Int32Array();
assertEquals(foo(Object(), 1), 1);
assertEquals(foo(v, 2), undefined);
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