[maglev] Share JumpLoopProgolue IR

Bug: v8:7700
Change-Id: I738523b02e2700438a179e00f252d3fce53a0066
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4131403
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85216}
This commit is contained in:
Victor Gomes 2023-01-11 13:06:26 +01:00 committed by V8 LUCI CQ
parent 9685f44f51
commit 20aad404d0
10 changed files with 149 additions and 124 deletions

View File

@ -1148,6 +1148,12 @@ void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) {
JumpIfSmi(value, nullptr, not_smi_label);
}
inline void MacroAssembler::AssertFeedbackVector(Register object) {
UseScratchRegisterScope temps(this);
Register scratch = temps.AcquireX();
AssertFeedbackVector(object, scratch);
}
void TurboAssembler::jmp(Label* L) { B(L); }
template <TurboAssembler::StoreLRMode lr_mode>

View File

@ -1883,6 +1883,7 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
void PopCalleeSavedRegisters();
// Tiering support.
inline void AssertFeedbackVector(Register object);
void AssertFeedbackVector(Register object,
Register scratch) NOOP_UNLESS_DEBUG_CODE
void ReplaceClosureCodeWithOptimizedCode(Register optimized_code,

View File

@ -8,4 +8,10 @@ specific_include_rules = {
"maglev-graph-builder\.h": [
"+src/interpreter/interpreter-intrinsics.h",
],
"maglev-ir\.cc": [
# Allow Maglev to reuse the baseline assembler.
# TODO(v8:7700): Clean up these dependencies by extracting common code to a
# separate directory.
"+src/baseline/baseline-assembler-inl.h",
],
}

View File

@ -472,6 +472,14 @@ inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
}
}
inline void MaglevAssembler::LoadByte(Register dst, MemOperand src) {
ldrb(dst.W(), src);
}
inline void MaglevAssembler::CompareInt32(Register reg, int32_t imm) {
Cmp(reg.W(), Immediate(imm));
}
inline void MaglevAssembler::CompareInt32(Register src1, Register src2) {
Cmp(src1.W(), src2.W());
}

View File

@ -265,8 +265,6 @@ void CheckJSObjectElementsBounds::GenerateCode(MaglevAssembler* masm,
__ EmitEagerDeoptIf(hs, DeoptimizeReason::kOutOfBounds, this);
}
UNIMPLEMENTED_NODE_WITH_CALL(JumpLoopPrologue, loop_depth_, unit_)
int BuiltinStringFromCharCode::MaxCallStackArgs() const {
return AllocateDescriptor::GetStackParameterCount();
}

View File

