From 0adb40efb62602e5545ea8f899039b79cdb11394 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Tue, 11 May 2021 11:50:47 +0200 Subject: [PATCH] [sparkplug] Introduce Compact Call Trampolines Argc and Slot are usually small and fit within a single 32bit word. This reduces most property calls by 5 bytes. This results in roughly 1% code reduction for sparkplug and no measurable regression on x64. Bug: v8:11420 Change-Id: I272c26c40b99f2dc5817f18bec113662a5bfebce Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2872828 Reviewed-by: Toon Verwaest Reviewed-by: Jakob Gruber Commit-Queue: Camillo Bruni Cr-Commit-Position: refs/heads/master@{#74505} --- src/baseline/baseline-compiler.cc | 33 ++++++++++-- src/builtins/builtins-call-gen.cc | 79 +++++++++++++++++++++-------- src/builtins/builtins-call-gen.h | 7 +++ src/builtins/builtins-definitions.h | 5 ++ src/codegen/interface-descriptors.h | 23 +++++++++ 5 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/baseline/baseline-compiler.cc b/src/baseline/baseline-compiler.cc index 147416e311..9c6e3f10e6 100644 --- a/src/baseline/baseline-compiler.cc +++ b/src/baseline/baseline-compiler.cc @@ -1121,6 +1121,20 @@ void BaselineCompiler::VisitGetSuperConstructor() { } namespace { +constexpr Builtins::Name ConvertReceiverModeToCompactBuiltin( + ConvertReceiverMode mode) { + switch (mode) { + case ConvertReceiverMode::kAny: + return Builtins::kCall_ReceiverIsAny_Baseline_Compact; + break; + case ConvertReceiverMode::kNullOrUndefined: + return Builtins::kCall_ReceiverIsNullOrUndefined_Baseline_Compact; + break; + case ConvertReceiverMode::kNotNullOrUndefined: + return Builtins::kCall_ReceiverIsNotNullOrUndefined_Baseline_Compact; + break; + } +} constexpr Builtins::Name ConvertReceiverModeToBuiltin( ConvertReceiverMode mode) { switch (mode) { @@ -1140,11 +1154,20 @@ constexpr Builtins::Name ConvertReceiverModeToBuiltin( template void BaselineCompiler::BuildCall(uint32_t slot, uint32_t arg_count, Args... args) { - CallBuiltin( - RegisterOperand(0), // kFunction - arg_count, // kActualArgumentsCount - slot, // kSlot - args...); // Arguments + uint32_t bitfield; + if (CallTrampoline_Baseline_CompactDescriptor::EncodeBitField(arg_count, slot, + &bitfield)) { + CallBuiltin( + RegisterOperand(0), // kFunction + bitfield, // kActualArgumentsCount | kSlot + args...); // Arguments + } else { + CallBuiltin( + RegisterOperand(0), // kFunction + arg_count, // kActualArgumentsCount + slot, // kSlot + args...); // Arguments + } } void BaselineCompiler::VisitCallAnyReceiver() { diff --git a/src/builtins/builtins-call-gen.cc b/src/builtins/builtins-call-gen.cc index 62ed9e291a..fda3e98319 100644 --- a/src/builtins/builtins-call-gen.cc +++ b/src/builtins/builtins-call-gen.cc @@ -64,43 +64,45 @@ void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) { masm->isolate()->builtins()->CallFunction()); } +// TODO(cbruni): Try reusing code between builtin versions to avoid binary +// overhead. +TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline_Compact, + CallOrConstructBuiltinsAssembler) { + auto receiver = UndefinedConstant(); + CallReceiver(Builtins::kCall_ReceiverIsNullOrUndefined, receiver); +} + TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline, CallOrConstructBuiltinsAssembler) { - auto target = Parameter(Descriptor::kFunction); auto argc = UncheckedParameter(Descriptor::kActualArgumentsCount); - auto context = LoadContextFromBaseline(); - auto feedback_vector = LoadFeedbackVectorFromBaseline(); auto slot = UncheckedParameter(Descriptor::kSlot); auto receiver = UndefinedConstant(); - CollectCallFeedback(target, receiver, context, feedback_vector, slot); - TailCallBuiltin(Builtins::kCall_ReceiverIsNullOrUndefined, context, target, - argc); + CallReceiver(Builtins::kCall_ReceiverIsNullOrUndefined, argc, + slot, receiver); +} + +TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact, + CallOrConstructBuiltinsAssembler) { + CallReceiver(Builtins::kCall_ReceiverIsNotNullOrUndefined); } TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline, CallOrConstructBuiltinsAssembler) { - auto target = Parameter(Descriptor::kFunction); auto argc = UncheckedParameter(Descriptor::kActualArgumentsCount); - auto context = LoadContextFromBaseline(); - auto feedback_vector = LoadFeedbackVectorFromBaseline(); auto slot = UncheckedParameter(Descriptor::kSlot); - CodeStubArguments args(this, argc); - auto receiver = args.GetReceiver(); - CollectCallFeedback(target, receiver, context, feedback_vector, slot); - TailCallBuiltin(Builtins::kCall_ReceiverIsNotNullOrUndefined, context, target, - argc); + CallReceiver(Builtins::kCall_ReceiverIsNotNullOrUndefined, argc, + slot); +} + +TF_BUILTIN(Call_ReceiverIsAny_Baseline_Compact, + CallOrConstructBuiltinsAssembler) { + CallReceiver(Builtins::kCall_ReceiverIsAny); } TF_BUILTIN(Call_ReceiverIsAny_Baseline, CallOrConstructBuiltinsAssembler) { - auto target = Parameter(Descriptor::kFunction); auto argc = UncheckedParameter(Descriptor::kActualArgumentsCount); - auto context = LoadContextFromBaseline(); - auto feedback_vector = LoadFeedbackVectorFromBaseline(); auto slot = UncheckedParameter(Descriptor::kSlot); - CodeStubArguments args(this, argc); - auto receiver = args.GetReceiver(); - CollectCallFeedback(target, receiver, context, feedback_vector, slot); - TailCallBuiltin(Builtins::kCall_ReceiverIsAny, context, target, argc); + CallReceiver(Builtins::kCall_ReceiverIsAny, argc, slot); } TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback, @@ -457,6 +459,41 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread( } } +template +void CallOrConstructBuiltinsAssembler::CallReceiver( + Builtins::Name id, base::Optional> receiver) { + static_assert(std::is_same::value, + "Incompatible Descriptor"); + auto bitfield = UncheckedParameter(Descriptor::kBitField); + TNode argc = + Signed(DecodeWord32< + CallTrampoline_Baseline_CompactDescriptor::ArgumentCountField>( + bitfield)); + TNode slot = ChangeUint32ToWord( + DecodeWord32( + bitfield)); + CallReceiver(id, argc, slot, receiver); +} + +template +void CallOrConstructBuiltinsAssembler::CallReceiver( + Builtins::Name id, TNode argc, TNode slot, + base::Optional> maybe_receiver) { + auto target = Parameter(Descriptor::kFunction); + auto context = LoadContextFromBaseline(); + auto feedback_vector = LoadFeedbackVectorFromBaseline(); + TNode receiver; + if (maybe_receiver) { + receiver = *maybe_receiver; + } else { + CodeStubArguments args(this, argc); + receiver = args.GetReceiver(); + } + CollectCallFeedback(target, receiver, context, feedback_vector, slot); + TailCallBuiltin(id, context, target, argc); +} + TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) { auto target = Parameter(Descriptor::kTarget); base::Optional> new_target = base::nullopt; diff --git a/src/builtins/builtins-call-gen.h b/src/builtins/builtins-call-gen.h index c938662d5e..ff4d998ff3 100644 --- a/src/builtins/builtins-call-gen.h +++ b/src/builtins/builtins-call-gen.h @@ -30,6 +30,13 @@ class CallOrConstructBuiltinsAssembler : public CodeStubAssembler { TNode spread, TNode args_count, TNode context); + template + void CallReceiver(Builtins::Name id, + base::Optional> = base::nullopt); + template + void CallReceiver(Builtins::Name id, TNode argc, TNode slot, + base::Optional> = base::nullopt); + enum class CallFunctionTemplateMode : uint8_t { kCheckAccess, kCheckCompatibleReceiver, diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 7cb9459e4e..78255a30e9 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -50,8 +50,13 @@ namespace internal { ASM(Call_ReceiverIsNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsNotNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsAny, CallTrampoline) \ + TFC(Call_ReceiverIsNullOrUndefined_Baseline_Compact, \ + CallTrampoline_Baseline_Compact) \ TFC(Call_ReceiverIsNullOrUndefined_Baseline, CallTrampoline_Baseline) \ + TFC(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact, \ + CallTrampoline_Baseline_Compact) \ TFC(Call_ReceiverIsNotNullOrUndefined_Baseline, CallTrampoline_Baseline) \ + TFC(Call_ReceiverIsAny_Baseline_Compact, CallTrampoline_Baseline_Compact) \ TFC(Call_ReceiverIsAny_Baseline, CallTrampoline_Baseline) \ TFC(Call_ReceiverIsNullOrUndefined_WithFeedback, \ CallTrampoline_WithFeedback) \ diff --git a/src/codegen/interface-descriptors.h b/src/codegen/interface-descriptors.h index d22eb7dd42..e64826e6fc 100644 --- a/src/codegen/interface-descriptors.h +++ b/src/codegen/interface-descriptors.h @@ -40,6 +40,7 @@ namespace internal { V(CallFunctionTemplate) \ V(CallTrampoline) \ V(CallTrampoline_Baseline) \ + V(CallTrampoline_Baseline_Compact) \ V(CallTrampoline_WithFeedback) \ V(CallVarargs) \ V(CallWithArrayLike) \ @@ -1841,6 +1842,28 @@ class BinaryOp_WithFeedbackDescriptor DECLARE_DESCRIPTOR(BinaryOp_WithFeedbackDescriptor) }; +class CallTrampoline_Baseline_CompactDescriptor + : public StaticCallInterfaceDescriptor< + CallTrampoline_Baseline_CompactDescriptor> { + public: + using ArgumentCountField = base::BitField; + using SlotField = base::BitField; + + static bool EncodeBitField(uint32_t argc, uintptr_t slot, uint32_t* out) { + if (ArgumentCountField::is_valid(argc) && SlotField::is_valid(slot)) { + *out = ArgumentCountField::encode(argc) | SlotField::encode(slot); + return true; + } + return false; + } + + DEFINE_PARAMETERS_NO_CONTEXT_VARARGS(kFunction, kBitField) + DEFINE_PARAMETER_TYPES( + MachineType::AnyTagged(), // kFunction + MachineType::Uint32()) // kBitField = ArgumentCountField | SlotField + DECLARE_DESCRIPTOR(CallTrampoline_Baseline_CompactDescriptor) +}; + class CallTrampoline_BaselineDescriptor : public StaticCallInterfaceDescriptor { public: