[sparkplug][x64] Reduce CallRecordWrite instructions
Directly use the correct registers for calling the RecordWrite stubs in sparkplug. To keep changes to existing builtins minimal there are certain register requirements which are now made explicit in WriteBarrierDescriptor::Verify. Bug: v8:11420 Change-Id: I3a0c500fbe26f82ee2243a61dbf574fd31656982 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2910313 Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#74998}
This commit is contained in:
parent
0f4d1cecb7
commit
f68e1be795
@ -713,6 +713,18 @@ void BaselineCompiler::VisitLdaImmutableCurrentContextSlot() {
|
||||
}
|
||||
|
||||
void BaselineCompiler::VisitStaContextSlot() {
|
||||
// TODO(cbruni): enable on all platforms
|
||||
#if V8_TARGET_ARCH_X64
|
||||
Register value = WriteBarrierDescriptor::ValueRegister();
|
||||
Register context = WriteBarrierDescriptor::ObjectRegister();
|
||||
DCHECK(!AreAliased(value, context, kInterpreterAccumulatorRegister));
|
||||
__ Move(value, kInterpreterAccumulatorRegister);
|
||||
LoadRegister(context, 0);
|
||||
int depth = Uint(2);
|
||||
for (; depth > 0; --depth) {
|
||||
__ LoadTaggedPointerField(context, context, Context::kPreviousOffset);
|
||||
}
|
||||
#else
|
||||
BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_);
|
||||
Register context = scratch_scope.AcquireScratch();
|
||||
LoadRegister(context, 0);
|
||||
@ -722,17 +734,27 @@ void BaselineCompiler::VisitStaContextSlot() {
|
||||
}
|
||||
Register value = scratch_scope.AcquireScratch();
|
||||
__ Move(value, kInterpreterAccumulatorRegister);
|
||||
#endif // V8_TARGET_ARCH_X64
|
||||
__ StoreTaggedFieldWithWriteBarrier(
|
||||
context, Context::OffsetOfElementAt(iterator().GetIndexOperand(1)),
|
||||
value);
|
||||
}
|
||||
|
||||
void BaselineCompiler::VisitStaCurrentContextSlot() {
|
||||
// TODO(cbruni): enable on all platforms
|
||||
#if V8_TARGET_ARCH_X64
|
||||
Register value = WriteBarrierDescriptor::ValueRegister();
|
||||
Register context = WriteBarrierDescriptor::ObjectRegister();
|
||||
DCHECK(!AreAliased(value, context, kInterpreterAccumulatorRegister));
|
||||
__ Move(value, kInterpreterAccumulatorRegister);
|
||||
__ LoadContext(context);
|
||||
#else
|
||||
BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_);
|
||||
Register context = scratch_scope.AcquireScratch();
|
||||
__ LoadContext(context);
|
||||
Register value = scratch_scope.AcquireScratch();
|
||||
__ Move(value, kInterpreterAccumulatorRegister);
|
||||
#endif // V8_TARGET_ARCH_X64
|
||||
__ StoreTaggedFieldWithWriteBarrier(
|
||||
context, Context::OffsetOfElementAt(Index(0)), value);
|
||||
}
|
||||
@ -857,6 +879,34 @@ void BaselineCompiler::VisitLdaModuleVariable() {
|
||||
}
|
||||
|
||||
void BaselineCompiler::VisitStaModuleVariable() {
|
||||
// TODO(cbruni): enable on all platforms
|
||||
#if V8_TARGET_ARCH_X64
|
||||
int cell_index = Int(0);
|
||||
if (V8_UNLIKELY(cell_index < 0)) {
|
||||
// Not supported (probably never).
|
||||
CallRuntime(Runtime::kAbort,
|
||||
Smi::FromInt(static_cast<int>(
|
||||
AbortReason::kUnsupportedModuleOperation)));
|
||||
__ Trap();
|
||||
}
|
||||
Register value = WriteBarrierDescriptor::ValueRegister();
|
||||
Register scratch = WriteBarrierDescriptor::ObjectRegister();
|
||||
DCHECK(!AreAliased(value, scratch, kInterpreterAccumulatorRegister));
|
||||
__ Move(value, kInterpreterAccumulatorRegister);
|
||||
__ LoadContext(scratch);
|
||||
int depth = Uint(1);
|
||||
for (; depth > 0; --depth) {
|
||||
__ LoadTaggedPointerField(scratch, scratch, Context::kPreviousOffset);
|
||||
}
|
||||
__ LoadTaggedPointerField(scratch, scratch, Context::kExtensionOffset);
|
||||
__ LoadTaggedPointerField(scratch, scratch,
|
||||
SourceTextModule::kRegularExportsOffset);
|
||||
|
||||
// The actual array index is (cell_index - 1).
|
||||
cell_index -= 1;
|
||||
__ LoadFixedArrayElement(scratch, scratch, cell_index);
|
||||
__ StoreTaggedFieldWithWriteBarrier(scratch, Cell::kValueOffset, value);
|
||||
#else // V8_TARGET_ARCH_X64
|
||||
BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_);
|
||||
Register scratch = scratch_scope.AcquireScratch();
|
||||
__ LoadContext(scratch);
|
||||
@ -882,6 +932,7 @@ void BaselineCompiler::VisitStaModuleVariable() {
|
||||
AbortReason::kUnsupportedModuleOperation)));
|
||||
__ Trap();
|
||||
}
|
||||
#endif // V8_TARGET_ARCH_X64
|
||||
}
|
||||
|
||||
void BaselineCompiler::VisitStaNamedProperty() {
|
||||
|
@ -318,12 +318,9 @@ void BaselineAssembler::StoreTaggedSignedField(Register target, int offset,
|
||||
}
|
||||
void BaselineAssembler::StoreTaggedFieldWithWriteBarrier(Register target,
|
||||
int offset,
|
||||
|
||||
Register value) {
|
||||
BaselineAssembler::ScratchRegisterScope scratch_scope(this);
|
||||
Register scratch = scratch_scope.AcquireScratch();
|
||||
DCHECK_NE(target, scratch);
|
||||
DCHECK_NE(value, scratch);
|
||||
Register scratch = WriteBarrierDescriptor::SlotAddressRegister();
|
||||
DCHECK(!AreAliased(target, value, scratch));
|
||||
__ StoreTaggedField(FieldOperand(target, offset), value);
|
||||
__ RecordWriteField(target, offset, value, scratch, SaveFPRegsMode::kIgnore);
|
||||
}
|
||||
|
@ -686,7 +686,10 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
|
||||
// Store input value into generator object.
|
||||
__ StoreTaggedField(
|
||||
FieldOperand(rdx, JSGeneratorObject::kInputOrDebugPosOffset), rax);
|
||||
__ RecordWriteField(rdx, JSGeneratorObject::kInputOrDebugPosOffset, rax, rcx,
|
||||
Register object = WriteBarrierDescriptor::ObjectRegister();
|
||||
__ Move(object, rdx);
|
||||
__ RecordWriteField(object, JSGeneratorObject::kInputOrDebugPosOffset, rax,
|
||||
WriteBarrierDescriptor::SlotAddressRegister(),
|
||||
SaveFPRegsMode::kIgnore);
|
||||
|
||||
Register decompr_scratch1 = COMPRESS_POINTERS_BOOL ? r8 : no_reg;
|
||||
@ -1086,7 +1089,8 @@ static void MaybeOptimizeCodeOrTailCallOptimizedCodeSlot(
|
||||
__ LoadAnyTaggedField(
|
||||
optimized_code_entry,
|
||||
FieldOperand(feedback_vector, FeedbackVector::kMaybeOptimizedCodeOffset));
|
||||
TailCallOptimizedCodeSlot(masm, optimized_code_entry, closure, r8, r15,
|
||||
TailCallOptimizedCodeSlot(masm, optimized_code_entry, closure, r9,
|
||||
WriteBarrierDescriptor::SlotAddressRegister(),
|
||||
jump_mode);
|
||||
}
|
||||
|
||||
@ -1327,9 +1331,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
||||
FieldOperand(kInterpreterBytecodeArrayRegister,
|
||||
BaselineData::kBaselineCodeOffset));
|
||||
static_assert(kJavaScriptCallCodeStartRegister == rcx, "ABI mismatch");
|
||||
ReplaceClosureCodeWithOptimizedCode(masm, rcx, closure,
|
||||
kInterpreterBytecodeArrayRegister,
|
||||
kInterpreterBytecodeOffsetRegister);
|
||||
ReplaceClosureCodeWithOptimizedCode(
|
||||
masm, rcx, closure, kInterpreterBytecodeArrayRegister,
|
||||
WriteBarrierDescriptor::SlotAddressRegister());
|
||||
__ JumpCodeObject(rcx);
|
||||
|
||||
__ bind(&install_baseline_code);
|
||||
@ -1856,7 +1860,8 @@ void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
|
||||
void Builtins::Generate_TailCallOptimizedCodeSlot(MacroAssembler* masm) {
|
||||
Register optimized_code_entry = kJavaScriptCallCodeStartRegister;
|
||||
Register closure = kJSFunctionRegister;
|
||||
TailCallOptimizedCodeSlot(masm, optimized_code_entry, closure, r8, r15,
|
||||
TailCallOptimizedCodeSlot(masm, optimized_code_entry, closure, r9,
|
||||
WriteBarrierDescriptor::SlotAddressRegister(),
|
||||
JumpMode::kJump);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,23 @@ constexpr auto CallInterfaceDescriptor::DefaultRegisterArray() {
|
||||
return registers;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
template <typename DerivedDescriptor>
|
||||
void StaticCallInterfaceDescriptor<DerivedDescriptor>::
|
||||
VerifyArgumentRegisterCount(CallInterfaceDescriptorData* data, int argc) {
|
||||
RegList allocatable_regs = data->allocatable_registers();
|
||||
if (argc >= 1) DCHECK(allocatable_regs | r0.bit());
|
||||
if (argc >= 2) DCHECK(allocatable_regs | r1.bit());
|
||||
if (argc >= 3) DCHECK(allocatable_regs | r2.bit());
|
||||
if (argc >= 4) DCHECK(allocatable_regs | r3.bit());
|
||||
if (argc >= 5) DCHECK(allocatable_regs | r4.bit());
|
||||
if (argc >= 6) DCHECK(allocatable_regs | r5.bit());
|
||||
if (argc >= 7) DCHECK(allocatable_regs | r6.bit());
|
||||
if (argc >= 8) DCHECK(allocatable_regs | r7.bit());
|
||||
// Additional arguments are passed on the stack.
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
constexpr auto WriteBarrierDescriptor::registers() {
|
||||
STATIC_ASSERT(kReturnRegister0 == r0);
|
||||
|
@ -20,6 +20,22 @@ constexpr auto CallInterfaceDescriptor::DefaultRegisterArray() {
|
||||
return registers;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
template <typename DerivedDescriptor>
|
||||
void StaticCallInterfaceDescriptor<DerivedDescriptor>::
|
||||
VerifyArgumentRegisterCount(CallInterfaceDescriptorData* data, int argc) {
|
||||
RegList allocatable_regs = data->allocatable_registers();
|
||||
if (argc >= 1) DCHECK(allocatable_regs | x0.bit());
|
||||
if (argc >= 2) DCHECK(allocatable_regs | x1.bit());
|
||||
if (argc >= 3) DCHECK(allocatable_regs | x2.bit());
|
||||
if (argc >= 4) DCHECK(allocatable_regs | x3.bit());
|
||||
if (argc >= 5) DCHECK(allocatable_regs | x4.bit());
|
||||
if (argc >= 6) DCHECK(allocatable_regs | x5.bit());
|
||||
if (argc >= 7) DCHECK(allocatable_regs | x6.bit());
|
||||
if (argc >= 8) DCHECK(allocatable_regs | x7.bit());
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
constexpr auto WriteBarrierDescriptor::registers() {
|
||||
STATIC_ASSERT(kReturnRegister0 == x0);
|
||||
|
@ -18,6 +18,18 @@ constexpr auto CallInterfaceDescriptor::DefaultRegisterArray() {
|
||||
return registers;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
template <typename DerivedDescriptor>
|
||||
void StaticCallInterfaceDescriptor<DerivedDescriptor>::
|
||||
VerifyArgumentRegisterCount(CallInterfaceDescriptorData* data,
|
||||
int nof_expected_args) {
|
||||
RegList allocatable_regs = data->allocatable_registers();
|
||||
if (nof_expected_args >= 1) DCHECK(allocatable_regs | esi.bit());
|
||||
if (nof_expected_args >= 2) DCHECK(allocatable_regs | edi.bit());
|
||||
// Additional arguments are passed on the stack.
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
constexpr auto WriteBarrierDescriptor::registers() {
|
||||
STATIC_ASSERT(esi == kContextRegister);
|
||||
|
@ -84,8 +84,10 @@ void StaticCallInterfaceDescriptor<DerivedDescriptor>::Initialize(
|
||||
|
||||
DCHECK(data->IsInitialized());
|
||||
DCHECK(this->CheckFloatingPointParameters(data));
|
||||
#if DEBUG
|
||||
DerivedDescriptor::Verify(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename DerivedDescriptor>
|
||||
constexpr int
|
||||
|
@ -125,5 +125,33 @@ bool CallInterfaceDescriptor::IsValidFloatParameterRegister(Register reg) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
template <typename DerivedDescriptor>
|
||||
void StaticCallInterfaceDescriptor<DerivedDescriptor>::Verify(
|
||||
CallInterfaceDescriptorData* data) {}
|
||||
// static
|
||||
void WriteBarrierDescriptor::Verify(CallInterfaceDescriptorData* data) {
|
||||
DCHECK(!AreAliased(ObjectRegister(), SlotAddressRegister(), ValueRegister()));
|
||||
// TODO(cbruni): enable on all platforms.
|
||||
#if V8_TARGET_ARCH_X64
|
||||
// The default parameters should not clobber vital registers in order to
|
||||
// reduce code size:
|
||||
DCHECK(!AreAliased(ObjectRegister(), kContextRegister,
|
||||
kInterpreterAccumulatorRegister));
|
||||
DCHECK(!AreAliased(SlotAddressRegister(), kContextRegister,
|
||||
kInterpreterAccumulatorRegister));
|
||||
DCHECK(!AreAliased(ValueRegister(), kContextRegister,
|
||||
kInterpreterAccumulatorRegister));
|
||||
// Coincidental: to make calling from various builtins easier.
|
||||
DCHECK_EQ(ObjectRegister(), kJSFunctionRegister);
|
||||
#endif
|
||||
// We need a certain set of registers by default:
|
||||
RegList allocatable_regs = data->allocatable_registers();
|
||||
DCHECK(allocatable_regs | kContextRegister.bit());
|
||||
DCHECK(allocatable_regs | kReturnRegister0.bit());
|
||||
VerifyArgumentRegisterCount(data, 4);
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -473,10 +473,18 @@ class StaticCallInterfaceDescriptor : public CallInterfaceDescriptor {
|
||||
static constexpr inline Register GetRegisterParameter(int i) {
|
||||
return DerivedDescriptor::registers()[i];
|
||||
}
|
||||
|
||||
explicit StaticCallInterfaceDescriptor(CallDescriptors::Key key)
|
||||
: CallInterfaceDescriptor(key) {}
|
||||
|
||||
#if DEBUG
|
||||
// Overwritten in DerivedDescriptor.
|
||||
static void Verify(CallInterfaceDescriptorData* data);
|
||||
// Verify that the CallInterfaceDescriptorData contains the default
|
||||
// argument registers for {argc} arguments.
|
||||
static inline void VerifyArgumentRegisterCount(
|
||||
CallInterfaceDescriptorData* data, int nof_expected_args);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// {CallDescriptors} is allowed to call the private {Initialize} method.
|
||||
friend class CallDescriptors;
|
||||
@ -1025,6 +1033,9 @@ class WriteBarrierDescriptor final
|
||||
static constexpr inline Register ValueRegister();
|
||||
static constexpr inline RegList ComputeSavedRegisters(
|
||||
Register object, Register slot_address = no_reg);
|
||||
#if DEBUG
|
||||
static void Verify(CallInterfaceDescriptorData* data);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef V8_IS_TSAN
|
||||
|
@ -18,10 +18,27 @@ constexpr auto CallInterfaceDescriptor::DefaultRegisterArray() {
|
||||
return registers;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
template <typename DerivedDescriptor>
|
||||
void StaticCallInterfaceDescriptor<DerivedDescriptor>::
|
||||
VerifyArgumentRegisterCount(CallInterfaceDescriptorData* data,
|
||||
int nof_expected_args) {
|
||||
RegList allocatable_regs = data->allocatable_registers();
|
||||
if (nof_expected_args >= 1) DCHECK(allocatable_regs | arg_reg_1.bit());
|
||||
if (nof_expected_args >= 2) DCHECK(allocatable_regs | arg_reg_2.bit());
|
||||
if (nof_expected_args >= 3) DCHECK(allocatable_regs | arg_reg_3.bit());
|
||||
if (nof_expected_args >= 4) DCHECK(allocatable_regs | arg_reg_4.bit());
|
||||
// Additional arguments are passed on the stack.
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
constexpr auto WriteBarrierDescriptor::registers() {
|
||||
return RegisterArray(arg_reg_1, arg_reg_2, arg_reg_3, arg_reg_4,
|
||||
kReturnRegister0);
|
||||
#if V8_TARGET_OS_WIN
|
||||
return RegisterArray(rdi, r8, rcx, rax, r9, rdx, rsi);
|
||||
#else
|
||||
return RegisterArray(rdi, rbx, rdx, rcx, rax, rsi);
|
||||
#endif // V8_TARGET_OS_WIN
|
||||
}
|
||||
|
||||
#ifdef V8_IS_TSAN
|
||||
|
@ -553,8 +553,7 @@ void MacroAssembler::RecordWrite(Register object, Register slot_address,
|
||||
MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done,
|
||||
Label::kNear);
|
||||
|
||||
CallRecordWriteStubSaveRegisters(object, slot_address, remembered_set_action,
|
||||
fp_mode);
|
||||
CallRecordWriteStub(object, slot_address, remembered_set_action, fp_mode);
|
||||
|
||||
bind(&done);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user