[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: Jaroslav Sevcik <jarin@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#62310}
This commit is contained in:
parent
dd65ef6a9a
commit
02892ad221
@ -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);
|
||||
|
||||
|
@ -969,9 +969,8 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
|
||||
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
|
||||
|
||||
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
|
||||
LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackSource source(p.feedback());
|
||||
@ -1001,9 +1000,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
|
||||
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
|
||||
|
||||
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
|
||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||
|
||||
StoreGlobalParameters const& p = StoreGlobalParametersOf(node->op());
|
||||
@ -1292,7 +1290,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
|
||||
Node* node, Node* value, FeedbackNexus const& nexus, NameRef const& name,
|
||||
Node* node, Node* value, FeedbackSource const& source, NameRef const& name,
|
||||
AccessMode access_mode) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
|
||||
node->opcode() == IrOpcode::kJSStoreNamed ||
|
||||
@ -1306,11 +1304,11 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
|
||||
return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
|
||||
}
|
||||
|
||||
return ReducePropertyAccessUsingProcessedFeedback(node, nullptr, name, value,
|
||||
nexus, access_mode);
|
||||
return ReducePropertyAccess(node, nullptr, name, value, source, access_mode);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
|
||||
NamedAccess const& p = NamedAccessOf(node->op());
|
||||
Node* const receiver = NodeProperties::GetValueInput(node, 0);
|
||||
@ -1349,40 +1347,32 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
// Extract receiver maps from the load IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Try to lower the named access based on the {receiver_maps}.
|
||||
return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, name,
|
||||
return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(),
|
||||
FeedbackSource(p.feedback()), name,
|
||||
AccessMode::kLoad);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
|
||||
NamedAccess const& p = NamedAccessOf(node->op());
|
||||
Node* const value = NodeProperties::GetValueInput(node, 1);
|
||||
|
||||
// Extract receiver maps from the store IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Try to lower the named access based on the {receiver_maps}.
|
||||
return ReduceNamedAccessFromNexus(
|
||||
node, value, nexus, NameRef(broker(), p.name()), AccessMode::kStore);
|
||||
return ReduceNamedAccessFromNexus(node, value, FeedbackSource(p.feedback()),
|
||||
NameRef(broker(), p.name()),
|
||||
AccessMode::kStore);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
|
||||
StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
|
||||
Node* const value = NodeProperties::GetValueInput(node, 1);
|
||||
|
||||
// Extract receiver maps from the IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Try to lower the creation of a named property based on the {receiver_maps}.
|
||||
return ReduceNamedAccessFromNexus(node, value, nexus,
|
||||
return ReduceNamedAccessFromNexus(node, value, FeedbackSource(p.feedback()),
|
||||
NameRef(broker(), p.name()),
|
||||
AccessMode::kStoreInLiteral);
|
||||
}
|
||||
@ -1431,24 +1421,31 @@ base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
Node* node, Node* index, Node* value,
|
||||
ElementAccessFeedback const& processed, AccessMode access_mode,
|
||||
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
|
||||
ElementAccessFeedback const& processed) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
node->opcode() == IrOpcode::kJSStoreProperty ||
|
||||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
|
||||
node->opcode() == IrOpcode::kJSHasProperty);
|
||||
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 0);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* frame_state =
|
||||
NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
|
||||
|
||||
AccessMode access_mode = processed.keyed_mode.access_mode();
|
||||
if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
|
||||
receiver->opcode() == IrOpcode::kHeapConstant) {
|
||||
Reduction reduction = ReduceKeyedLoadFromHeapConstant(
|
||||
node, index, access_mode, processed.keyed_mode.load_mode());
|
||||
if (reduction.Changed()) return reduction;
|
||||
}
|
||||
|
||||
if (HasOnlyStringMaps(broker(), processed.receiver_maps)) {
|
||||
DCHECK(processed.transitions.empty());
|
||||
return ReduceElementAccessOnString(node, index, value, access_mode,
|
||||
load_mode);
|
||||
processed.keyed_mode.load_mode());
|
||||
}
|
||||
|
||||
// Compute element access infos for the receiver maps.
|
||||
@ -1479,7 +1476,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
// then we need to check that all prototypes have stable maps with
|
||||
// fast elements (and we need to guard against changes to that below).
|
||||
if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) ||
|
||||
IsGrowStoreMode(store_mode)) &&
|
||||
IsGrowStoreMode(processed.keyed_mode.store_mode())) &&
|
||||
!receiver_map.HasOnlyStablePrototypesWithFastElements(
|
||||
&prototype_maps)) {
|
||||
return NoChange();
|
||||
@ -1552,7 +1549,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
// Access the actual element.
|
||||
ValueEffectControl continuation =
|
||||
BuildElementAccess(receiver, index, value, effect, control, access_info,
|
||||
access_mode, load_mode, store_mode);
|
||||
processed.keyed_mode);
|
||||
value = continuation.value();
|
||||
effect = continuation.effect();
|
||||
control = continuation.control();
|
||||
@ -1617,9 +1614,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
}
|
||||
|
||||
// Access the actual element.
|
||||
ValueEffectControl continuation = BuildElementAccess(
|
||||
this_receiver, this_index, this_value, this_effect, this_control,
|
||||
access_info, access_mode, load_mode, store_mode);
|
||||
ValueEffectControl continuation =
|
||||
BuildElementAccess(this_receiver, this_index, this_value, this_effect,
|
||||
this_control, access_info, processed.keyed_mode);
|
||||
values.push_back(continuation.value());
|
||||
effects.push_back(continuation.effect());
|
||||
controls.push_back(continuation.control());
|
||||
@ -1653,7 +1650,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
|
||||
Node* node, Node* key, FeedbackNexus const& nexus, AccessMode access_mode,
|
||||
Node* node, Node* key, AccessMode access_mode,
|
||||
KeyedAccessLoadMode load_mode) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
node->opcode() == IrOpcode::kJSHasProperty);
|
||||
@ -1709,54 +1706,24 @@ Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
|
||||
// accesses using the known length, which doesn't change.
|
||||
if (receiver_ref.IsString()) {
|
||||
DCHECK_NE(access_mode, AccessMode::kHas);
|
||||
// We can only assume that the {index} is a valid array index if the
|
||||
// IC is in element access mode and not MEGAMORPHIC, otherwise there's
|
||||
// no guard for the bounds check below.
|
||||
if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
|
||||
// Ensure that {key} is less than {receiver} length.
|
||||
Node* length = jsgraph()->Constant(receiver_ref.AsString().length());
|
||||
// Ensure that {key} is less than {receiver} length.
|
||||
Node* length = jsgraph()->Constant(receiver_ref.AsString().length());
|
||||
|
||||
// Load the single character string from {receiver} or yield
|
||||
// undefined if the {key} is out of bounds (depending on the
|
||||
// {load_mode}).
|
||||
Node* value = BuildIndexedStringLoad(receiver, key, length, &effect,
|
||||
&control, load_mode);
|
||||
ReplaceWithValue(node, value, effect, control);
|
||||
return Replace(value);
|
||||
}
|
||||
// Load the single character string from {receiver} or yield
|
||||
// undefined if the {key} is out of bounds (depending on the
|
||||
// {load_mode}).
|
||||
Node* value = BuildIndexedStringLoad(receiver, key, length, &effect,
|
||||
&control, load_mode);
|
||||
ReplaceWithValue(node, value, effect, control);
|
||||
return Replace(value);
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
|
||||
Node* node, Node* key, Node* value, FeedbackNexus const& nexus,
|
||||
AccessMode access_mode, KeyedAccessLoadMode load_mode,
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
node->opcode() == IrOpcode::kJSStoreProperty ||
|
||||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
|
||||
node->opcode() == IrOpcode::kJSHasProperty);
|
||||
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 0);
|
||||
|
||||
if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
|
||||
receiver->opcode() == IrOpcode::kHeapConstant) {
|
||||
Reduction reduction = ReduceKeyedLoadFromHeapConstant(
|
||||
node, key, nexus, access_mode, load_mode);
|
||||
if (reduction.Changed()) return reduction;
|
||||
}
|
||||
|
||||
return ReducePropertyAccessUsingProcessedFeedback(node, key, base::nullopt,
|
||||
value, nexus, access_mode,
|
||||
load_mode, store_mode);
|
||||
}
|
||||
|
||||
Reduction
|
||||
JSNativeContextSpecialization::ReducePropertyAccessUsingProcessedFeedback(
|
||||
Reduction JSNativeContextSpecialization::ReducePropertyAccess(
|
||||
Node* node, Node* key, base::Optional<NameRef> static_name, Node* value,
|
||||
FeedbackNexus const& nexus, AccessMode access_mode,
|
||||
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
|
||||
FeedbackSource const& source, AccessMode access_mode) {
|
||||
DCHECK_EQ(key == nullptr, static_name.has_value());
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
node->opcode() == IrOpcode::kJSStoreProperty ||
|
||||
@ -1771,11 +1738,12 @@ JSNativeContextSpecialization::ReducePropertyAccessUsingProcessedFeedback(
|
||||
|
||||
ProcessedFeedback const* processed = nullptr;
|
||||
if (FLAG_concurrent_inlining) {
|
||||
processed = broker()->GetFeedback(FeedbackSource(nexus));
|
||||
processed = broker()->GetFeedback(source);
|
||||
// TODO(neis): Infer maps from the graph and consolidate with feedback/hints
|
||||
// and filter impossible candidates based on inferred root map.
|
||||
} else {
|
||||
// TODO(neis): Try to unify this with the similar code in the serializer.
|
||||
FeedbackNexus nexus(source.vector, source.slot);
|
||||
if (nexus.ic_state() == UNINITIALIZED) {
|
||||
processed = new (zone()) InsufficientFeedback();
|
||||
} else {
|
||||
@ -1795,8 +1763,8 @@ JSNativeContextSpecialization::ReducePropertyAccessUsingProcessedFeedback(
|
||||
processed = new (zone()) NamedAccessFeedback(*name, access_infos);
|
||||
} else if (nexus.GetKeyType() == ELEMENT &&
|
||||
MEGAMORPHIC != nexus.ic_state()) {
|
||||
processed =
|
||||
broker()->ProcessFeedbackMapsForElementAccess(receiver_maps);
|
||||
processed = broker()->ProcessFeedbackMapsForElementAccess(
|
||||
receiver_maps, KeyedAccessMode::FromNexus(nexus));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1812,9 +1780,10 @@ JSNativeContextSpecialization::ReducePropertyAccessUsingProcessedFeedback(
|
||||
return ReduceNamedAccess(node, value, *processed->AsNamedAccess(),
|
||||
access_mode, key);
|
||||
case ProcessedFeedback::kElementAccess:
|
||||
CHECK_EQ(processed->AsElementAccess()->keyed_mode.access_mode(),
|
||||
access_mode);
|
||||
return ReduceElementAccess(node, key, value,
|
||||
*processed->AsElementAccess(), access_mode,
|
||||
load_mode, store_mode);
|
||||
*processed->AsElementAccess());
|
||||
case ProcessedFeedback::kGlobalAccess:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1840,21 +1809,15 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode());
|
||||
PropertyAccess const& p = PropertyAccessOf(node->op());
|
||||
Node* key = NodeProperties::GetValueInput(node, 1);
|
||||
Node* value = jsgraph()->Dead();
|
||||
|
||||
// Extract receiver maps from the has property IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Extract the keyed access load mode from the keyed load IC.
|
||||
KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
|
||||
|
||||
// Try to lower the keyed access based on the {nexus}.
|
||||
return ReduceKeyedAccess(node, key, value, nexus, AccessMode::kHas, load_mode,
|
||||
STANDARD_STORE);
|
||||
return ReducePropertyAccess(node, key, base::nullopt, value,
|
||||
FeedbackSource(p.feedback()), AccessMode::kHas);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
|
||||
@ -1964,6 +1927,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
|
||||
PropertyAccess const& p = PropertyAccessOf(node->op());
|
||||
Node* name = NodeProperties::GetValueInput(node, 1);
|
||||
@ -1973,60 +1937,51 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
|
||||
if (reduction.Changed()) return reduction;
|
||||
}
|
||||
|
||||
// Extract receiver maps from the keyed load IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Extract the keyed access load mode from the keyed load IC.
|
||||
KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
|
||||
|
||||
// Try to lower the keyed access based on the {nexus}.
|
||||
Node* value = jsgraph()->Dead();
|
||||
return ReduceKeyedAccess(node, name, value, nexus, AccessMode::kLoad,
|
||||
load_mode, STANDARD_STORE);
|
||||
return ReducePropertyAccess(node, name, base::nullopt, value,
|
||||
FeedbackSource(p.feedback()), AccessMode::kLoad);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
|
||||
PropertyAccess const& p = PropertyAccessOf(node->op());
|
||||
Node* const key = NodeProperties::GetValueInput(node, 1);
|
||||
Node* const value = NodeProperties::GetValueInput(node, 2);
|
||||
|
||||
// Extract receiver maps from the keyed store IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Extract the keyed access store mode from the keyed store IC.
|
||||
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
|
||||
|
||||
// Try to lower the keyed access based on the {nexus}.
|
||||
return ReduceKeyedAccess(node, key, value, nexus, AccessMode::kStore,
|
||||
STANDARD_LOAD, store_mode);
|
||||
return ReducePropertyAccess(node, key, base::nullopt, value,
|
||||
FeedbackSource(p.feedback()), AccessMode::kStore);
|
||||
}
|
||||
|
||||
Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
|
||||
Node* receiver, Node* context, Node* frame_state, Node** effect,
|
||||
Node** control, ZoneVector<Node*>* if_exceptions,
|
||||
PropertyAccessInfo const& access_info) {
|
||||
Node* target = jsgraph()->Constant(access_info.constant());
|
||||
ObjectRef constant(broker(), access_info.constant());
|
||||
Node* target = jsgraph()->Constant(constant);
|
||||
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
|
||||
// Introduce the call to the getter function.
|
||||
Node* value;
|
||||
ObjectRef constant(broker(), access_info.constant());
|
||||
if (constant.IsJSFunction()) {
|
||||
value = *effect = *control = graph()->NewNode(
|
||||
jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
|
||||
ConvertReceiverMode::kNotNullOrUndefined),
|
||||
target, receiver, context, frame_state, *effect, *control);
|
||||
} else {
|
||||
// TODO(mslekova): Move this to the serialization of property loads.
|
||||
FunctionTemplateInfoRef function_template_info =
|
||||
constant.AsFunctionTemplateInfo();
|
||||
function_template_info.Serialize();
|
||||
Node* holder =
|
||||
access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
|
||||
auto function_template_info = constant.AsFunctionTemplateInfo();
|
||||
{ // TODO(mslekova): Move this to the serialization of property loads.
|
||||
AllowCodeDependencyChange dependency_change_;
|
||||
AllowHandleAllocation handle_allocation_;
|
||||
AllowHandleDereference handle_dereference_;
|
||||
AllowHeapAllocation heap_allocation_;
|
||||
function_template_info.Serialize();
|
||||
}
|
||||
Node* holder = access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(ObjectRef(
|
||||
broker(), access_info.holder().ToHandleChecked()));
|
||||
SharedFunctionInfoRef shared_info(
|
||||
broker(), frame_info.shared_info().ToHandleChecked());
|
||||
|
||||
@ -2049,10 +2004,10 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
|
||||
Node* receiver, Node* value, Node* context, Node* frame_state,
|
||||
Node** effect, Node** control, ZoneVector<Node*>* if_exceptions,
|
||||
PropertyAccessInfo const& access_info) {
|
||||
Node* target = jsgraph()->Constant(access_info.constant());
|
||||
ObjectRef constant(broker(), access_info.constant());
|
||||
Node* target = jsgraph()->Constant(constant);
|
||||
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
|
||||
// Introduce the call to the setter function.
|
||||
ObjectRef constant(broker(), access_info.constant());
|
||||
if (constant.IsJSFunction()) {
|
||||
*effect = *control = graph()->NewNode(
|
||||
jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
|
||||
@ -2061,11 +2016,17 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
|
||||
} else {
|
||||
// TODO(mslekova): Move this to the serialization of property stores.
|
||||
auto function_template_info = constant.AsFunctionTemplateInfo();
|
||||
function_template_info.Serialize();
|
||||
Node* holder =
|
||||
access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
|
||||
{ // TODO(mslekova): Remove this Serialize call.
|
||||
AllowCodeDependencyChange dependency_change_;
|
||||
AllowHandleAllocation handle_allocation_;
|
||||
AllowHandleDereference handle_dereference_;
|
||||
AllowHeapAllocation heap_allocation_;
|
||||
function_template_info.Serialize();
|
||||
}
|
||||
Node* holder = access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(ObjectRef(
|
||||
broker(), access_info.holder().ToHandleChecked()));
|
||||
SharedFunctionInfoRef shared_info(
|
||||
broker(), frame_info.shared_info().ToHandleChecked());
|
||||
InlineApiCall(receiver, holder, frame_state, value, effect, control,
|
||||
@ -2149,7 +2110,7 @@ JSNativeContextSpecialization::BuildPropertyLoad(
|
||||
value = InlinePropertyGetterCall(receiver, context, frame_state, &effect,
|
||||
&control, if_exceptions, access_info);
|
||||
} else if (access_info.IsModuleExport()) {
|
||||
Node* cell = jsgraph()->Constant(access_info.export_cell());
|
||||
Node* cell = jsgraph()->Constant(access_info.export_cell(broker()));
|
||||
value = effect =
|
||||
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
|
||||
cell, effect, control);
|
||||
@ -2380,7 +2341,6 @@ JSNativeContextSpecialization::BuildPropertyStore(
|
||||
// Check if we need to grow the properties backing store
|
||||
// with this transitioning store.
|
||||
MapRef transition_map_ref(broker(), transition_map);
|
||||
transition_map_ref.SerializeBackPointer();
|
||||
MapRef original_map = transition_map_ref.GetBackPointer().AsMap();
|
||||
if (original_map.UnusedPropertyFields() == 0) {
|
||||
DCHECK(!field_index.is_inobject());
|
||||
@ -2402,7 +2362,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
|
||||
common()->BeginRegion(RegionObservability::kObservable), effect);
|
||||
effect = graph()->NewNode(
|
||||
simplified()->StoreField(AccessBuilder::ForMap()), receiver,
|
||||
jsgraph()->Constant(transition_map), effect, control);
|
||||
jsgraph()->Constant(transition_map_ref), effect, control);
|
||||
effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
|
||||
value, effect, control);
|
||||
effect = graph()->NewNode(common()->FinishRegion(),
|
||||
@ -2493,21 +2453,16 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
|
||||
Node* node) {
|
||||
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
|
||||
DCHECK_EQ(IrOpcode::kJSStoreInArrayLiteral, node->opcode());
|
||||
FeedbackParameter const& p = FeedbackParameterOf(node->op());
|
||||
Node* const index = NodeProperties::GetValueInput(node, 1);
|
||||
Node* const value = NodeProperties::GetValueInput(node, 2);
|
||||
|
||||
// Extract receiver maps from the keyed store IC using the FeedbackNexus.
|
||||
if (!p.feedback().IsValid()) return NoChange();
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
|
||||
// Extract the keyed access store mode from the keyed store IC.
|
||||
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
|
||||
|
||||
return ReduceKeyedAccess(node, index, value, nexus,
|
||||
AccessMode::kStoreInLiteral, STANDARD_LOAD,
|
||||
store_mode);
|
||||
return ReducePropertyAccess(node, index, base::nullopt, value,
|
||||
FeedbackSource(p.feedback()),
|
||||
AccessMode::kStoreInLiteral);
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSToObject(Node* node) {
|
||||
@ -2544,8 +2499,7 @@ ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
|
||||
JSNativeContextSpecialization::ValueEffectControl
|
||||
JSNativeContextSpecialization::BuildElementAccess(
|
||||
Node* receiver, Node* index, Node* value, Node* effect, Node* control,
|
||||
ElementAccessInfo const& access_info, AccessMode access_mode,
|
||||
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
|
||||
ElementAccessInfo const& access_info, KeyedAccessMode const& keyed_mode) {
|
||||
// TODO(bmeurer): We currently specialize based on elements kind. We should
|
||||
// also be able to properly support strings and other JSObjects here.
|
||||
ElementsKind elements_kind = access_info.elements_kind();
|
||||
@ -2627,8 +2581,10 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
buffer_or_receiver = buffer;
|
||||
}
|
||||
|
||||
if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS ||
|
||||
store_mode == STORE_IGNORE_OUT_OF_BOUNDS) {
|
||||
if ((keyed_mode.IsLoad() &&
|
||||
keyed_mode.load_mode() == LOAD_IGNORE_OUT_OF_BOUNDS) ||
|
||||
(keyed_mode.IsStore() &&
|
||||
keyed_mode.store_mode() == STORE_IGNORE_OUT_OF_BOUNDS)) {
|
||||
// Only check that the {index} is in SignedSmall range. We do the actual
|
||||
// bounds check below and just skip the property access if it's out of
|
||||
// bounds for the {receiver}.
|
||||
@ -2649,10 +2605,10 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
// Access the actual element.
|
||||
ExternalArrayType external_array_type =
|
||||
GetArrayTypeFromElementsKind(elements_kind);
|
||||
switch (access_mode) {
|
||||
switch (keyed_mode.access_mode()) {
|
||||
case AccessMode::kLoad: {
|
||||
// Check if we can return undefined for out-of-bounds loads.
|
||||
if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS) {
|
||||
if (keyed_mode.load_mode() == LOAD_IGNORE_OUT_OF_BOUNDS) {
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->NumberLessThan(), index, length);
|
||||
Node* branch = graph()->NewNode(
|
||||
@ -2714,7 +2670,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
}
|
||||
|
||||
// Check if we can skip the out-of-bounds store.
|
||||
if (store_mode == STORE_IGNORE_OUT_OF_BOUNDS) {
|
||||
if (keyed_mode.store_mode() == STORE_IGNORE_OUT_OF_BOUNDS) {
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->NumberLessThan(), index, length);
|
||||
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
|
||||
@ -2764,9 +2720,9 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
|
||||
// Don't try to store to a copy-on-write backing store (unless supported by
|
||||
// the store mode).
|
||||
if (access_mode == AccessMode::kStore &&
|
||||
if (keyed_mode.access_mode() == AccessMode::kStore &&
|
||||
IsSmiOrObjectElementsKind(elements_kind) &&
|
||||
!IsCOWHandlingStoreMode(store_mode)) {
|
||||
!IsCOWHandlingStoreMode(keyed_mode.store_mode())) {
|
||||
effect = graph()->NewNode(
|
||||
simplified()->CheckMaps(
|
||||
CheckMapsFlag::kNone,
|
||||
@ -2789,11 +2745,10 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
elements, effect, control);
|
||||
|
||||
// Check if we might need to grow the {elements} backing store.
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
if (keyed_mode.IsStore() && IsGrowStoreMode(keyed_mode.store_mode())) {
|
||||
// For growing stores we validate the {index} below.
|
||||
DCHECK(access_mode == AccessMode::kStore ||
|
||||
access_mode == AccessMode::kStoreInLiteral);
|
||||
} else if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
|
||||
} else if (keyed_mode.IsLoad() &&
|
||||
keyed_mode.load_mode() == LOAD_IGNORE_OUT_OF_BOUNDS &&
|
||||
CanTreatHoleAsUndefined(receiver_maps)) {
|
||||
// Check that the {index} is a valid array index, we do the actual
|
||||
// bounds check below and just skip the store below if it's out of
|
||||
@ -2824,7 +2779,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
kFullWriteBarrier, LoadSensitivity::kCritical};
|
||||
|
||||
// Access the actual element.
|
||||
if (access_mode == AccessMode::kLoad) {
|
||||
if (keyed_mode.access_mode() == AccessMode::kLoad) {
|
||||
// Compute the real element access type, which includes the hole in case
|
||||
// of holey backing stores.
|
||||
if (IsHoleyElementsKind(elements_kind)) {
|
||||
@ -2837,7 +2792,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
}
|
||||
|
||||
// Check if we can return undefined for out-of-bounds loads.
|
||||
if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
|
||||
if (keyed_mode.load_mode() == LOAD_IGNORE_OUT_OF_BOUNDS &&
|
||||
CanTreatHoleAsUndefined(receiver_maps)) {
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->NumberLessThan(), index, length);
|
||||
@ -2921,7 +2876,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
effect, control);
|
||||
}
|
||||
}
|
||||
} else if (access_mode == AccessMode::kHas) {
|
||||
} else if (keyed_mode.access_mode() == AccessMode::kHas) {
|
||||
// For packed arrays with NoElementsProctector valid, a bound check
|
||||
// is equivalent to HasProperty.
|
||||
value = effect = graph()->NewNode(simplified()->SpeculativeNumberLessThan(
|
||||
@ -2994,8 +2949,9 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
vtrue, vfalse, control);
|
||||
}
|
||||
} else {
|
||||
DCHECK(access_mode == AccessMode::kStore ||
|
||||
access_mode == AccessMode::kStoreInLiteral);
|
||||
DCHECK(keyed_mode.access_mode() == AccessMode::kStore ||
|
||||
keyed_mode.access_mode() == AccessMode::kStoreInLiteral);
|
||||
|
||||
if (IsSmiElementsKind(elements_kind)) {
|
||||
value = effect = graph()->NewNode(
|
||||
simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
|
||||
@ -3009,11 +2965,11 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
|
||||
// Ensure that copy-on-write backing store is writable.
|
||||
if (IsSmiOrObjectElementsKind(elements_kind) &&
|
||||
store_mode == STORE_HANDLE_COW) {
|
||||
keyed_mode.store_mode() == STORE_HANDLE_COW) {
|
||||
elements = effect =
|
||||
graph()->NewNode(simplified()->EnsureWritableFastElements(),
|
||||
receiver, elements, effect, control);
|
||||
} else if (IsGrowStoreMode(store_mode)) {
|
||||
} else if (IsGrowStoreMode(keyed_mode.store_mode())) {
|
||||
// Determine the length of the {elements} backing store.
|
||||
Node* elements_length = effect = graph()->NewNode(
|
||||
simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
|
||||
@ -3051,7 +3007,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
// If we didn't grow {elements}, it might still be COW, in which case we
|
||||
// copy it now.
|
||||
if (IsSmiOrObjectElementsKind(elements_kind) &&
|
||||
store_mode == STORE_AND_GROW_HANDLE_COW) {
|
||||
keyed_mode.store_mode() == STORE_AND_GROW_HANDLE_COW) {
|
||||
elements = effect =
|
||||
graph()->NewNode(simplified()->EnsureWritableFastElements(),
|
||||
receiver, elements, effect, control);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user