Commit 02892ad2 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Remove most remaining heap accesses from property loads

A few are still left and made explicit with Allow* scopes.

Bug: v8:7790
Change-Id: I85e78949730d046d3449e0cee70997e60a043825
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1622108
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62310}
parent dd65ef6a
......@@ -258,9 +258,9 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
}
}
Handle<Cell> PropertyAccessInfo::export_cell() const {
CellRef PropertyAccessInfo::export_cell(JSHeapBroker* broker) const {
DCHECK_EQ(kModuleExport, kind_);
return Handle<Cell>::cast(constant_);
return ObjectRef(broker, constant_).AsCell();
}
AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
......@@ -793,6 +793,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
unrecorded_dependencies.push_back(
dependencies()->TransitionDependencyOffTheRecord(
MapRef(broker(), transition_map)));
transition_map_ref.SerializeBackPointer(); // For BuildPropertyStore.
// Transitioning stores *may* store to const fields. The resulting
// DataConstant access infos can be distinguished from later, i.e. redundant,
// stores to the same constant field by the presence of a transition map.
......
......@@ -127,7 +127,7 @@ class PropertyAccessInfo final {
ZoneVector<Handle<Map>> const& receiver_maps() const {
return receiver_maps_;
}
Handle<Cell> export_cell() const;
CellRef export_cell(JSHeapBroker* broker) const;
private:
explicit PropertyAccessInfo(Zone* zone);
......
......@@ -565,6 +565,11 @@ namespace {
// This function expects to never see a JSProxy.
void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
base::Optional<JSObjectRef> last_prototype) {
// TODO(neis): Remove heap access (SerializePrototype call).
AllowCodeDependencyChange dependency_change_;
AllowHandleAllocation handle_allocation_;
AllowHandleDereference handle_dereference_;
AllowHeapAllocation heap_allocation_;
while (true) {
map.SerializePrototype();
HeapObjectRef proto = map.prototype();
......
......@@ -3492,10 +3492,67 @@ base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantHint() const {
return {};
}
ElementAccessFeedback::ElementAccessFeedback(Zone* zone)
KeyedAccessMode KeyedAccessMode::FromNexus(FeedbackNexus const& nexus) {
if (IsKeyedLoadICKind(nexus.kind())) {
return KeyedAccessMode(AccessMode::kLoad, nexus.GetKeyedAccessLoadMode());
}
if (IsKeyedHasICKind(nexus.kind())) {
return KeyedAccessMode(AccessMode::kHas, nexus.GetKeyedAccessLoadMode());
}
if (IsKeyedStoreICKind(nexus.kind())) {
return KeyedAccessMode(AccessMode::kStore, nexus.GetKeyedAccessStoreMode());
}
if (IsStoreInArrayLiteralICKind(nexus.kind())) {
return KeyedAccessMode(AccessMode::kStoreInLiteral,
nexus.GetKeyedAccessStoreMode());
}
UNREACHABLE();
}
AccessMode KeyedAccessMode::access_mode() const { return access_mode_; }
bool KeyedAccessMode::IsLoad() const {
return access_mode_ == AccessMode::kLoad || access_mode_ == AccessMode::kHas;
}
bool KeyedAccessMode::IsStore() const {
return access_mode_ == AccessMode::kStore ||
access_mode_ == AccessMode::kStoreInLiteral;
}
KeyedAccessLoadMode KeyedAccessMode::load_mode() const {
CHECK(IsLoad());
return load_store_mode_.load_mode;
}
KeyedAccessStoreMode KeyedAccessMode::store_mode() const {
CHECK(IsStore());
return load_store_mode_.store_mode;
}
KeyedAccessMode::LoadStoreMode::LoadStoreMode(KeyedAccessLoadMode load_mode)
: load_mode(load_mode) {}
KeyedAccessMode::LoadStoreMode::LoadStoreMode(KeyedAccessStoreMode store_mode)
: store_mode(store_mode) {}
KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
KeyedAccessLoadMode load_mode)
: access_mode_(access_mode), load_store_mode_(load_mode) {
CHECK(!IsStore());
CHECK(IsLoad());
}
KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
KeyedAccessStoreMode store_mode)
: access_mode_(access_mode), load_store_mode_(store_mode) {
CHECK(!IsLoad());
CHECK(IsStore());
}
ElementAccessFeedback::ElementAccessFeedback(Zone* zone,
KeyedAccessMode const& keyed_mode)
: ProcessedFeedback(kElementAccess),
receiver_maps(zone),
transitions(zone) {}
transitions(zone),
keyed_mode(keyed_mode) {}
ElementAccessFeedback::MapIterator::MapIterator(
ElementAccessFeedback const& processed, JSHeapBroker* broker)
......@@ -3568,7 +3625,7 @@ GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
}
ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
MapHandles const& maps) {
MapHandles const& maps, KeyedAccessMode const& keyed_mode) {
DCHECK(!maps.empty());
// Collect possible transition targets.
......@@ -3582,7 +3639,8 @@ ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
}
}
ElementAccessFeedback* result = new (zone()) ElementAccessFeedback(zone());
ElementAccessFeedback* result =
new (zone()) ElementAccessFeedback(zone(), keyed_mode);
// Separate the actual receiver maps and the possible transition sources.
for (Handle<Map> map : maps) {
......
......@@ -777,15 +777,40 @@ class GlobalAccessFeedback : public ProcessedFeedback {
int const index_and_immutable_;
};
class KeyedAccessMode {
public:
static KeyedAccessMode FromNexus(FeedbackNexus const& nexus);
AccessMode access_mode() const;
bool IsLoad() const;
bool IsStore() const;
KeyedAccessLoadMode load_mode() const;
KeyedAccessStoreMode store_mode() const;
private:
AccessMode const access_mode_;
union LoadStoreMode {
LoadStoreMode(KeyedAccessLoadMode load_mode);
LoadStoreMode(KeyedAccessStoreMode store_mode);
KeyedAccessLoadMode load_mode;
KeyedAccessStoreMode store_mode;
} const load_store_mode_;
KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode);
KeyedAccessMode(AccessMode access_mode, KeyedAccessStoreMode store_mode);
};
class ElementAccessFeedback : public ProcessedFeedback {
public:
explicit ElementAccessFeedback(Zone* zone);
ElementAccessFeedback(Zone* zone, KeyedAccessMode const& keyed_mode);
// No transition sources appear in {receiver_maps}.
// All transition targets appear in {receiver_maps}.
ZoneVector<Handle<Map>> receiver_maps;
ZoneVector<std::pair<Handle<Map>, Handle<Map>>> transitions;
KeyedAccessMode const keyed_mode;
class MapIterator {
public:
bool done() const;
......@@ -901,7 +926,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
// TODO(neis): Move these into serializer when we're always in the background.
ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
MapHandles const& maps);
MapHandles const& maps, KeyedAccessMode const& keyed_mode);
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(
FeedbackSource const& source);
......
......@@ -93,24 +93,15 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceJSToObject(Node* node);
Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
ElementAccessFeedback const& processed,
AccessMode access_mode,
KeyedAccessLoadMode load_mode,
KeyedAccessStoreMode store_mode);
ElementAccessFeedback const& processed);
// In the case of non-keyed (named) accesses, pass the name as {static_name}
// and use {nullptr} for {key} (load/store modes are irrelevant).
Reduction ReducePropertyAccessUsingProcessedFeedback(
Node* node, Node* key, base::Optional<NameRef> static_name, Node* value,
FeedbackNexus const& nexus, AccessMode access_mode,
KeyedAccessLoadMode load_mode = STANDARD_LOAD,
KeyedAccessStoreMode store_mode = STANDARD_STORE);
Reduction ReduceKeyedAccess(Node* node, Node* key, Node* value,
FeedbackNexus const& nexus,
AccessMode access_mode,
KeyedAccessLoadMode load_mode,
KeyedAccessStoreMode store_mode);
Reduction ReducePropertyAccess(Node* node, Node* key,
base::Optional<NameRef> static_name,
Node* value, FeedbackSource const& source,
AccessMode access_mode);
Reduction ReduceNamedAccessFromNexus(Node* node, Node* value,
FeedbackNexus const& nexus,
FeedbackSource const& source,
NameRef const& name,
AccessMode access_mode);
Reduction ReduceNamedAccess(Node* node, Node* value,
......@@ -123,7 +114,6 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
NameRef const& name, AccessMode access_mode,
Node* key, PropertyCellRef const& property_cell);
Reduction ReduceKeyedLoadFromHeapConstant(Node* node, Node* key,
FeedbackNexus const& nexus,
AccessMode access_mode,
KeyedAccessLoadMode load_mode);
Reduction ReduceElementAccessOnString(Node* node, Node* index, Node* value,
......@@ -197,10 +187,11 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
FunctionTemplateInfoRef const& function_template_info);
// Construct the appropriate subgraph for element access.
ValueEffectControl BuildElementAccess(
Node* receiver, Node* index, Node* value, Node* effect, Node* control,
ElementAccessInfo const& access_info, AccessMode access_mode,
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode);
ValueEffectControl BuildElementAccess(Node* receiver, Node* index,
Node* value, Node* effect,
Node* control,
ElementAccessInfo const& access_info,
KeyedAccessMode const& keyed_mode);
// Construct appropriate subgraph to load from a String.
Node* BuildIndexedStringLoad(Node* receiver, Node* index, Node* length,
......
......@@ -127,7 +127,7 @@ Node* PropertyAccessBuilder::ResolveHolder(
PropertyAccessInfo const& access_info, Node* receiver) {
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
return jsgraph()->Constant(holder);
return jsgraph()->Constant(ObjectRef(broker(), holder));
}
return receiver;
}
......@@ -151,7 +151,16 @@ MachineRepresentation PropertyAccessBuilder::ConvertRepresentation(
Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
NameRef const& name, PropertyAccessInfo const& access_info,
Node* receiver) {
// TODO(neis): Eliminate FastPropertyAt call below by doing the lookup during
// acccess info computation. Requires extra care in the case where the
// receiver is the holder.
AllowCodeDependencyChange dependency_change_;
AllowHandleAllocation handle_allocation_;
AllowHandleDereference handle_dereference_;
AllowHeapAllocation heap_allocation_;
if (!access_info.IsDataConstant()) return nullptr;
// First, determine if we have a constant holder to load from.
Handle<JSObject> holder;
// If {access_info} has a holder, just use it.
......@@ -165,7 +174,7 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
MapRef receiver_map = m.Ref(broker()).map();
if (std::find_if(access_info.receiver_maps().begin(),
access_info.receiver_maps().end(), [&](Handle<Map> map) {
return map.address() == receiver_map.object().address();
return map.equals(receiver_map.object());
}) == access_info.receiver_maps().end()) {
// The map of the receiver is not in the feedback, let us bail out.
return nullptr;
......
......@@ -1075,9 +1075,10 @@ MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
ElementAccessFeedback const*
SerializerForBackgroundCompilation::ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode) {
const MapHandles& maps, AccessMode mode,
KeyedAccessMode const& keyed_mode) {
ElementAccessFeedback const* result =
broker()->ProcessFeedbackMapsForElementAccess(maps);
broker()->ProcessFeedbackMapsForElementAccess(maps, keyed_mode);
for (ElementAccessFeedback::MapIterator it = result->all_maps(broker());
!it.done(); it.advance()) {
switch (mode) {
......@@ -1145,8 +1146,10 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForPropertyAccess(
static_name.has_value() ? static_name : broker()->GetNameFeedback(nexus);
if (name.has_value()) {
processed = ProcessFeedbackMapsForNamedAccess(maps, mode, *name);
} else if (nexus.GetKeyType() == ELEMENT && nexus.ic_state() != MEGAMORPHIC) {
processed = ProcessFeedbackMapsForElementAccess(maps, mode);
} else if (nexus.GetKeyType() == ELEMENT) {
DCHECK_NE(nexus.ic_state(), MEGAMORPHIC);
processed = ProcessFeedbackMapsForElementAccess(
maps, mode, KeyedAccessMode::FromNexus(nexus));
}
broker()->SetFeedback(source, processed);
}
......
......@@ -341,7 +341,8 @@ class SerializerForBackgroundCompilation {
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
const MapHandles& maps, AccessMode mode, NameRef const& name);
ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode);
const MapHandles& maps, AccessMode mode,
KeyedAccessMode const& keyed_mode);
void ProcessFeedbackForPropertyAccess(FeedbackSlot slot, AccessMode mode,
base::Optional<NameRef> static_name);
void ProcessMapForNamedPropertyAccess(MapRef const& map, NameRef const& name);
......
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