Commit f620df20 authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[maglev] Call the write barrier in GeneratorStore

There was a missing write barrier for the saved registers and context
in GeneratorStore. Add (deferred) write barriers for these, with some
careful register reshuffling to minimise moves.

Bug: v8:7700
Change-Id: Icf50e96adf3775785ce9b2c5a7566ecbbd1d63d9
Fixed: chromium:1359163
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3870914Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82962}
parent 9beb6f38
...@@ -840,26 +840,119 @@ void GeneratorStore::AllocateVreg(MaglevVregAllocationState* vreg_state) { ...@@ -840,26 +840,119 @@ void GeneratorStore::AllocateVreg(MaglevVregAllocationState* vreg_state) {
for (int i = 0; i < num_parameters_and_registers(); i++) { for (int i = 0; i < num_parameters_and_registers(); i++) {
UseAny(parameters_and_registers(i)); UseAny(parameters_and_registers(i));
} }
set_temporaries_needed(1); RequireSpecificTemporary(WriteBarrierDescriptor::ObjectRegister());
RequireSpecificTemporary(WriteBarrierDescriptor::SlotAddressRegister());
} }
void GeneratorStore::GenerateCode(MaglevCodeGenState* code_gen_state, void GeneratorStore::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) { const ProcessingState& state) {
Register generator = ToRegister(generator_input()); Register generator = ToRegister(generator_input());
Register array = temporaries().PopFirst(); Register array = WriteBarrierDescriptor::ObjectRegister();
__ DecompressAnyTagged( __ LoadTaggedPointerField(
array, FieldOperand(generator, array, FieldOperand(generator,
JSGeneratorObject::kParametersAndRegistersOffset)); JSGeneratorObject::kParametersAndRegistersOffset));
for (int i = 0; i < num_parameters_and_registers(); i++) { for (int i = 0; i < num_parameters_and_registers(); i++) {
Register value = FromAnyToRegister(code_gen_state, kScratchRegister, // Use WriteBarrierDescriptor::SlotAddressRegister() as the scratch
parameters_and_registers(i)); // register since it's a known temporary, and the write barrier slow path
// generates better code when value == scratch. Can't use kScratchRegister
// because CheckPageFlag uses it.
Register value = FromAnyToRegister(
code_gen_state, WriteBarrierDescriptor::SlotAddressRegister(),
parameters_and_registers(i));
DeferredCodeInfo* deferred_write_barrier = PushDeferredCode(
code_gen_state,
[](MaglevCodeGenState* code_gen_state, Label* return_label,
Register value, Register array, GeneratorStore* node,
int32_t offset) {
ASM_CODE_COMMENT_STRING(code_gen_state->masm(),
"Write barrier slow path");
// Use WriteBarrierDescriptor::SlotAddressRegister() as the scratch
// register, see comment above.
__ CheckPageFlag(
value, WriteBarrierDescriptor::SlotAddressRegister(),
MemoryChunk::kPointersToHereAreInterestingOrInSharedHeapMask,
zero, return_label);
Register slot_reg = WriteBarrierDescriptor::SlotAddressRegister();
__ leaq(slot_reg, FieldOperand(array, offset));
// TODO(leszeks): Add an interface for flushing all double registers
// before this Node, to avoid needing to save them here.
SaveFPRegsMode const save_fp_mode =
!node->register_snapshot().live_double_registers.is_empty()
? SaveFPRegsMode::kSave
: SaveFPRegsMode::kIgnore;
__ CallRecordWriteStub(array, slot_reg, save_fp_mode);
__ jmp(return_label);
},
value, array, this, FixedArray::OffsetOfElementAt(i));
__ StoreTaggedField(FieldOperand(array, FixedArray::OffsetOfElementAt(i)), __ StoreTaggedField(FieldOperand(array, FixedArray::OffsetOfElementAt(i)),
value); value);
__ JumpIfSmi(value, &deferred_write_barrier->return_label, Label::kNear);
// TODO(leszeks): This will stay either false or true throughout this loop.
// Consider hoisting the check out of the loop and duplicating the loop into
// with and without write barrier.
__ CheckPageFlag(array, kScratchRegister,
MemoryChunk::kPointersFromHereAreInterestingMask, not_zero,
&deferred_write_barrier->deferred_code_label);
__ bind(&deferred_write_barrier->return_label);
} }
Register context = // Use WriteBarrierDescriptor::SlotAddressRegister() as the scratch
FromAnyToRegister(code_gen_state, kScratchRegister, context_input()); // register, see comment above.
Register context = FromAnyToRegister(
code_gen_state, WriteBarrierDescriptor::SlotAddressRegister(),
context_input());
DeferredCodeInfo* deferred_context_write_barrier = PushDeferredCode(
code_gen_state,
[](MaglevCodeGenState* code_gen_state, Label* return_label,
Register context, Register generator, GeneratorStore* node) {
ASM_CODE_COMMENT_STRING(code_gen_state->masm(),
"Write barrier slow path");
// Use WriteBarrierDescriptor::SlotAddressRegister() as the scratch
// register, see comment above.
// TODO(leszeks): The context is almost always going to be in old-space,
// consider moving this check to the fast path, maybe even as the first
// bailout.
__ CheckPageFlag(
context, WriteBarrierDescriptor::SlotAddressRegister(),
MemoryChunk::kPointersToHereAreInterestingOrInSharedHeapMask, zero,
return_label);
__ Move(WriteBarrierDescriptor::ObjectRegister(), generator);
generator = WriteBarrierDescriptor::ObjectRegister();
Register slot_reg = WriteBarrierDescriptor::SlotAddressRegister();
__ leaq(slot_reg,
FieldOperand(generator, JSGeneratorObject::kContextOffset));
// TODO(leszeks): Add an interface for flushing all double registers
// before this Node, to avoid needing to save them here.
SaveFPRegsMode const save_fp_mode =
!node->register_snapshot().live_double_registers.is_empty()
? SaveFPRegsMode::kSave
: SaveFPRegsMode::kIgnore;
__ CallRecordWriteStub(generator, slot_reg, save_fp_mode);
__ jmp(return_label);
},
context, generator, this);
__ StoreTaggedField( __ StoreTaggedField(
FieldOperand(generator, JSGeneratorObject::kContextOffset), context); FieldOperand(generator, JSGeneratorObject::kContextOffset), context);
__ AssertNotSmi(context);
__ CheckPageFlag(generator, kScratchRegister,
MemoryChunk::kPointersFromHereAreInterestingMask, not_zero,
&deferred_context_write_barrier->deferred_code_label);
__ bind(&deferred_context_write_barrier->return_label);
__ StoreTaggedSignedField( __ StoreTaggedSignedField(
FieldOperand(generator, JSGeneratorObject::kContinuationOffset), FieldOperand(generator, JSGeneratorObject::kContinuationOffset),
Smi::FromInt(suspend_id())); Smi::FromInt(suspend_id()));
......
...@@ -1945,6 +1945,8 @@ class GeneratorStore : public NodeT<GeneratorStore> { ...@@ -1945,6 +1945,8 @@ class GeneratorStore : public NodeT<GeneratorStore> {
set_input(kGeneratorIndex, generator); set_input(kGeneratorIndex, generator);
} }
static constexpr OpProperties kProperties = OpProperties::DeferredCall();
int suspend_id() const { return suspend_id_; } int suspend_id() const { return suspend_id_; }
int bytecode_offset() const { return bytecode_offset_; } int bytecode_offset() const { return bytecode_offset_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment