[maglev] Optimize store to constant field
This doesn't optimize stores to object literals yet since the feedback is partially broken. Bug: v8:7700 Change-Id: Idfa95b51cb2673b47c6a626a6b60501838ffb468 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4023045 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/main@{#84238}
This commit is contained in:
parent
b9eeaf1b88
commit
6ae0cd3717
@ -1565,25 +1565,24 @@ bool MaglevGraphBuilder::TryFoldLoadDictPrototypeConstant(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaglevGraphBuilder::TryFoldLoadConstantDataField(
|
ValueNode* MaglevGraphBuilder::TryFoldLoadConstantDataField(
|
||||||
compiler::PropertyAccessInfo access_info, ValueNode* lookup_start_object) {
|
compiler::PropertyAccessInfo access_info, ValueNode* lookup_start_object) {
|
||||||
if (!access_info.IsFastDataConstant()) return false;
|
if (!access_info.IsFastDataConstant()) return nullptr;
|
||||||
base::Optional<compiler::JSObjectRef> source;
|
base::Optional<compiler::JSObjectRef> source;
|
||||||
if (access_info.holder().has_value()) {
|
if (access_info.holder().has_value()) {
|
||||||
source = access_info.holder();
|
source = access_info.holder();
|
||||||
} else if (Constant* n = lookup_start_object->TryCast<Constant>()) {
|
} else if (Constant* n = lookup_start_object->TryCast<Constant>()) {
|
||||||
if (!n->ref().IsJSObject()) return false;
|
if (!n->ref().IsJSObject()) return nullptr;
|
||||||
source = n->ref().AsJSObject();
|
source = n->ref().AsJSObject();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
base::Optional<compiler::ObjectRef> constant =
|
base::Optional<compiler::ObjectRef> constant =
|
||||||
source.value().GetOwnFastDataProperty(access_info.field_representation(),
|
source.value().GetOwnFastDataProperty(access_info.field_representation(),
|
||||||
access_info.field_index(),
|
access_info.field_index(),
|
||||||
broker()->dependencies());
|
broker()->dependencies());
|
||||||
if (!constant.has_value()) return false;
|
if (!constant.has_value()) return nullptr;
|
||||||
SetAccumulator(GetConstant(constant.value()));
|
return GetConstant(constant.value());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaglevGraphBuilder::TryBuildPropertyGetterCall(
|
bool MaglevGraphBuilder::TryBuildPropertyGetterCall(
|
||||||
@ -1629,9 +1628,12 @@ bool MaglevGraphBuilder::TryBuildPropertySetterCall(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaglevGraphBuilder::BuildLoadField(
|
ValueNode* MaglevGraphBuilder::BuildLoadField(
|
||||||
compiler::PropertyAccessInfo access_info, ValueNode* lookup_start_object) {
|
compiler::PropertyAccessInfo access_info, ValueNode* lookup_start_object) {
|
||||||
if (TryFoldLoadConstantDataField(access_info, lookup_start_object)) return;
|
if (ValueNode* result =
|
||||||
|
TryFoldLoadConstantDataField(access_info, lookup_start_object)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve property holder.
|
// Resolve property holder.
|
||||||
ValueNode* load_source;
|
ValueNode* load_source;
|
||||||
@ -1650,37 +1652,36 @@ void MaglevGraphBuilder::BuildLoadField(
|
|||||||
|
|
||||||
// Do the load.
|
// Do the load.
|
||||||
if (field_index.is_double()) {
|
if (field_index.is_double()) {
|
||||||
SetAccumulator(
|
return AddNewNode<LoadDoubleField>({load_source}, field_index.offset());
|
||||||
AddNewNode<LoadDoubleField>({load_source}, field_index.offset()));
|
}
|
||||||
} else {
|
ValueNode* value =
|
||||||
ValueNode* value =
|
AddNewNode<LoadTaggedField>({load_source}, field_index.offset());
|
||||||
AddNewNode<LoadTaggedField>({load_source}, field_index.offset());
|
// Insert stable field information if present.
|
||||||
SetAccumulator(value);
|
if (access_info.field_representation().IsSmi()) {
|
||||||
// Insert stable field information if present.
|
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(value);
|
||||||
if (access_info.field_representation().IsSmi()) {
|
known_info->type = NodeType::kSmi;
|
||||||
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(value);
|
} else if (access_info.field_representation().IsHeapObject()) {
|
||||||
known_info->type = NodeType::kSmi;
|
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(value);
|
||||||
} else if (access_info.field_representation().IsHeapObject()) {
|
if (access_info.field_map().has_value() &&
|
||||||
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(value);
|
access_info.field_map().value().is_stable()) {
|
||||||
if (access_info.field_map().has_value() &&
|
DCHECK(access_info.field_map().value().IsJSReceiverMap());
|
||||||
access_info.field_map().value().is_stable()) {
|
known_info->type = NodeType::kJSReceiverWithKnownMap;
|
||||||
DCHECK(access_info.field_map().value().IsJSReceiverMap());
|
auto map = access_info.field_map().value();
|
||||||
known_info->type = NodeType::kJSReceiverWithKnownMap;
|
ZoneHandleSet<Map> stable_maps(map.object());
|
||||||
auto map = access_info.field_map().value();
|
ZoneHandleSet<Map> unstable_maps;
|
||||||
ZoneHandleSet<Map> stable_maps(map.object());
|
known_node_aspects().stable_maps.emplace(value, stable_maps);
|
||||||
ZoneHandleSet<Map> unstable_maps;
|
known_node_aspects().unstable_maps.emplace(value, unstable_maps);
|
||||||
known_node_aspects().stable_maps.emplace(value, stable_maps);
|
broker()->dependencies()->DependOnStableMap(map);
|
||||||
known_node_aspects().unstable_maps.emplace(value, unstable_maps);
|
} else {
|
||||||
broker()->dependencies()->DependOnStableMap(map);
|
known_info->type = NodeType::kAnyHeapObject;
|
||||||
} else {
|
|
||||||
known_info->type = NodeType::kAnyHeapObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaglevGraphBuilder::TryBuildStoreField(
|
bool MaglevGraphBuilder::TryBuildStoreField(
|
||||||
compiler::PropertyAccessInfo access_info, ValueNode* receiver) {
|
compiler::PropertyAccessInfo access_info, ValueNode* receiver,
|
||||||
|
compiler::AccessMode access_mode) {
|
||||||
FieldIndex field_index = access_info.field_index();
|
FieldIndex field_index = access_info.field_index();
|
||||||
Representation field_representation = access_info.field_representation();
|
Representation field_representation = access_info.field_representation();
|
||||||
|
|
||||||
@ -1688,9 +1689,25 @@ bool MaglevGraphBuilder::TryBuildStoreField(
|
|||||||
compiler::MapRef transition = access_info.transition_map().value();
|
compiler::MapRef transition = access_info.transition_map().value();
|
||||||
compiler::MapRef original_map = transition.GetBackPointer().AsMap();
|
compiler::MapRef original_map = transition.GetBackPointer().AsMap();
|
||||||
// TODO(verwaest): Support growing backing stores.
|
// TODO(verwaest): Support growing backing stores.
|
||||||
if (original_map.UnusedPropertyFields() == 0) return false;
|
if (original_map.UnusedPropertyFields() == 0) {
|
||||||
} else if (access_info.IsFastDataConstant()) {
|
return false;
|
||||||
return false;
|
}
|
||||||
|
} else if (access_info.IsFastDataConstant() &&
|
||||||
|
access_mode != compiler::AccessMode::kStoreInLiteral) {
|
||||||
|
// For object literals we want to just store, similar to StoreInLiteral, but
|
||||||
|
// Define is also used for classes so we can't. Bail out for now.
|
||||||
|
if (access_mode == compiler::AccessMode::kDefine) return false;
|
||||||
|
// TODO(verwaest): Support doubles.
|
||||||
|
if (field_representation.IsDouble()) return false;
|
||||||
|
ValueNode* value = GetAccumulatorTagged();
|
||||||
|
ValueNode* expected = BuildLoadField(access_info, receiver);
|
||||||
|
if (Constant* constant = expected->TryCast<Constant>()) {
|
||||||
|
BuildCheckValue(value, constant->ref());
|
||||||
|
} else {
|
||||||
|
AddNewNode<CheckDynamicValue>({value, expected});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueNode* store_target;
|
ValueNode* store_target;
|
||||||
@ -1781,7 +1798,7 @@ bool MaglevGraphBuilder::TryBuildPropertyLoad(
|
|||||||
return true;
|
return true;
|
||||||
case compiler::PropertyAccessInfo::kDataField:
|
case compiler::PropertyAccessInfo::kDataField:
|
||||||
case compiler::PropertyAccessInfo::kFastDataConstant:
|
case compiler::PropertyAccessInfo::kFastDataConstant:
|
||||||
BuildLoadField(access_info, lookup_start_object);
|
SetAccumulator(BuildLoadField(access_info, lookup_start_object));
|
||||||
RecordKnownProperty(lookup_start_object, name,
|
RecordKnownProperty(lookup_start_object, name,
|
||||||
current_interpreter_frame_.accumulator(),
|
current_interpreter_frame_.accumulator(),
|
||||||
access_info.IsFastDataConstant());
|
access_info.IsFastDataConstant());
|
||||||
@ -1808,7 +1825,8 @@ bool MaglevGraphBuilder::TryBuildPropertyLoad(
|
|||||||
|
|
||||||
bool MaglevGraphBuilder::TryBuildPropertyStore(
|
bool MaglevGraphBuilder::TryBuildPropertyStore(
|
||||||
ValueNode* receiver, compiler::NameRef name,
|
ValueNode* receiver, compiler::NameRef name,
|
||||||
compiler::PropertyAccessInfo const& access_info) {
|
compiler::PropertyAccessInfo const& access_info,
|
||||||
|
compiler::AccessMode access_mode) {
|
||||||
if (access_info.holder().has_value()) {
|
if (access_info.holder().has_value()) {
|
||||||
broker()->dependencies()->DependOnStablePrototypeChains(
|
broker()->dependencies()->DependOnStablePrototypeChains(
|
||||||
access_info.lookup_start_object_maps(), kStartAtPrototype,
|
access_info.lookup_start_object_maps(), kStartAtPrototype,
|
||||||
@ -1820,7 +1838,7 @@ bool MaglevGraphBuilder::TryBuildPropertyStore(
|
|||||||
GetAccumulatorTagged());
|
GetAccumulatorTagged());
|
||||||
} else {
|
} else {
|
||||||
DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
|
DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
|
||||||
if (TryBuildStoreField(access_info, receiver)) {
|
if (TryBuildStoreField(access_info, receiver, access_mode)) {
|
||||||
RecordKnownProperty(receiver, name,
|
RecordKnownProperty(receiver, name,
|
||||||
current_interpreter_frame_.accumulator(),
|
current_interpreter_frame_.accumulator(),
|
||||||
access_info.IsFastDataConstant());
|
access_info.IsFastDataConstant());
|
||||||
@ -1842,7 +1860,7 @@ bool MaglevGraphBuilder::TryBuildPropertyAccess(
|
|||||||
case compiler::AccessMode::kStoreInLiteral:
|
case compiler::AccessMode::kStoreInLiteral:
|
||||||
case compiler::AccessMode::kDefine:
|
case compiler::AccessMode::kDefine:
|
||||||
DCHECK_EQ(receiver, lookup_start_object);
|
DCHECK_EQ(receiver, lookup_start_object);
|
||||||
return TryBuildPropertyStore(receiver, name, access_info);
|
return TryBuildPropertyStore(receiver, name, access_info, access_mode);
|
||||||
case compiler::AccessMode::kHas:
|
case compiler::AccessMode::kHas:
|
||||||
// TODO(victorgomes): BuildPropertyTest.
|
// TODO(victorgomes): BuildPropertyTest.
|
||||||
return false;
|
return false;
|
||||||
@ -2922,7 +2940,7 @@ Call* MaglevGraphBuilder::BuildGenericCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MaglevGraphBuilder::BuildCheckValue(ValueNode* node,
|
bool MaglevGraphBuilder::BuildCheckValue(ValueNode* node,
|
||||||
const compiler::HeapObjectRef& ref) {
|
const compiler::ObjectRef& ref) {
|
||||||
if (node->Is<Constant>()) {
|
if (node->Is<Constant>()) {
|
||||||
if (node->Cast<Constant>()->object().equals(ref)) return true;
|
if (node->Cast<Constant>()->object().equals(ref)) return true;
|
||||||
EmitUnconditionalDeopt(DeoptimizeReason::kUnknown);
|
EmitUnconditionalDeopt(DeoptimizeReason::kUnknown);
|
||||||
|
@ -1117,7 +1117,7 @@ class MaglevGraphBuilder {
|
|||||||
ZoneVector<compiler::MapRef> const& maps);
|
ZoneVector<compiler::MapRef> const& maps);
|
||||||
// Emits an unconditional deopt and returns false if the node is a constant
|
// Emits an unconditional deopt and returns false if the node is a constant
|
||||||
// that doesn't match the ref.
|
// that doesn't match the ref.
|
||||||
bool BuildCheckValue(ValueNode* node, const compiler::HeapObjectRef& ref);
|
bool BuildCheckValue(ValueNode* node, const compiler::ObjectRef& ref);
|
||||||
|
|
||||||
ValueNode* GetInt32ElementIndex(interpreter::Register reg) {
|
ValueNode* GetInt32ElementIndex(interpreter::Register reg) {
|
||||||
ValueNode* index_object = current_interpreter_frame_.get(reg);
|
ValueNode* index_object = current_interpreter_frame_.get(reg);
|
||||||
@ -1130,13 +1130,16 @@ class MaglevGraphBuilder {
|
|||||||
|
|
||||||
bool TryFoldLoadDictPrototypeConstant(
|
bool TryFoldLoadDictPrototypeConstant(
|
||||||
compiler::PropertyAccessInfo access_info);
|
compiler::PropertyAccessInfo access_info);
|
||||||
bool TryFoldLoadConstantDataField(compiler::PropertyAccessInfo access_info,
|
// Returns a ValueNode if the load could be folded, and nullptr otherwise.
|
||||||
ValueNode* lookup_start_object);
|
ValueNode* TryFoldLoadConstantDataField(
|
||||||
|
compiler::PropertyAccessInfo access_info, ValueNode* lookup_start_object);
|
||||||
|
|
||||||
void BuildLoadField(compiler::PropertyAccessInfo access_info,
|
// Returns the loaded value node but doesn't update the accumulator yet.
|
||||||
ValueNode* lookup_start_object);
|
ValueNode* BuildLoadField(compiler::PropertyAccessInfo access_info,
|
||||||
|
ValueNode* lookup_start_object);
|
||||||
bool TryBuildStoreField(compiler::PropertyAccessInfo access_info,
|
bool TryBuildStoreField(compiler::PropertyAccessInfo access_info,
|
||||||
ValueNode* receiver);
|
ValueNode* receiver,
|
||||||
|
compiler::AccessMode access_mode);
|
||||||
bool TryBuildPropertyGetterCall(compiler::PropertyAccessInfo access_info,
|
bool TryBuildPropertyGetterCall(compiler::PropertyAccessInfo access_info,
|
||||||
ValueNode* receiver,
|
ValueNode* receiver,
|
||||||
ValueNode* lookup_start_object);
|
ValueNode* lookup_start_object);
|
||||||
@ -1147,7 +1150,8 @@ class MaglevGraphBuilder {
|
|||||||
compiler::NameRef name,
|
compiler::NameRef name,
|
||||||
compiler::PropertyAccessInfo const& access_info);
|
compiler::PropertyAccessInfo const& access_info);
|
||||||
bool TryBuildPropertyStore(ValueNode* receiver, compiler::NameRef name,
|
bool TryBuildPropertyStore(ValueNode* receiver, compiler::NameRef name,
|
||||||
compiler::PropertyAccessInfo const& access_info);
|
compiler::PropertyAccessInfo const& access_info,
|
||||||
|
compiler::AccessMode access_mode);
|
||||||
bool TryBuildPropertyAccess(ValueNode* receiver,
|
bool TryBuildPropertyAccess(ValueNode* receiver,
|
||||||
ValueNode* lookup_start_object,
|
ValueNode* lookup_start_object,
|
||||||
compiler::NameRef name,
|
compiler::NameRef name,
|
||||||
|
@ -199,6 +199,7 @@ class MaglevGraphVerifier {
|
|||||||
DCHECK_EQ(node->input_count(), 1);
|
DCHECK_EQ(node->input_count(), 1);
|
||||||
CheckValueInputIs(node, 0, ValueRepresentation::kFloat64);
|
CheckValueInputIs(node, 0, ValueRepresentation::kFloat64);
|
||||||
break;
|
break;
|
||||||
|
case Opcode::kCheckDynamicValue:
|
||||||
case Opcode::kForInPrepare:
|
case Opcode::kForInPrepare:
|
||||||
case Opcode::kGenericAdd:
|
case Opcode::kGenericAdd:
|
||||||
case Opcode::kGenericBitwiseAnd:
|
case Opcode::kGenericBitwiseAnd:
|
||||||
|
@ -1159,6 +1159,22 @@ void CheckValue::PrintParams(std::ostream& os,
|
|||||||
MaglevGraphLabeller* graph_labeller) const {
|
MaglevGraphLabeller* graph_labeller) const {
|
||||||
os << "(" << *value().object() << ")";
|
os << "(" << *value().object() << ")";
|
||||||
}
|
}
|
||||||
|
void CheckDynamicValue::AllocateVreg(MaglevVregAllocationState* vreg_state) {
|
||||||
|
UseRegister(first_input());
|
||||||
|
UseRegister(second_input());
|
||||||
|
}
|
||||||
|
void CheckDynamicValue::GenerateCode(MaglevAssembler* masm,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
Register first = ToRegister(first_input());
|
||||||
|
Register second = ToRegister(second_input());
|
||||||
|
|
||||||
|
__ cmpl(first, second);
|
||||||
|
__ EmitEagerDeoptIf(not_equal, DeoptimizeReason::kWrongValue, this);
|
||||||
|
}
|
||||||
|
void CheckDynamicValue::PrintParams(std::ostream& os,
|
||||||
|
MaglevGraphLabeller* graph_labeller) const {
|
||||||
|
}
|
||||||
|
|
||||||
void CheckSmi::AllocateVreg(MaglevVregAllocationState* vreg_state) {
|
void CheckSmi::AllocateVreg(MaglevVregAllocationState* vreg_state) {
|
||||||
UseRegister(receiver_input());
|
UseRegister(receiver_input());
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,7 @@ class CompactInterpreterFrameState;
|
|||||||
|
|
||||||
#define NODE_LIST(V) \
|
#define NODE_LIST(V) \
|
||||||
V(AssertInt32) \
|
V(AssertInt32) \
|
||||||
|
V(CheckDynamicValue) \
|
||||||
V(CheckInt32IsSmi) \
|
V(CheckInt32IsSmi) \
|
||||||
V(CheckUint32IsSmi) \
|
V(CheckUint32IsSmi) \
|
||||||
V(CheckHeapObject) \
|
V(CheckHeapObject) \
|
||||||
@ -3085,12 +3086,12 @@ class CheckValue : public FixedInputNodeT<1, CheckValue> {
|
|||||||
using Base = FixedInputNodeT<1, CheckValue>;
|
using Base = FixedInputNodeT<1, CheckValue>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CheckValue(uint64_t bitfield, const compiler::HeapObjectRef& value)
|
explicit CheckValue(uint64_t bitfield, const compiler::ObjectRef& value)
|
||||||
: Base(bitfield), value_(value) {}
|
: Base(bitfield), value_(value) {}
|
||||||
|
|
||||||
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
|
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
|
||||||
|
|
||||||
compiler::HeapObjectRef value() const { return value_; }
|
compiler::ObjectRef value() const { return value_; }
|
||||||
|
|
||||||
static constexpr int kTargetIndex = 0;
|
static constexpr int kTargetIndex = 0;
|
||||||
Input& target_input() { return input(kTargetIndex); }
|
Input& target_input() { return input(kTargetIndex); }
|
||||||
@ -3100,7 +3101,25 @@ class CheckValue : public FixedInputNodeT<1, CheckValue> {
|
|||||||
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const compiler::HeapObjectRef value_;
|
const compiler::ObjectRef value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CheckDynamicValue : public FixedInputNodeT<2, CheckDynamicValue> {
|
||||||
|
using Base = FixedInputNodeT<2, CheckDynamicValue>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CheckDynamicValue(uint64_t bitfield) : Base(bitfield) {}
|
||||||
|
|
||||||
|
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
|
||||||
|
|
||||||
|
static constexpr int kFirstIndex = 0;
|
||||||
|
static constexpr int kSecondIndex = 1;
|
||||||
|
Input& first_input() { return input(kFirstIndex); }
|
||||||
|
Input& second_input() { return input(kSecondIndex); }
|
||||||
|
|
||||||
|
void AllocateVreg(MaglevVregAllocationState*);
|
||||||
|
void GenerateCode(MaglevAssembler*, const ProcessingState&);
|
||||||
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CheckSmi : public FixedInputNodeT<1, CheckSmi> {
|
class CheckSmi : public FixedInputNodeT<1, CheckSmi> {
|
||||||
|
Loading…
Reference in New Issue
Block a user