From 03a98347b3a58618e4ff59ae71de164b6c4183df Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Tue, 6 Apr 2021 19:46:43 +0200 Subject: [PATCH] [sparkplug] Create separate builtins for suspend and resume generators Change-Id: Ibe7d571ee057eb9229d74922f94b9791be953b08 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2786845 Commit-Queue: Camillo Bruni Reviewed-by: Igor Sheludko Cr-Commit-Position: refs/heads/master@{#73844} --- src/baseline/baseline-compiler.cc | 63 +++----------- src/builtins/builtins-definitions.h | 2 + src/builtins/builtins-generator-gen.cc | 109 +++++++++++++++++++++++++ src/codegen/interface-descriptors.cc | 10 +++ src/codegen/interface-descriptors.h | 27 ++++++ 5 files changed, 158 insertions(+), 53 deletions(-) diff --git a/src/baseline/baseline-compiler.cc b/src/baseline/baseline-compiler.cc index 77e2ee486e..3d599c11fd 100644 --- a/src/baseline/baseline-compiler.cc +++ b/src/baseline/baseline-compiler.cc @@ -2227,72 +2227,29 @@ void BaselineCompiler::VisitSwitchOnGeneratorState() { void BaselineCompiler::VisitSuspendGenerator() { DCHECK_EQ(iterator().GetRegisterOperand(1), interpreter::Register(0)); - int register_count = RegisterCount(2); - uint32_t suspend_id = Uint(3); - BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_); Register generator_object = scratch_scope.AcquireScratch(); - Register parameters_and_registers_array = scratch_scope.AcquireScratch(); - Register value = scratch_scope.AcquireScratch(); - LoadRegister(generator_object, 0); - __ LoadTaggedPointerField(parameters_and_registers_array, generator_object, - JSGeneratorObject::kParametersAndRegistersOffset); + { + SaveAccumulatorScope accumulator_scope(&basm_); - int formal_parameter_count = - shared_function_info_->internal_formal_parameter_count(); - for (int i = 0; i < formal_parameter_count; ++i) { - __ LoadRegister(value, interpreter::Register::FromParameterIndex( - i + 1, bytecode_->parameter_count())); - __ StoreTaggedFieldWithWriteBarrier(parameters_and_registers_array, - FixedArray::OffsetOfElementAt(i), - value); + int bytecode_offset = + BytecodeArray::kHeaderSize + iterator().current_offset(); + CallBuiltin(Builtins::kSuspendGeneratorBaseline, generator_object, + static_cast(Uint(3)), // suspend_id + bytecode_offset, + static_cast(RegisterCount(2))); // register_count } - for (int i = 0; i < register_count; ++i) { - __ LoadRegister(value, interpreter::Register(i)); - __ StoreTaggedFieldWithWriteBarrier( - parameters_and_registers_array, - FixedArray::OffsetOfElementAt(formal_parameter_count + i), value); - } - - __ LoadContext(value); - __ StoreTaggedFieldWithWriteBarrier(generator_object, - JSGeneratorObject::kContextOffset, value); - - __ StoreTaggedSignedField(generator_object, - JSGeneratorObject::kContinuationOffset, - Smi::FromInt(suspend_id)); - - __ StoreTaggedSignedField( - generator_object, JSGeneratorObject::kInputOrDebugPosOffset, - Smi::FromInt(BytecodeArray::kHeaderSize + iterator().current_offset())); VisitReturn(); } void BaselineCompiler::VisitResumeGenerator() { DCHECK_EQ(iterator().GetRegisterOperand(1), interpreter::Register(0)); - int register_count = RegisterCount(2); - BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_); Register generator_object = scratch_scope.AcquireScratch(); - Register parameters_and_registers_array = scratch_scope.AcquireScratch(); - Register value = scratch_scope.AcquireScratch(); - LoadRegister(generator_object, 0); - __ LoadTaggedPointerField(parameters_and_registers_array, generator_object, - JSGeneratorObject::kParametersAndRegistersOffset); - - int formal_parameter_count = - shared_function_info_->internal_formal_parameter_count(); - for (int i = 0; i < register_count; ++i) { - __ LoadTaggedAnyField( - value, parameters_and_registers_array, - FixedArray::OffsetOfElementAt(formal_parameter_count + i)); - __ StoreRegister(interpreter::Register(i), value); - } - - __ LoadTaggedAnyField(kInterpreterAccumulatorRegister, generator_object, - JSGeneratorObject::kInputOrDebugPosOffset); + CallBuiltin(Builtins::kResumeGeneratorBaseline, generator_object, + static_cast(RegisterCount(2))); // register_count } void BaselineCompiler::VisitGetIterator() { diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index a3096ad7e2..b0e608418e 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -533,6 +533,8 @@ namespace internal { /* ES6 #sec-generator.prototype.throw */ \ TFJ(GeneratorPrototypeThrow, kDontAdaptArgumentsSentinel) \ CPP(AsyncFunctionConstructor) \ + TFC(SuspendGeneratorBaseline, SuspendGeneratorBaseline) \ + TFC(ResumeGeneratorBaseline, ResumeGeneratorBaseline) \ \ /* Iterator Protocol */ \ TFC(GetIteratorWithFeedbackLazyDeoptContinuation, GetIteratorStackParameter) \ diff --git a/src/builtins/builtins-generator-gen.cc b/src/builtins/builtins-generator-gen.cc index d93ab2e103..2e9d7e24e4 100644 --- a/src/builtins/builtins-generator-gen.cc +++ b/src/builtins/builtins-generator-gen.cc @@ -202,5 +202,114 @@ TF_BUILTIN(GeneratorPrototypeThrow, GeneratorBuiltinsAssembler) { "[Generator].prototype.throw"); } +// TODO(cbruni): Merge with corresponding bytecode handler. +TF_BUILTIN(SuspendGeneratorBaseline, GeneratorBuiltinsAssembler) { + auto generator = Parameter(Descriptor::kGeneratorObject); + auto context = Parameter(Descriptor::kContext); + StoreJSGeneratorObjectContext(generator, context); + auto suspend_id = SmiTag(UncheckedParameter(Descriptor::kSuspendId)); + StoreJSGeneratorObjectContinuation(generator, suspend_id); + // Store the bytecode offset in the [input_or_debug_pos] field, to be used by + // the inspector. + auto bytecode_offset = + SmiTag(UncheckedParameter(Descriptor::kBytecodeOffset)); + // Avoid the write barrier by using the generic helper. + StoreObjectFieldNoWriteBarrier( + generator, JSGeneratorObject::kInputOrDebugPosOffset, bytecode_offset); + + TNode closure = LoadJSGeneratorObjectFunction(generator); + auto sfi = LoadJSFunctionSharedFunctionInfo(closure); + TNode formal_parameter_count = Signed( + ChangeUint32ToWord(LoadSharedFunctionInfoFormalParameterCount(sfi))); + CSA_ASSERT(this, Word32BinaryNot(IntPtrEqual( + formal_parameter_count, + IntPtrConstant(kDontAdaptArgumentsSentinel)))); + + TNode parameters_and_registers = + LoadJSGeneratorObjectParametersAndRegisters(generator); + auto parameters_and_registers_length = + SmiUntag(LoadFixedArrayBaseLength(parameters_and_registers)); + + // Copy over the function parameters + auto parameter_base_index = IntPtrConstant( + interpreter::Register::FromParameterIndex(0, 1).ToOperand() + 1); + CSA_CHECK(this, UintPtrLessThan(formal_parameter_count, + parameters_and_registers_length)); + auto parent_frame_pointer = LoadParentFramePointer(); + BuildFastLoop( + IntPtrConstant(0), formal_parameter_count, + [=](TNode index) { + auto reg_index = IntPtrAdd(parameter_base_index, index); + TNode value = LoadFullTagged(parent_frame_pointer, + TimesSystemPointerSize(reg_index)); + UnsafeStoreFixedArrayElement(parameters_and_registers, index, value); + }, + 1, IndexAdvanceMode::kPost); + + // Iterate over register file and write values into array. + // The mapping of register to array index must match that used in + // BytecodeGraphBuilder::VisitResumeGenerator. + auto register_base_index = + IntPtrAdd(formal_parameter_count, + IntPtrConstant(interpreter::Register(0).ToOperand())); + auto register_count = UncheckedParameter(Descriptor::kRegisterCount); + auto end_index = IntPtrAdd(formal_parameter_count, register_count); + CSA_CHECK(this, UintPtrLessThan(end_index, parameters_and_registers_length)); + BuildFastLoop( + formal_parameter_count, end_index, + [=](TNode index) { + auto reg_index = IntPtrSub(register_base_index, index); + TNode value = LoadFullTagged(parent_frame_pointer, + TimesSystemPointerSize(reg_index)); + UnsafeStoreFixedArrayElement(parameters_and_registers, index, value); + }, + 1, IndexAdvanceMode::kPost); + + // The return value is unused, defaulting to undefined. + Return(UndefinedConstant()); +} + +// TODO(cbruni): Merge with corresponding bytecode handler. +TF_BUILTIN(ResumeGeneratorBaseline, GeneratorBuiltinsAssembler) { + auto generator = Parameter(Descriptor::kGeneratorObject); + TNode closure = LoadJSGeneratorObjectFunction(generator); + auto sfi = LoadJSFunctionSharedFunctionInfo(closure); + TNode formal_parameter_count = Signed( + ChangeUint32ToWord(LoadSharedFunctionInfoFormalParameterCount(sfi))); + CSA_ASSERT(this, Word32BinaryNot(IntPtrEqual( + formal_parameter_count, + IntPtrConstant(kDontAdaptArgumentsSentinel)))); + + TNode parameters_and_registers = + LoadJSGeneratorObjectParametersAndRegisters(generator); + + // Iterate over array and write values into register file. Also erase the + // array contents to not keep them alive artificially. + auto register_base_index = + IntPtrAdd(formal_parameter_count, + IntPtrConstant(interpreter::Register(0).ToOperand())); + auto register_count = UncheckedParameter(Descriptor::kRegisterCount); + auto end_index = IntPtrAdd(formal_parameter_count, register_count); + auto parameters_and_registers_length = + SmiUntag(LoadFixedArrayBaseLength(parameters_and_registers)); + CSA_CHECK(this, UintPtrLessThan(end_index, parameters_and_registers_length)); + auto parent_frame_pointer = LoadParentFramePointer(); + BuildFastLoop( + formal_parameter_count, end_index, + [=](TNode index) { + TNode value = + UnsafeLoadFixedArrayElement(parameters_and_registers, index); + auto reg_index = IntPtrSub(register_base_index, index); + StoreFullTaggedNoWriteBarrier(parent_frame_pointer, + TimesSystemPointerSize(reg_index), value); + UnsafeStoreFixedArrayElement(parameters_and_registers, index, + StaleRegisterConstant(), + SKIP_WRITE_BARRIER); + }, + 1, IndexAdvanceMode::kPost); + + Return(LoadJSGeneratorObjectInputOrDebugPos(generator)); +} + } // namespace internal } // namespace v8 diff --git a/src/codegen/interface-descriptors.cc b/src/codegen/interface-descriptors.cc index d8411d878f..53b678580e 100644 --- a/src/codegen/interface-descriptors.cc +++ b/src/codegen/interface-descriptors.cc @@ -618,5 +618,15 @@ void ForInPrepareDescriptor::InitializePlatformSpecific( DefaultInitializePlatformSpecific(data, kParameterCount); } +void SuspendGeneratorBaselineDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + DefaultInitializePlatformSpecific(data, kParameterCount); +} + +void ResumeGeneratorBaselineDescriptor::InitializePlatformSpecific( + CallInterfaceDescriptorData* data) { + DefaultInitializePlatformSpecific(data, kParameterCount); +} + } // namespace internal } // namespace v8 diff --git a/src/codegen/interface-descriptors.h b/src/codegen/interface-descriptors.h index 7d26511cf8..8d03907efc 100644 --- a/src/codegen/interface-descriptors.h +++ b/src/codegen/interface-descriptors.h @@ -97,6 +97,8 @@ namespace internal { V(NoContext) \ V(RecordWrite) \ V(ResumeGenerator) \ + V(SuspendGeneratorBaseline) \ + V(ResumeGeneratorBaseline) \ V(RunMicrotasks) \ V(RunMicrotasksEntry) \ V(SingleParameterOnStack) \ @@ -1587,6 +1589,31 @@ class ResumeGeneratorDescriptor final : public CallInterfaceDescriptor { DECLARE_DESCRIPTOR(ResumeGeneratorDescriptor, CallInterfaceDescriptor) }; +class ResumeGeneratorBaselineDescriptor final : public CallInterfaceDescriptor { + public: + DEFINE_PARAMETERS(kGeneratorObject, kRegisterCount) + DEFINE_RESULT_AND_PARAMETER_TYPES( + MachineType::TaggedSigned(), // return type + MachineType::AnyTagged(), // kGeneratorObject + MachineType::IntPtr(), // kRegisterCount + ) + DECLARE_DESCRIPTOR(ResumeGeneratorBaselineDescriptor, CallInterfaceDescriptor) +}; + +class SuspendGeneratorBaselineDescriptor final + : public CallInterfaceDescriptor { + public: + DEFINE_PARAMETERS(kGeneratorObject, kSuspendId, kBytecodeOffset, + kRegisterCount) + DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kGeneratorObject + MachineType::IntPtr(), // kSuspendId + MachineType::IntPtr(), // kBytecodeOffset + MachineType::IntPtr(), // kRegisterCount + ) + DECLARE_DESCRIPTOR(SuspendGeneratorBaselineDescriptor, + CallInterfaceDescriptor) +}; + class FrameDropperTrampolineDescriptor final : public CallInterfaceDescriptor { public: DEFINE_PARAMETERS(kRestartFp)