[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:
parent
11b9128d19
commit
325ea86f33
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user