@ -161,12 +161,15 @@ class MaglevAssembler : public MacroAssembler {
inline void Move(DoubleRegister dst, double n);
inline void Move(Register dst, Handle<HeapObject> obj);
inline void LoadByte(Register dst, MemOperand src);
inline void SignExtend32To64Bits(Register dst, Register src);
template <typename NodeT>
inline void DeoptIfBufferDetached(Register array, Register scratch,
NodeT* node);
inline void CompareInt32(Register reg, int32_t imm);
inline void CompareInt32(Register src1, Register src2);
inline void Jump(Label* target);

View File

@ -4,6 +4,7 @@
#include "src/maglev/maglev-ir.h"
#include "src/baseline/baseline-assembler-inl.h"
#include "src/builtins/builtins-constructor.h"
#include "src/codegen/interface-descriptors-inl.h"
#include "src/execution/isolate-inl.h"
@ -2288,6 +2289,122 @@ void JumpFromInlined::GenerateCode(MaglevAssembler* masm,
}
}
namespace {
void AttemptOnStackReplacement(MaglevAssembler* masm,
ZoneLabelRef no_code_for_osr,
JumpLoopPrologue* node, Register scratch0,
Register scratch1, int32_t loop_depth,
FeedbackSlot feedback_slot,
BytecodeOffset osr_offset) {
// Two cases may cause us to attempt OSR, in the following order:
//
// 1) Presence of cached OSR Turbofan code.
// 2) The OSR urgency exceeds the current loop depth - in that case, call
// into runtime to trigger a Turbofan OSR compilation. A non-zero return
// value means we should deopt into Ignition which will handle all further
// necessary steps (rewriting the stack frame, jumping to OSR'd code).
//
// See also: InterpreterAssembler::OnStackReplacement.
baseline::BaselineAssembler basm(masm);
__ AssertFeedbackVector(scratch0);
// Case 1).
Label deopt;
Register maybe_target_code = scratch1;
{
basm.TryLoadOptimizedOsrCode(maybe_target_code, scratch0, feedback_slot,
&deopt, Label::kFar);
}
// Case 2).
{
__ LoadByte(scratch0,
FieldMemOperand(scratch0, FeedbackVector::kOsrStateOffset));
__ DecodeField<FeedbackVector::OsrUrgencyBits>(scratch0);
basm.JumpIfByte(baseline::Condition::kUnsignedLessThanEqual, scratch0,
loop_depth, *no_code_for_osr, Label::kNear);
// The osr_urgency exceeds the current loop_depth, signaling an OSR
// request. Call into runtime to compile.
{
// At this point we need a custom register snapshot since additional
// registers may be live at the eager deopt below (the normal
// register_snapshot only contains live registers *after this
// node*).
// TODO(v8:7700): Consider making the snapshot location
// configurable.
RegisterSnapshot snapshot = node->register_snapshot();
AddDeoptRegistersToSnapshot(&snapshot, node->eager_deopt_info());
DCHECK(!snapshot.live_registers.has(maybe_target_code));
SaveRegisterStateForCall save_register_state(masm, snapshot);
__ Move(kContextRegister, masm->native_context().object());
__ Push(Smi::FromInt(osr_offset.ToInt()));
__ CallRuntime(Runtime::kCompileOptimizedOSRFromMaglev, 1);
save_register_state.DefineSafepoint();
__ Move(maybe_target_code, kReturnRegister0);
}
// A `0` return value means there is no OSR code available yet. Continue
// execution in Maglev, OSR code will be picked up once it exists and is
// cached on the feedback vector.
__ Cmp(maybe_target_code, 0);
__ JumpIf(ToCondition(AssertCondition::kEqual), *no_code_for_osr);
}
__ bind(&deopt);
if (V8_LIKELY(v8_flags.turbofan)) {
// None of the mutated input registers should be a register input into the
// eager deopt info.
DCHECK_REGLIST_EMPTY(
RegList{scratch0, scratch1} &
GetGeneralRegistersUsedAsInputs(node->eager_deopt_info()));
__ EmitEagerDeopt(node, DeoptimizeReason::kPrepareForOnStackReplacement);
} else {
// Continue execution in Maglev. With TF disabled we cannot OSR and thus it
// doesn't make sense to start the process. We do still perform all
// remaining bookkeeping above though, to keep Maglev code behavior roughly
// the same in both configurations.
__ Jump(*no_code_for_osr);
}
}
} // namespace
int JumpLoopPrologue::MaxCallStackArgs() const {
// For the kCompileOptimizedOSRFromMaglev call.
return 1;
}
void JumpLoopPrologue::SetValueLocationConstraints() {
if (!v8_flags.use_osr) return;
set_temporaries_needed(2);
}
void JumpLoopPrologue::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
if (!v8_flags.use_osr) return;
Register scratch0 = general_temporaries().PopFirst();
Register scratch1 = general_temporaries().PopFirst();
const Register osr_state = scratch1;
__ Move(scratch0, unit_->feedback().object());
__ AssertFeedbackVector(scratch0);
__ LoadByte(osr_state,
FieldMemOperand(scratch0, FeedbackVector::kOsrStateOffset));
// The quick initial OSR check. If it passes, we proceed on to more
// expensive OSR logic.
static_assert(FeedbackVector::MaybeHasOptimizedOsrCodeBit::encode(true) >
FeedbackVector::kMaxOsrUrgency);
__ CompareInt32(osr_state, loop_depth_);
ZoneLabelRef no_code_for_osr(masm);
__ JumpToDeferredIf(ToCondition(AssertCondition::kAbove),
AttemptOnStackReplacement, no_code_for_osr, this,
scratch0, scratch1, loop_depth_, feedback_slot_,
osr_offset_);
__ bind(*no_code_for_osr);
}
void JumpLoop::SetValueLocationConstraints() {}
void JumpLoop::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {

View File

@ -1,8 +0,0 @@
specific_include_rules = {
"maglev-ir-x64\.cc": [
# Allow Maglev to reuse the baseline assembler.
# TODO(v8:7700): Clean up these dependencies by extracting common code to a
# separate directory.
"+src/baseline/baseline-assembler-inl.h",
],
}

View File

@ -360,6 +360,14 @@ inline void MaglevAssembler::DeoptIfBufferDetached(Register array,
}
}
inline void MaglevAssembler::LoadByte(Register dst, MemOperand src) {
movb(dst, src);
}
inline void MaglevAssembler::CompareInt32(Register reg, int32_t imm) {
cmpl(reg, Immediate(imm));
}
inline void MaglevAssembler::CompareInt32(Register src1, Register src2) {
cmpl(src1, src2);
}

View File

