Commit 0adb40ef authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[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/+/2872828Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74505}
parent 9153bc38
......@@ -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 <ConvertReceiverMode kMode, typename... Args>
void BaselineCompiler::BuildCall(uint32_t slot, uint32_t arg_count,
Args... args) {
uint32_t bitfield;
if (CallTrampoline_Baseline_CompactDescriptor::EncodeBitField(arg_count, slot,
&bitfield)) {
CallBuiltin<ConvertReceiverModeToCompactBuiltin(kMode)>(
RegisterOperand(0), // kFunction
bitfield, // kActualArgumentsCount | kSlot
args...); // Arguments
} else {
CallBuiltin<ConvertReceiverModeToBuiltin(kMode)>(
RegisterOperand(0), // kFunction
arg_count, // kActualArgumentsCount
slot, // kSlot
args...); // Arguments
}
}
void BaselineCompiler::VisitCallAnyReceiver() {
......
......@@ -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<Descriptor>(Builtins::kCall_ReceiverIsNullOrUndefined, receiver);
}
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline,
CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
auto receiver = UndefinedConstant();
CollectCallFeedback(target, receiver, context, feedback_vector, slot);
TailCallBuiltin(Builtins::kCall_ReceiverIsNullOrUndefined, context, target,
argc);
CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsNullOrUndefined, argc,
slot, receiver);
}
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact,
CallOrConstructBuiltinsAssembler) {
CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsNotNullOrUndefined);
}
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline,
CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(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<Descriptor>(Builtins::kCall_ReceiverIsNotNullOrUndefined, argc,
slot);
}
TF_BUILTIN(Call_ReceiverIsAny_Baseline_Compact,
CallOrConstructBuiltinsAssembler) {
CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsAny);
}
TF_BUILTIN(Call_ReceiverIsAny_Baseline, CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(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<Descriptor>(Builtins::kCall_ReceiverIsAny, argc, slot);
}
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback,
......@@ -457,6 +459,41 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
}
}
template <class Descriptor>
void CallOrConstructBuiltinsAssembler::CallReceiver(
Builtins::Name id, base::Optional<TNode<Object>> receiver) {
static_assert(std::is_same<Descriptor,
CallTrampoline_Baseline_CompactDescriptor>::value,
"Incompatible Descriptor");
auto bitfield = UncheckedParameter<Word32T>(Descriptor::kBitField);
TNode<Int32T> argc =
Signed(DecodeWord32<
CallTrampoline_Baseline_CompactDescriptor::ArgumentCountField>(
bitfield));
TNode<UintPtrT> slot = ChangeUint32ToWord(
DecodeWord32<CallTrampoline_Baseline_CompactDescriptor::SlotField>(
bitfield));
CallReceiver<Descriptor>(id, argc, slot, receiver);
}
template <class Descriptor>
void CallOrConstructBuiltinsAssembler::CallReceiver(
Builtins::Name id, TNode<Int32T> argc, TNode<UintPtrT> slot,
base::Optional<TNode<Object>> maybe_receiver) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
TNode<Object> 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<Object>(Descriptor::kTarget);
base::Optional<TNode<Object>> new_target = base::nullopt;
......
......@@ -30,6 +30,13 @@ class CallOrConstructBuiltinsAssembler : public CodeStubAssembler {
TNode<Object> spread, TNode<Int32T> args_count,
TNode<Context> context);
template <class Descriptor>
void CallReceiver(Builtins::Name id,
base::Optional<TNode<Object>> = base::nullopt);
template <class Descriptor>
void CallReceiver(Builtins::Name id, TNode<Int32T> argc, TNode<UintPtrT> slot,
base::Optional<TNode<Object>> = base::nullopt);
enum class CallFunctionTemplateMode : uint8_t {
kCheckAccess,
kCheckCompatibleReceiver,
......
......@@ -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) \
......
......@@ -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<uint32_t, 0, 8>;
using SlotField = base::BitField<uintptr_t, 8, 24>;
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<CallTrampoline_BaselineDescriptor> {
public:
......
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