Commit 6070e74d authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Preprocess feedback for ElementAccessInfo computation.

When --concurrent_inlining is on, precompute (during serialization)
the list of receiver maps and the transition matrix of element
accesses.

Bug: v8:7790
Change-Id: I257eaea630f33831ab6600851ccdf297e17e35ca
Reviewed-on: https://chromium-review.googlesource.com/c/1475769
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59863}
parent 0686bf7b
...@@ -24,21 +24,6 @@ namespace compiler { ...@@ -24,21 +24,6 @@ namespace compiler {
namespace { namespace {
bool CanInlineElementAccess(Handle<Map> map) {
if (!map->IsJSObjectMap()) return false;
if (map->is_access_check_needed()) return false;
if (map->has_indexed_interceptor()) return false;
ElementsKind const elements_kind = map->elements_kind();
if (IsFastElementsKind(elements_kind)) return true;
if (IsFixedTypedArrayElementsKind(elements_kind) &&
elements_kind != BIGUINT64_ELEMENTS &&
elements_kind != BIGINT64_ELEMENTS) {
return true;
}
return false;
}
bool CanInlinePropertyAccess(Handle<Map> map) { bool CanInlinePropertyAccess(Handle<Map> map) {
// We can inline property access to prototypes of all primitives, except // We can inline property access to prototypes of all primitives, except
// the special Oddball ones that have no wrapper counterparts (i.e. Null, // the special Oddball ones that have no wrapper counterparts (i.e. Null,
...@@ -267,62 +252,49 @@ bool AccessInfoFactory::ComputeElementAccessInfo( ...@@ -267,62 +252,49 @@ bool AccessInfoFactory::ComputeElementAccessInfo(
return true; return true;
} }
typedef std::vector<std::pair<Handle<Map>, Handle<Map>>> TransitionList; bool AccessInfoFactory::ComputeElementAccessInfos(
FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode,
namespace { ZoneVector<ElementAccessInfo>* access_infos) const {
void ProcessFeedbackMaps(Isolate* isolate, MapHandles const& maps, ProcessedFeedback processed(broker()->zone());
MapHandles* receiver_maps, ProcessFeedbackMapsForElementAccess(isolate(), maps, &processed);
TransitionList* transitions) {
DCHECK(receiver_maps->empty()); if (FLAG_concurrent_inlining) {
DCHECK(transitions->empty()); if (broker()->HasFeedback(nexus)) {
// We have already processed the feedback for this nexus during
// Collect possible transition targets. // serialization. Use that data instead of the data computed above.
MapHandles possible_transition_targets; ProcessedFeedback const& preprocessed =
possible_transition_targets.reserve(maps.size()); broker()->GetOrCreateFeedback(nexus);
for (Handle<Map> map : maps) { TRACE_BROKER(broker(),
if (CanInlineElementAccess(map) && "ComputeElementAccessInfos: using preprocessed feedback "
IsFastElementsKind(map->elements_kind()) && << "(slot " << nexus.slot() << " of "
GetInitialFastElementsKind() != map->elements_kind()) { << Brief(*nexus.vector_handle()) << "; "
possible_transition_targets.push_back(map); << preprocessed.receiver_maps.size() << "/"
} << preprocessed.transitions.size() << " vs "
} << processed.receiver_maps.size() << "/"
<< processed.transitions.size() << ").\n");
// Separate the actual receiver maps and the possible transition sources. processed.receiver_maps = preprocessed.receiver_maps;
for (Handle<Map> map : maps) { processed.transitions = preprocessed.transitions;
// Don't generate elements kind transitions from stable maps.
Map transition_target = map->is_stable()
? Map()
: map->FindElementsKindTransitionedMap(
isolate, possible_transition_targets);
if (transition_target.is_null()) {
receiver_maps->push_back(map);
} else { } else {
transitions->emplace_back(map, handle(transition_target, isolate)); TRACE_BROKER(broker(),
"ComputeElementAccessInfos: missing preprocessed feedback "
<< "(slot " << nexus.slot() << " of "
<< Brief(*nexus.vector_handle()) << ").\n");
} }
} }
}
} // namespace
bool AccessInfoFactory::ComputeElementAccessInfos(
MapHandles const& maps, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) const {
if (access_mode == AccessMode::kLoad) { if (access_mode == AccessMode::kLoad) {
// For polymorphic loads of similar elements kinds (i.e. all tagged or all // For polymorphic loads of similar elements kinds (i.e. all tagged or all
// double), always use the "worst case" code without a transition. This is // double), always use the "worst case" code without a transition. This is
// much faster than transitioning the elements to the worst case, trading a // much faster than transitioning the elements to the worst case, trading a
// TransitionElementsKind for a CheckMaps, avoiding mutation of the array. // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
ElementAccessInfo access_info; ElementAccessInfo access_info;
if (ConsolidateElementLoad(maps, &access_info)) { if (ConsolidateElementLoad(processed, &access_info)) {
access_infos->push_back(access_info); access_infos->push_back(access_info);
return true; return true;
} }
} }
MapHandles receiver_maps; for (Handle<Map> receiver_map : processed.receiver_maps) {
TransitionList transitions;
ProcessFeedbackMaps(isolate(), maps, &receiver_maps, &transitions);
for (Handle<Map> receiver_map : receiver_maps) {
// Compute the element access information. // Compute the element access information.
ElementAccessInfo access_info; ElementAccessInfo access_info;
if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) { if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
...@@ -330,7 +302,7 @@ bool AccessInfoFactory::ComputeElementAccessInfos( ...@@ -330,7 +302,7 @@ bool AccessInfoFactory::ComputeElementAccessInfos(
} }
// Collect the possible transitions for the {receiver_map}. // Collect the possible transitions for the {receiver_map}.
for (auto transition : transitions) { for (auto transition : processed.transitions) {
if (transition.second.is_identical_to(receiver_map)) { if (transition.second.is_identical_to(receiver_map)) {
access_info.AddTransitionSource(transition.first); access_info.AddTransitionSource(transition.first);
} }
...@@ -633,11 +605,15 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind, ...@@ -633,11 +605,15 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
} // namespace } // namespace
bool AccessInfoFactory::ConsolidateElementLoad( bool AccessInfoFactory::ConsolidateElementLoad(
MapHandles const& maps, ElementAccessInfo* access_info) const { ProcessedFeedback const& processed, ElementAccessInfo* access_info) const {
CHECK(!maps.empty()); CHECK(!processed.receiver_maps.empty());
InstanceType instance_type = maps.front()->instance_type();
ElementsKind elements_kind = maps.front()->elements_kind(); // We want to look at each map but the maps are split across
for (Handle<Map> map : maps) { // {processed.receiver_maps} and {processed.transitions}.
InstanceType instance_type = processed.receiver_maps.front()->instance_type();
ElementsKind elements_kind = processed.receiver_maps.front()->elements_kind();
auto processMap = [&](Handle<Map> map) {
if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) { if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
return false; return false;
} }
...@@ -645,7 +621,22 @@ bool AccessInfoFactory::ConsolidateElementLoad( ...@@ -645,7 +621,22 @@ bool AccessInfoFactory::ConsolidateElementLoad(
.To(&elements_kind)) { .To(&elements_kind)) {
return false; return false;
} }
return true;
};
for (Handle<Map> map : processed.receiver_maps) {
if (!processMap(map)) return false;
} }
MapHandles maps(processed.receiver_maps.begin(),
processed.receiver_maps.end());
for (auto& pair : processed.transitions) {
if (!processMap(pair.first) || !processMap(pair.second)) return false;
maps.push_back(pair.first);
maps.push_back(pair.second);
}
// {maps} may now contain duplicate entries, but that shouldn't matter.
*access_info = ElementAccessInfo(maps, elements_kind); *access_info = ElementAccessInfo(maps, elements_kind);
return true; return true;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <iosfwd> #include <iosfwd>
#include "src/compiler/types.h" #include "src/compiler/types.h"
#include "src/feedback-vector.h"
#include "src/field-index.h" #include "src/field-index.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "src/objects.h" #include "src/objects.h"
...@@ -26,6 +27,7 @@ namespace compiler { ...@@ -26,6 +27,7 @@ namespace compiler {
class CompilationDependencies; class CompilationDependencies;
class Type; class Type;
class TypeCache; class TypeCache;
struct ProcessedFeedback;
// Whether we are loading a property or storing to a property. // Whether we are loading a property or storing to a property.
// For a store during literal creation, do not walk up the prototype chain. // For a store during literal creation, do not walk up the prototype chain.
...@@ -150,7 +152,7 @@ class AccessInfoFactory final { ...@@ -150,7 +152,7 @@ class AccessInfoFactory final {
bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode, bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode,
ElementAccessInfo* access_info) const; ElementAccessInfo* access_info) const;
bool ComputeElementAccessInfos( bool ComputeElementAccessInfos(
MapHandles const& maps, AccessMode access_mode, FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) const; ZoneVector<ElementAccessInfo>* access_infos) const;
bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name, bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name,
...@@ -164,7 +166,7 @@ class AccessInfoFactory final { ...@@ -164,7 +166,7 @@ class AccessInfoFactory final {
ZoneVector<PropertyAccessInfo>* access_infos) const; ZoneVector<PropertyAccessInfo>* access_infos) const;
private: private:
bool ConsolidateElementLoad(MapHandles const& maps, bool ConsolidateElementLoad(ProcessedFeedback const& processed,
ElementAccessInfo* access_info) const; ElementAccessInfo* access_info) const;
bool LookupSpecialFieldAccessor(Handle<Map> map, Handle<Name> name, bool LookupSpecialFieldAccessor(Handle<Map> map, Handle<Name> name,
PropertyAccessInfo* access_info) const; PropertyAccessInfo* access_info) const;
......
...@@ -1572,7 +1572,8 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone) ...@@ -1572,7 +1572,8 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone)
current_zone_(broker_zone), current_zone_(broker_zone),
refs_(new (zone()) refs_(new (zone())
RefsMap(kMinimalRefsBucketCount, AddressMatcher(), zone())), RefsMap(kMinimalRefsBucketCount, AddressMatcher(), zone())),
array_and_object_prototypes_(zone()) { array_and_object_prototypes_(zone()),
feedback_(zone()) {
// Note that this initialization of the refs_ pointer with the minimal // Note that this initialization of the refs_ pointer with the minimal
// initial capacity is redundant in the normal use case (concurrent // initial capacity is redundant in the normal use case (concurrent
// compilation enabled, standard objects to be serialized), as the map // compilation enabled, standard objects to be serialized), as the map
...@@ -2756,6 +2757,66 @@ void JSBoundFunctionRef::Serialize() { ...@@ -2756,6 +2757,66 @@ void JSBoundFunctionRef::Serialize() {
data()->AsJSBoundFunction()->Serialize(broker()); data()->AsJSBoundFunction()->Serialize(broker());
} }
bool CanInlineElementAccess(Handle<Map> map) {
if (!map->IsJSObjectMap()) return false;
if (map->is_access_check_needed()) return false;
if (map->has_indexed_interceptor()) return false;
ElementsKind const elements_kind = map->elements_kind();
if (IsFastElementsKind(elements_kind)) return true;
if (IsFixedTypedArrayElementsKind(elements_kind) &&
elements_kind != BIGUINT64_ELEMENTS &&
elements_kind != BIGINT64_ELEMENTS) {
return true;
}
return false;
}
bool JSHeapBroker::HasFeedback(FeedbackNexus const& nexus) const {
return feedback_.find(nexus) != feedback_.end();
}
ProcessedFeedback& JSHeapBroker::GetOrCreateFeedback(
FeedbackNexus const& nexus) {
auto it = feedback_.find(nexus);
if (it != feedback_.end()) return it->second;
auto insertion = feedback_.insert({nexus, ProcessedFeedback(zone())});
CHECK(insertion.second);
return insertion.first->second;
}
void ProcessFeedbackMapsForElementAccess(Isolate* isolate,
MapHandles const& maps,
ProcessedFeedback* processed) {
DCHECK(processed->receiver_maps.empty());
DCHECK(processed->transitions.empty());
// Collect possible transition targets.
MapHandles possible_transition_targets;
possible_transition_targets.reserve(maps.size());
for (Handle<Map> map : maps) {
if (CanInlineElementAccess(map) &&
IsFastElementsKind(map->elements_kind()) &&
GetInitialFastElementsKind() != map->elements_kind()) {
possible_transition_targets.push_back(map);
}
}
// Separate the actual receiver maps and the possible transition sources.
for (Handle<Map> map : maps) {
// Don't generate elements kind transitions from stable maps.
Map transition_target = map->is_stable()
? Map()
: map->FindElementsKindTransitionedMap(
isolate, possible_transition_targets);
if (transition_target.is_null()) {
processed->receiver_maps.push_back(map);
} else {
processed->transitions.emplace_back(map,
handle(transition_target, isolate));
}
}
}
#undef BIMODAL_ACCESSOR #undef BIMODAL_ACCESSOR
#undef BIMODAL_ACCESSOR_B #undef BIMODAL_ACCESSOR_B
#undef BIMODAL_ACCESSOR_C #undef BIMODAL_ACCESSOR_C
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/base/optional.h" #include "src/base/optional.h"
#include "src/compiler/refs-map.h" #include "src/compiler/refs-map.h"
#include "src/feedback-vector.h"
#include "src/function-kind.h" #include "src/function-kind.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/handles.h" #include "src/handles.h"
...@@ -615,9 +616,18 @@ class InternalizedStringRef : public StringRef { ...@@ -615,9 +616,18 @@ class InternalizedStringRef : public StringRef {
static const uint32_t kNotAnArrayIndex = -1; // 2^32-1 is not a valid index. static const uint32_t kNotAnArrayIndex = -1; // 2^32-1 is not a valid index.
}; };
struct ProcessedFeedback {
ZoneVector<Handle<Map>> receiver_maps;
ZoneVector<std::pair<Handle<Map>, Handle<Map>>> transitions;
explicit ProcessedFeedback(Zone* zone)
: receiver_maps(zone), transitions(zone) {}
};
class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) { class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
public: public:
JSHeapBroker(Isolate* isolate, Zone* broker_zone); JSHeapBroker(Isolate* isolate, Zone* broker_zone);
void SetNativeContextRef(); void SetNativeContextRef();
void SerializeStandardObjects(); void SerializeStandardObjects();
...@@ -644,8 +654,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -644,8 +654,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
// %ObjectPrototype%. // %ObjectPrototype%.
bool IsArrayOrObjectPrototype(const JSObjectRef& object) const; bool IsArrayOrObjectPrototype(const JSObjectRef& object) const;
std::ostream& Trace(); bool HasFeedback(FeedbackNexus const& nexus) const;
ProcessedFeedback& GetOrCreateFeedback(FeedbackNexus const& nexus);
std::ostream& Trace();
void IncrementTracingIndentation(); void IncrementTracingIndentation();
void DecrementTracingIndentation(); void DecrementTracingIndentation();
...@@ -657,6 +669,18 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -657,6 +669,18 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
void SerializeShareableObjects(); void SerializeShareableObjects();
void CollectArrayAndObjectPrototypes(); void CollectArrayAndObjectPrototypes();
struct FeedbackNexusHash {
size_t operator()(FeedbackNexus const& nexus) const {
return base::hash_combine(nexus.vector_handle().location(), nexus.slot());
}
};
struct FeedbackNexusEqual {
bool operator()(FeedbackNexus const& lhs, FeedbackNexus const& rhs) const {
return lhs.vector_handle().equals(rhs.vector_handle()) &&
lhs.slot() == rhs.slot();
}
};
Isolate* const isolate_; Isolate* const isolate_;
Zone* const broker_zone_; Zone* const broker_zone_;
Zone* current_zone_; Zone* current_zone_;
...@@ -669,6 +693,9 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -669,6 +693,9 @@ class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
StdoutStream trace_out_; StdoutStream trace_out_;
unsigned trace_indentation_ = 0; unsigned trace_indentation_ = 0;
PerIsolateCompilerCache* compiler_cache_; PerIsolateCompilerCache* compiler_cache_;
ZoneUnorderedMap<FeedbackNexus, ProcessedFeedback, FeedbackNexusHash,
FeedbackNexusEqual>
feedback_;
static const size_t kMinimalRefsBucketCount = 8; // must be power of 2 static const size_t kMinimalRefsBucketCount = 8; // must be power of 2
static const size_t kInitialRefsBucketCount = 1024; // must be power of 2 static const size_t kInitialRefsBucketCount = 1024; // must be power of 2
...@@ -685,6 +712,13 @@ class Reduction; ...@@ -685,6 +712,13 @@ class Reduction;
Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker, Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker,
const char* function, int line); const char* function, int line);
// Miscellaneous definitions that should be moved elsewhere once concurrent
// compilation is finished.
bool CanInlineElementAccess(Handle<Map> map);
void ProcessFeedbackMapsForElementAccess(Isolate* isolate,
MapHandles const& maps,
ProcessedFeedback* processed);
#define TRACE_BROKER(broker, x) \ #define TRACE_BROKER(broker, x) \
do { \ do { \
if (FLAG_trace_heap_broker) broker->Trace() << x << '\n'; \ if (FLAG_trace_heap_broker) broker->Trace() << x << '\n'; \
......
...@@ -1500,9 +1500,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccessOnString( ...@@ -1500,9 +1500,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
} }
Reduction JSNativeContextSpecialization::ReduceElementAccess( Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* node, Node* index, Node* value, MapHandles const& receiver_maps, Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
AccessMode access_mode, KeyedAccessLoadMode load_mode, MapHandles const& receiver_maps, AccessMode access_mode,
KeyedAccessStoreMode store_mode) { KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty || node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral); node->opcode() == IrOpcode::kJSStoreInArrayLiteral);
...@@ -1520,8 +1520,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -1520,8 +1520,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
ZoneVector<ElementAccessInfo> access_infos(zone()); ZoneVector<ElementAccessInfo> access_infos(zone());
if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode, if (!access_info_factory.ComputeElementAccessInfos(
&access_infos)) { nexus, receiver_maps, access_mode, &access_infos)) {
return NoChange(); return NoChange();
} }
...@@ -1856,8 +1856,8 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1856,8 +1856,8 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
} }
// Try to lower the element access based on the {receiver_maps}. // Try to lower the element access based on the {receiver_maps}.
return ReduceElementAccess(node, index, value, receiver_maps, access_mode, return ReduceElementAccess(node, index, value, nexus, receiver_maps,
load_mode, store_mode); access_mode, load_mode, store_mode);
} }
Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize( Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
...@@ -2513,7 +2513,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral( ...@@ -2513,7 +2513,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
if (nexus.ic_state() == MEGAMORPHIC) return NoChange(); if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
// Try to lower the element access based on the {receiver_maps}. // Try to lower the element access based on the {receiver_maps}.
return ReduceElementAccess(node, index, value, receiver_maps, return ReduceElementAccess(node, index, value, nexus, receiver_maps,
AccessMode::kStoreInLiteral, STANDARD_LOAD, AccessMode::kStoreInLiteral, STANDARD_LOAD,
store_mode); store_mode);
} }
......
...@@ -92,6 +92,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final ...@@ -92,6 +92,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceJSToObject(Node* node); Reduction ReduceJSToObject(Node* node);
Reduction ReduceElementAccess(Node* node, Node* index, Node* value, Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
FeedbackNexus const& nexus,
MapHandles const& receiver_maps, MapHandles const& receiver_maps,
AccessMode access_mode, AccessMode access_mode,
KeyedAccessLoadMode load_mode, KeyedAccessLoadMode load_mode,
......
...@@ -683,6 +683,59 @@ void SerializerForBackgroundCompilation::VisitConstructWithSpread( ...@@ -683,6 +683,59 @@ void SerializerForBackgroundCompilation::VisitConstructWithSpread(
ProcessCallOrConstruct(callee, new_target, arguments, slot, true); ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
} }
void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
BytecodeArrayIterator* iterator) {
interpreter::Bytecode bytecode = iterator->current_bytecode();
DCHECK(bytecode == interpreter::Bytecode::kLdaKeyedProperty ||
bytecode == interpreter::Bytecode::kStaKeyedProperty ||
bytecode == interpreter::Bytecode::kStaInArrayLiteral);
if (environment()->function().feedback_vector.is_null()) return;
FeedbackSlot slot = iterator->GetSlotOperand(
bytecode == interpreter::Bytecode::kLdaKeyedProperty ? 1 : 2);
if (slot.IsInvalid()) return;
FeedbackNexus nexus(environment()->function().feedback_vector, slot);
if (broker()->HasFeedback(nexus)) return;
Handle<Name> name(nexus.GetName(), broker()->isolate());
CHECK_IMPLIES(nexus.GetKeyType() == ELEMENT, name->is_null());
if (!name->is_null() || nexus.GetKeyType() == PROPERTY) {
CHECK_NE(bytecode, interpreter::Bytecode::kStaInArrayLiteral);
return; // TODO(neis): Support named access.
}
if (nexus.ic_state() == MEGAMORPHIC) {
return;
}
ProcessedFeedback& processed = broker()->GetOrCreateFeedback(nexus);
MapHandles maps;
nexus.ExtractMaps(&maps);
ProcessFeedbackMapsForElementAccess(broker()->isolate(), maps, &processed);
// TODO(neis): Have something like MapRef::SerializeForElementStore() and call
// it for every receiver map in case of an element store.
}
void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
ProcessFeedbackForKeyedPropertyAccess(iterator);
}
void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
ProcessFeedbackForKeyedPropertyAccess(iterator);
}
void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
ProcessFeedbackForKeyedPropertyAccess(iterator);
}
#define DEFINE_CLEAR_ENVIRONMENT(name, ...) \ #define DEFINE_CLEAR_ENVIRONMENT(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \ void SerializerForBackgroundCompilation::Visit##name( \
BytecodeArrayIterator* iterator) { \ BytecodeArrayIterator* iterator) { \
......
...@@ -57,7 +57,6 @@ namespace compiler { ...@@ -57,7 +57,6 @@ namespace compiler {
V(LdaGlobalInsideTypeof) \ V(LdaGlobalInsideTypeof) \
V(LdaImmutableContextSlot) \ V(LdaImmutableContextSlot) \
V(LdaImmutableCurrentContextSlot) \ V(LdaImmutableCurrentContextSlot) \
V(LdaKeyedProperty) \
V(LdaNamedProperty) \ V(LdaNamedProperty) \
V(LdaNamedPropertyNoFeedback) V(LdaNamedPropertyNoFeedback)
...@@ -122,6 +121,7 @@ namespace compiler { ...@@ -122,6 +121,7 @@ namespace compiler {
V(ExtraWide) \ V(ExtraWide) \
V(Illegal) \ V(Illegal) \
V(LdaConstant) \ V(LdaConstant) \
V(LdaKeyedProperty) \
V(LdaNull) \ V(LdaNull) \
V(Ldar) \ V(Ldar) \
V(LdaSmi) \ V(LdaSmi) \
...@@ -130,6 +130,8 @@ namespace compiler { ...@@ -130,6 +130,8 @@ namespace compiler {
V(Mov) \ V(Mov) \
V(Return) \ V(Return) \
V(StackCheck) \ V(StackCheck) \
V(StaInArrayLiteral) \
V(StaKeyedProperty) \
V(Star) \ V(Star) \
V(Wide) \ V(Wide) \
CLEAR_ENVIRONMENT_LIST(V) \ CLEAR_ENVIRONMENT_LIST(V) \
...@@ -241,6 +243,9 @@ class SerializerForBackgroundCompilation { ...@@ -241,6 +243,9 @@ class SerializerForBackgroundCompilation {
base::Optional<Hints> new_target, base::Optional<Hints> new_target,
const HintsVector& arguments, bool with_spread); const HintsVector& arguments, bool with_spread);
void ProcessFeedbackForKeyedPropertyAccess(
interpreter::BytecodeArrayIterator* iterator);
JSHeapBroker* broker() const { return broker_; } JSHeapBroker* broker() const { return broker_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
Environment* environment() const { return environment_; } Environment* environment() const { return environment_; }
......
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