From 20aad404d0a3da13c1b8314c8d1df9e23ae045fb Mon Sep 17 00:00:00 2001 From: Victor Gomes Date: Wed, 11 Jan 2023 13:06:26 +0100 Subject: [PATCH] [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 Commit-Queue: Victor Gomes Cr-Commit-Position: refs/heads/main@{#85216} --- src/codegen/arm64/macro-assembler-arm64-inl.h | 6 + src/codegen/arm64/macro-assembler-arm64.h | 1 + src/maglev/DEPS | 6 + src/maglev/arm64/maglev-assembler-arm64-inl.h | 8 ++ src/maglev/arm64/maglev-ir-arm64.cc | 2 - src/maglev/maglev-assembler.h | 3 + src/maglev/maglev-ir.cc | 117 ++++++++++++++++++ src/maglev/x64/DEPS | 8 -- src/maglev/x64/maglev-assembler-x64-inl.h | 8 ++ src/maglev/x64/maglev-ir-x64.cc | 114 ----------------- 10 files changed, 149 insertions(+), 124 deletions(-) delete mode 100644 src/maglev/x64/DEPS diff --git a/src/codegen/arm64/macro-assembler-arm64-inl.h b/src/codegen/arm64/macro-assembler-arm64-inl.h index 72c367d33c..6a4cc044ee 100644 --- a/src/codegen/arm64/macro-assembler-arm64-inl.h +++ b/src/codegen/arm64/macro-assembler-arm64-inl.h @@ -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 diff --git a/src/codegen/arm64/macro-assembler-arm64.h b/src/codegen/arm64/macro-assembler-arm64.h index 515561ba70..d597408de6 100644 --- a/src/codegen/arm64/macro-assembler-arm64.h +++ b/src/codegen/arm64/macro-assembler-arm64.h @@ -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, diff --git a/src/maglev/DEPS b/src/maglev/DEPS index 6bb6ecf188..b6aca49f37 100644 --- a/src/maglev/DEPS +++ b/src/maglev/DEPS @@ -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", + ], } diff --git a/src/maglev/arm64/maglev-assembler-arm64-inl.h b/src/maglev/arm64/maglev-assembler-arm64-inl.h index 646fdc396c..8a57462ff9 100644 --- a/src/maglev/arm64/maglev-assembler-arm64-inl.h +++ b/src/maglev/arm64/maglev-assembler-arm64-inl.h @@ -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()); } diff --git a/src/maglev/arm64/maglev-ir-arm64.cc b/src/maglev/arm64/maglev-ir-arm64.cc index f5b6f97bf0..c8ce00e8dd 100644 --- a/src/maglev/arm64/maglev-ir-arm64.cc +++ b/src/maglev/arm64/maglev-ir-arm64.cc @@ -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(); } diff --git a/src/maglev/maglev-assembler.h b/src/maglev/maglev-assembler.h index 20f16cb5c9..d2ac2fda96 100644 --- a/src/maglev/maglev-assembler.h +++ b/src/maglev/maglev-assembler.h @@ -161,12 +161,15 @@ class MaglevAssembler : public MacroAssembler { inline void Move(DoubleRegister dst, double n); inline void Move(Register dst, Handle obj); + inline void LoadByte(Register dst, MemOperand src); + inline void SignExtend32To64Bits(Register dst, Register src); template 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); diff --git a/src/maglev/maglev-ir.cc b/src/maglev/maglev-ir.cc index 922095cbf8..2a4d47d38e 100644 --- a/src/maglev/maglev-ir.cc +++ b/src/maglev/maglev-ir.cc @@ -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(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) { diff --git a/src/maglev/x64/DEPS b/src/maglev/x64/DEPS deleted file mode 100644 index 0a2f64064b..0000000000 --- a/src/maglev/x64/DEPS +++ /dev/null @@ -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", - ], -} diff --git a/src/maglev/x64/maglev-assembler-x64-inl.h b/src/maglev/x64/maglev-assembler-x64-inl.h index 081469dc09..49e86eb562 100644 --- a/src/maglev/x64/maglev-assembler-x64-inl.h +++ b/src/maglev/x64/maglev-assembler-x64-inl.h @@ -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); } diff --git a/src/maglev/x64/maglev-ir-x64.cc b/src/maglev/x64/maglev-ir-x64.cc index 333ebe2e0f..e6c2973042 100644 --- a/src/maglev/x64/maglev-ir-x64.cc +++ b/src/maglev/x64/maglev-ir-x64.cc @@ -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(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()); }