[maglev] LoadPolymorphicTaggedField

Initial support for polymorphic loads using a single Maglev IR.

Bug: v8:7700
Change-Id: Ia1c800b60628636c6a9a0c153ab818fbc9d7540a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4178828
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85470}
This commit is contained in:
Victor Gomes 2023-01-25 09:56:15 +01:00 committed by V8 LUCI CQ
parent 11b9128d19
commit 325ea86f33
6 changed files with 215 additions and 2 deletions

View File

@ -496,6 +496,14 @@ inline void MaglevAssembler::LoadByte(Register dst, MemOperand src) {
Ldrb(dst, src);
}
inline void MaglevAssembler::CompareTagged(Register reg,
Handle<HeapObject> obj) {
ScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
Move(scratch, obj);
Cmp(reg, scratch);
}
inline void MaglevAssembler::CompareInt32(Register reg, int32_t imm) {
Cmp(reg.W(), Immediate(imm));
}
@ -511,6 +519,16 @@ inline void MaglevAssembler::JumpIf(Condition cond, Label* target,
b(target, cond);
}
inline void MaglevAssembler::JumpIfEqual(Label* target,
Label::Distance distance) {
b(target, eq);
}
inline void MaglevAssembler::JumpIfNotEqual(Label* target,
Label::Distance distance) {
b(target, ne);
}
inline void MaglevAssembler::JumpIfTaggedEqual(Register r1, Register r2,
Label* target, Label::Distance) {
CmpTagged(r1, r2);

View File

@ -194,12 +194,18 @@ class MaglevAssembler : public MacroAssembler {
inline void DeoptIfBufferDetached(Register array, Register scratch,
NodeT* node);
inline void CompareTagged(Register reg, Handle<HeapObject> obj);
inline void CompareInt32(Register reg, int32_t imm);
inline void CompareInt32(Register src1, Register src2);
inline void Jump(Label* target, Label::Distance distance = Label::kFar);
inline void JumpIf(Condition cond, Label* target,
Label::Distance distance = Label::kFar);
inline void JumpIfEqual(Label* target,
Label::Distance distance = Label::kFar);
inline void JumpIfNotEqual(Label* target,
Label::Distance distance = Label::kFar);
inline void JumpIfTaggedEqual(Register r1, Register r2, Label* target,
Label::Distance distance = Label::kFar);

View File

@ -2091,9 +2091,52 @@ bool MaglevGraphBuilder::TryBuildNamedAccess(
return TryBuildPropertyAccess(receiver, lookup_start_object,
feedback.name(), access_info, access_mode);
} else {
// TODO(victorgomes): polymorphic case.
// TODO(victorgomes): Support more generic polymorphic case.
// Only support polymorphic load at the moment.
if (access_mode != compiler::AccessMode::kLoad) {
return false;
}
// Check if we support the polymorphic load.
for (compiler::PropertyAccessInfo access_info : access_infos) {
switch (access_info.kind()) {
case compiler::PropertyAccessInfo::kNotFound:
case compiler::PropertyAccessInfo::kModuleExport:
break;
case compiler::PropertyAccessInfo::kDataField:
case compiler::PropertyAccessInfo::kFastDataConstant:
if (access_info.field_index().is_double()) {
return false;
}
break;
default:
// TODO(victorgomes): Support other access.
return false;
}
// TODO(victorgomes): Support map migration.
for (compiler::MapRef map : access_info.lookup_start_object_maps()) {
if (map.is_migration_target()) {
return false;
}
}
}
// Add compilation dependencies if needed.
for (compiler::PropertyAccessInfo access_info : access_infos) {
if (access_info.holder().has_value() &&
!access_info.HasDictionaryHolder()) {
broker()->dependencies()->DependOnStablePrototypeChains(
access_info.lookup_start_object_maps(), kStartAtPrototype,
access_info.holder().value());
}
}
SetAccumulator(AddNewNode<LoadPolymorphicTaggedField>(
{lookup_start_object}, std::move(access_infos)));
return true;
}
}
ValueNode* MaglevGraphBuilder::GetInt32ElementIndex(ValueNode* object) {

View File

@ -903,6 +903,110 @@ void LoadTaggedField::GenerateCode(MaglevAssembler* masm,
FieldMemOperand(object, offset()));
}
void LoadPolymorphicTaggedField::SetValueLocationConstraints() {
UseRegister(object_input());
DefineAsRegister(this);
set_temporaries_needed(1);
}
void LoadPolymorphicTaggedField::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
MaglevAssembler::ScratchRegisterScope temps(masm);
Register result_reg = ToRegister(result());
Register object = ToRegister(object_input());
Register object_map = temps.Acquire();
Label done;
Label is_number;
Condition is_smi = __ CheckSmi(object);
__ JumpIf(is_smi, &is_number);
__ LoadMap(object_map, object);
for (compiler::PropertyAccessInfo access_info : access_infos_) {
Label next;
Label do_load;
// Check if {object_map} one of the lookup_start_object_maps.
bool has_heap_number_map = false;
auto& maps = access_info.lookup_start_object_maps();
for (auto it = maps.begin(); it != maps.end(); ++it) {
if (it->IsHeapNumberMap()) {
has_heap_number_map = true;
}
__ CompareTagged(object_map, it->object());
if (it == maps.end() - 1) {
__ JumpIfNotEqual(&next);
// Fallthrough to {do_load}.
} else {
__ JumpIfEqual(&do_load);
__ Jump(&next);
}
}
// Bind number case here if one of the maps is HeapNumber.
if (has_heap_number_map && !is_number.is_bound()) {
__ bind(&is_number);
}
// Do the load based on the PropertyAccess kind.
__ bind(&do_load);
switch (access_info.kind()) {
case compiler::PropertyAccessInfo::kNotFound:
__ LoadRoot(result_reg, RootIndex::kUndefinedValue);
break;
case compiler::PropertyAccessInfo::kModuleExport: {
Register cell = object_map; // Reuse scratch.
__ Move(cell, access_info.constant().value().AsCell().object());
__ AssertNotSmi(cell);
__ DecompressAnyTagged(result_reg,
FieldMemOperand(cell, Cell::kValueOffset));
break;
}
case compiler::PropertyAccessInfo::kDataField:
case compiler::PropertyAccessInfo::kFastDataConstant: {
// TODO(victorgomes): Support ConstantDataFields.
Register load_source = object;
// Resolve property holder.
if (access_info.holder().has_value()) {
load_source = object_map; // Reuse scratch.
__ Move(load_source, access_info.holder().value().object());
}
FieldIndex field_index = access_info.field_index();
if (!field_index.is_inobject()) {
Register load_source_object = load_source;
if (load_source == object) {
load_source = object_map; // Reuse scratch.
}
// The field is in the property array, first load it from there.
__ AssertNotSmi(load_source_object);
__ DecompressAnyTagged(
load_source,
FieldMemOperand(load_source_object,
JSReceiver::kPropertiesOrHashOffset));
}
__ AssertNotSmi(load_source);
__ DecompressAnyTagged(
result_reg, FieldMemOperand(load_source, field_index.offset()));
break;
}
default:
UNREACHABLE();
}
__ Jump(&done);
__ bind(&next);
}
// A HeapNumberMap was not found, we should eager deopt here in case of a
// number.
if (!is_number.is_bound()) {
__ bind(&is_number);
}
// No map matched!
__ EmitEagerDeopt(this, DeoptimizeReason::kWrongMap);
__ bind(&done);
}
void LoadEnumCacheLength::SetValueLocationConstraints() {
UseRegister(map_input());
DefineAsRegister(this);

View File

@ -16,6 +16,7 @@
#include "src/codegen/source-position.h"
#include "src/common/globals.h"
#include "src/common/operation.h"
#include "src/compiler/access-info.h"
#include "src/compiler/backend/instruction.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/heap-refs.h"
@ -160,6 +161,7 @@ class CompactInterpreterFrameState;
V(GetSecondReturnedValue) \
V(GetTemplateObject) \
V(InitialValue) \
V(LoadPolymorphicTaggedField) \
V(LoadTaggedField) \
V(LoadDoubleField) \
V(LoadFixedArrayElement) \
@ -4035,6 +4037,31 @@ class BuiltinStringPrototypeCharCodeAt
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class LoadPolymorphicTaggedField
: public FixedInputValueNodeT<1, LoadPolymorphicTaggedField> {
using Base = FixedInputValueNodeT<1, LoadPolymorphicTaggedField>;
public:
explicit LoadPolymorphicTaggedField(
uint64_t bitfield, ZoneVector<compiler::PropertyAccessInfo>&& access_info)
: Base(bitfield), access_infos_(access_info) {}
static constexpr OpProperties kProperties =
OpProperties::Reading() | OpProperties::EagerDeopt();
static constexpr
typename Base::InputTypes kInputTypes{ValueRepresentation::kTagged};
static constexpr int kObjectIndex = 0;
Input& object_input() { return input(kObjectIndex); }
void SetValueLocationConstraints();
void GenerateCode(MaglevAssembler*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
private:
ZoneVector<compiler::PropertyAccessInfo> access_infos_;
};
class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> {
using Base = FixedInputValueNodeT<1, LoadTaggedField>;

View File

@ -385,6 +385,11 @@ inline void MaglevAssembler::LoadByte(Register dst, MemOperand src) {
movzxbl(dst, src);
}
inline void MaglevAssembler::CompareTagged(Register reg,
Handle<HeapObject> obj) {
Cmp(reg, obj);
}
inline void MaglevAssembler::CompareInt32(Register reg, int32_t imm) {
cmpl(reg, Immediate(imm));
}
@ -402,6 +407,16 @@ inline void MaglevAssembler::JumpIf(Condition cond, Label* target,
j(cond, target, distance);
}
inline void MaglevAssembler::JumpIfEqual(Label* target,
Label::Distance distance) {
j(equal, target, distance);
}
inline void MaglevAssembler::JumpIfNotEqual(Label* target,
Label::Distance distance) {
j(not_equal, target, distance);
}
inline void MaglevAssembler::JumpIfTaggedEqual(Register r1, Register r2,
Label* target,
Label::Distance distance) {