@ -4,7 +4,6 @@
#include "src/base/bits.h"
#include "src/base/logging.h"
#include "src/baseline/baseline-assembler-inl.h"
#include "src/builtins/builtins-constructor.h"
#include "src/codegen/interface-descriptors-inl.h"
#include "src/codegen/interface-descriptors.h"
@ -2700,119 +2699,6 @@ void Return::GenerateCode(MaglevAssembler* masm, const ProcessingState& state) {
__ Ret();
}
namespace {
void AttemptOnStackReplacement(MaglevAssembler* masm,
ZoneLabelRef no_code_for_osr,
JumpLoopPrologue* node, Register scratch0,
Register scratch1, int32_t loop_depth,
FeedbackSlot feedback_slot,
BytecodeOffset osr_offset) {
// Two cases may cause us to attempt OSR, in the following order:
//
// 1) Presence of cached OSR Turbofan code.
// 2) The OSR urgency exceeds the current loop depth - in that case, call
// into runtime to trigger a Turbofan OSR compilation. A non-zero return
// value means we should deopt into Ignition which will handle all further
// necessary steps (rewriting the stack frame, jumping to OSR'd code).
//
// See also: InterpreterAssembler::OnStackReplacement.
baseline::BaselineAssembler basm(masm);
__ AssertFeedbackVector(scratch0);
// Case 1).
Label deopt;
Register maybe_target_code = scratch1;
{
basm.TryLoadOptimizedOsrCode(maybe_target_code, scratch0, feedback_slot,
&deopt, Label::kFar);
}
// Case 2).
{
__ movb(scratch0, FieldOperand(scratch0, FeedbackVector::kOsrStateOffset));
__ DecodeField<FeedbackVector::OsrUrgencyBits>(scratch0);
basm.JumpIfByte(baseline::Condition::kUnsignedLessThanEqual, scratch0,
loop_depth, *no_code_for_osr, Label::kNear);
// The osr_urgency exceeds the current loop_depth, signaling an OSR
// request. Call into runtime to compile.
{
// At this point we need a custom register snapshot since additional
// registers may be live at the eager deopt below (the normal
// register_snapshot only contains live registers *after this
// node*).
// TODO(v8:7700): Consider making the snapshot location
// configurable.
RegisterSnapshot snapshot = node->register_snapshot();
AddDeoptRegistersToSnapshot(&snapshot, node->eager_deopt_info());
DCHECK(!snapshot.live_registers.has(maybe_target_code));
SaveRegisterStateForCall save_register_state(masm, snapshot);
__ Move(kContextRegister, masm->native_context().object());
__ Push(Smi::FromInt(osr_offset.ToInt()));
__ CallRuntime(Runtime::kCompileOptimizedOSRFromMaglev, 1);
save_register_state.DefineSafepoint();
__ Move(maybe_target_code, kReturnRegister0);
}
// A `0` return value means there is no OSR code available yet. Continue
// execution in Maglev, OSR code will be picked up once it exists and is
// cached on the feedback vector.
__ Cmp(maybe_target_code, 0);
__ j(equal, *no_code_for_osr, Label::kNear);
}
__ bind(&deopt);
if (V8_LIKELY(v8_flags.turbofan)) {
// None of the mutated input registers should be a register input into the
// eager deopt info.
DCHECK_REGLIST_EMPTY(
RegList{scratch0, scratch1} &
GetGeneralRegistersUsedAsInputs(node->eager_deopt_info()));
__ EmitEagerDeopt(node, DeoptimizeReason::kPrepareForOnStackReplacement);
} else {
// Continue execution in Maglev. With TF disabled we cannot OSR and thus it
// doesn't make sense to start the process. We do still perform all
// remaining bookkeeping above though, to keep Maglev code behavior roughly
// the same in both configurations.
__ jmp(*no_code_for_osr, Label::kNear);
}
}
} // namespace
int JumpLoopPrologue::MaxCallStackArgs() const {
// For the kCompileOptimizedOSRFromMaglev call.
return 1;
}
void JumpLoopPrologue::SetValueLocationConstraints() {
if (!v8_flags.use_osr) return;
set_temporaries_needed(2);
}
void JumpLoopPrologue::GenerateCode(MaglevAssembler* masm,
const ProcessingState& state) {
if (!v8_flags.use_osr) return;
Register scratch0 = general_temporaries().PopFirst();
Register scratch1 = general_temporaries().PopFirst();
const Register osr_state = scratch1;
__ Move(scratch0, unit_->feedback().object());
__ AssertFeedbackVector(scratch0);
__ movb(osr_state, FieldOperand(scratch0, FeedbackVector::kOsrStateOffset));
// The quick initial OSR check. If it passes, we proceed on to more
// expensive OSR logic.
static_assert(FeedbackVector::MaybeHasOptimizedOsrCodeBit::encode(true) >
FeedbackVector::kMaxOsrUrgency);
__ cmpl(osr_state, Immediate(loop_depth_));
ZoneLabelRef no_code_for_osr(masm);
__ JumpToDeferredIf(above, AttemptOnStackReplacement, no_code_for_osr, this,
scratch0, scratch1, loop_depth_, feedback_slot_,
osr_offset_);
__ bind(*no_code_for_osr);
}
void BranchIfJSReceiver::SetValueLocationConstraints() {
UseRegister(condition_input());
}