[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:
parent
9685f44f51
commit
20aad404d0
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
],
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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",
|
||||
],
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user