Commit 05e862f7 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

Cache StoreIC-Transition handlers

extending existing transition target storage (so both inline storage
on the map, and the "target" slots in TransitionArrays are supported).

Change-Id: Ib360b9755b8ca5f08bc3a25dd27833f348badaf4
Reviewed-on: https://chromium-review.googlesource.com/584192
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47150}
parent 0caf1d20
......@@ -788,8 +788,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// corresponds.
if (fill_array) {
Handle<Context> native_context = isolate->native_context();
array->set(LoadHandler::kFirstPrototypeIndex + checks_count,
native_context->self_weak_cell());
array->set(first_index + checks_count, native_context->self_weak_cell());
}
checks_count++;
......@@ -802,7 +801,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
......@@ -1636,8 +1635,20 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (state() != UNINITIALIZED) {
JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
}
LookupIterator it(object, name);
if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
MaybeHandle<Object> cached_handler;
Handle<Map> transition_map;
if (object->IsJSReceiver()) {
name = isolate()->factory()->InternalizeName(name);
TransitionsAccessor transitions(receiver_map());
Object* maybe_handler = transitions.SearchHandler(*name, &transition_map);
if (maybe_handler != nullptr) {
cached_handler = MaybeHandle<Object>(maybe_handler, isolate());
}
}
LookupIterator it = LookupIterator::ForTransitionHandler(
isolate(), object, name, value, cached_handler, transition_map);
if (FLAG_use_ic) UpdateCaches(&it, value, store_mode, cached_handler);
MAYBE_RETURN_NULL(
Object::SetProperty(&it, value, language_mode(), store_mode));
......@@ -1645,7 +1656,8 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
}
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode) {
JSReceiver::StoreFromKeyed store_mode,
MaybeHandle<Object> cached_handler) {
if (state() == UNINITIALIZED) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
......@@ -1656,7 +1668,9 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
}
Handle<Object> handler;
if (LookupForWrite(lookup, value, store_mode)) {
if (!cached_handler.is_null()) {
handler = cached_handler.ToHandleChecked();
} else if (LookupForWrite(lookup, value, store_mode)) {
handler = ComputeHandler(lookup);
} else {
TRACE_GENERIC_IC("LookupForWrite said 'false'");
......@@ -1766,8 +1780,11 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK(lookup->IsCacheableTransition());
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
return StoreTransition(receiver_map(), holder, transition,
lookup->name());
Handle<Object> handler =
StoreTransition(receiver_map(), holder, transition, lookup->name());
TransitionsAccessor(receiver_map())
.UpdateHandler(*lookup->name(), *handler);
return handler;
}
case LookupIterator::INTERCEPTOR: {
......
......@@ -362,7 +362,8 @@ class StoreIC : public IC {
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode);
JSReceiver::StoreFromKeyed store_mode,
MaybeHandle<Object> cached_handler);
Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
Handle<Code> CompileHandler(LookupIterator* lookup) override;
......
......@@ -759,12 +759,11 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
{
Comment("fast property store");
Node* descriptors = LoadMapDescriptors(receiver_map);
Label descriptor_found(this);
Label descriptor_found(this), lookup_transition(this);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
// TODO(jkummerow): Maybe look for existing map transitions?
Label* notfound = use_stub_cache == kUseStubCache ? &stub_cache : slow;
DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found,
&var_name_index, notfound);
&var_name_index, &lookup_transition);
BIND(&descriptor_found);
{
......@@ -792,6 +791,59 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Return(p->value);
}
}
BIND(&lookup_transition);
{
Comment("lookup transition");
VARIABLE(var_handler, MachineRepresentation::kTagged);
Label tuple3(this), fixedarray(this), found_handler(this, &var_handler);
Node* maybe_handler =
LoadObjectField(receiver_map, Map::kTransitionsOrPrototypeInfoOffset);
GotoIf(TaggedIsSmi(maybe_handler), notfound);
Node* handler_map = LoadMap(maybe_handler);
GotoIf(WordEqual(handler_map, Tuple3MapConstant()), &tuple3);
GotoIf(WordEqual(handler_map, FixedArrayMapConstant()), &fixedarray);
// TODO(jkummerow): Consider implementing TransitionArray search.
Goto(notfound);
VARIABLE(var_transition_cell, MachineRepresentation::kTagged);
Label check_key(this, &var_transition_cell);
BIND(&tuple3);
{
var_transition_cell.Bind(LoadObjectField(
maybe_handler, StoreHandler::kTransitionCellOffset));
Goto(&check_key);
}
BIND(&fixedarray);
{
var_transition_cell.Bind(LoadFixedArrayElement(
maybe_handler, StoreHandler::kTransitionCellIndex));
Goto(&check_key);
}
BIND(&check_key);
{
Node* transition = LoadWeakCellValue(var_transition_cell.value(), slow);
Node* transition_bitfield3 = LoadMapBitField3(transition);
GotoIf(IsSetWord32<Map::Deprecated>(transition_bitfield3), slow);
Node* nof =
DecodeWord32<Map::NumberOfOwnDescriptorsBits>(transition_bitfield3);
Node* last_added = Int32Sub(nof, Int32Constant(1));
Node* transition_descriptors = LoadMapDescriptors(transition);
Node* key = DescriptorArrayGetKey(transition_descriptors, last_added);
GotoIf(WordNotEqual(key, p->name), slow);
var_handler.Bind(maybe_handler);
Goto(&found_handler);
}
BIND(&found_handler);
{
Comment("KeyedStoreGeneric found transition handler");
HandleStoreICHandlerCase(p, var_handler.value(), notfound);
}
}
}
BIND(&dictionary_properties);
......
......@@ -44,6 +44,67 @@ LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
return LookupIterator(receiver, name, configuration);
}
// static
LookupIterator LookupIterator::ForTransitionHandler(
Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
Handle<Object> value, MaybeHandle<Object> handler,
Handle<Map> transition_map) {
if (handler.is_null()) return LookupIterator(receiver, name);
PropertyDetails details = PropertyDetails::Empty();
bool has_property;
if (transition_map->is_dictionary_map()) {
details = PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
has_property = false;
} else {
details = transition_map->GetLastDescriptorDetails();
has_property = true;
}
LookupIterator it(isolate, receiver, name, transition_map, details,
has_property);
if (!transition_map->is_dictionary_map()) {
PropertyConstness new_constness = kConst;
if (FLAG_track_constant_fields) {
if (it.constness() == kConst) {
DCHECK_EQ(kData, it.property_details_.kind());
// Check that current value matches new value otherwise we should make
// the property mutable.
if (!it.IsConstFieldValueEqualTo(*value)) new_constness = kMutable;
}
} else {
new_constness = kMutable;
}
int descriptor_number = transition_map->LastAdded();
Handle<Map> new_map = Map::PrepareForDataProperty(
transition_map, descriptor_number, new_constness, value);
// Reload information; this is no-op if nothing changed.
it.property_details_ =
new_map->instance_descriptors()->GetDetails(descriptor_number);
it.transition_ = new_map;
}
return it;
}
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name, Handle<Map> transition_map,
PropertyDetails details, bool has_property)
: configuration_(DEFAULT),
state_(TRANSITION),
has_property_(has_property),
interceptor_state_(InterceptorState::kUninitialized),
property_details_(details),
isolate_(isolate),
name_(name),
transition_(transition_map),
receiver_(receiver),
initial_holder_(GetRoot(isolate, receiver)),
index_(kMaxUInt32),
number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
holder_ = initial_holder_;
}
template <bool is_element>
void LookupIterator::Start() {
DisallowHeapAllocation no_gc;
......
......@@ -130,6 +130,13 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
bool* success, Configuration configuration = DEFAULT);
static LookupIterator ForTransitionHandler(Isolate* isolate,
Handle<Object> receiver,
Handle<Name> name,
Handle<Object> value,
MaybeHandle<Object> handler,
Handle<Map> transition_map);
void Restart() {
InterceptorState state = InterceptorState::kUninitialized;
IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
......@@ -277,6 +284,11 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
bool LookupCachedProperty();
private:
// For |ForTransitionHandler|.
LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
Handle<Map> transition_map, PropertyDetails details,
bool has_property);
void InternalUpdateProtector();
enum class InterceptorState {
......
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