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() { ...@@ -1121,6 +1121,20 @@ void BaselineCompiler::VisitGetSuperConstructor() {
} }
namespace { 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( constexpr Builtins::Name ConvertReceiverModeToBuiltin(
ConvertReceiverMode mode) { ConvertReceiverMode mode) {
switch (mode) { switch (mode) {
...@@ -1140,11 +1154,20 @@ constexpr Builtins::Name ConvertReceiverModeToBuiltin( ...@@ -1140,11 +1154,20 @@ constexpr Builtins::Name ConvertReceiverModeToBuiltin(
template <ConvertReceiverMode kMode, typename... Args> template <ConvertReceiverMode kMode, typename... Args>
void BaselineCompiler::BuildCall(uint32_t slot, uint32_t arg_count, void BaselineCompiler::BuildCall(uint32_t slot, uint32_t arg_count,
Args... args) { 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)>( CallBuiltin<ConvertReceiverModeToBuiltin(kMode)>(
RegisterOperand(0), // kFunction RegisterOperand(0), // kFunction
arg_count, // kActualArgumentsCount arg_count, // kActualArgumentsCount
slot, // kSlot slot, // kSlot
args...); // Arguments args...); // Arguments
}
} }
void BaselineCompiler::VisitCallAnyReceiver() { void BaselineCompiler::VisitCallAnyReceiver() {
......
...@@ -64,43 +64,45 @@ void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) { ...@@ -64,43 +64,45 @@ void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
masm->isolate()->builtins()->CallFunction()); 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, TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline,
CallOrConstructBuiltinsAssembler) { CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot); auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
auto receiver = UndefinedConstant(); auto receiver = UndefinedConstant();
CollectCallFeedback(target, receiver, context, feedback_vector, slot); CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsNullOrUndefined, argc,
TailCallBuiltin(Builtins::kCall_ReceiverIsNullOrUndefined, context, target, slot, receiver);
argc); }
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact,
CallOrConstructBuiltinsAssembler) {
CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsNotNullOrUndefined);
} }
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline, TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline,
CallOrConstructBuiltinsAssembler) { CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot); auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
CodeStubArguments args(this, argc); CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsNotNullOrUndefined, argc,
auto receiver = args.GetReceiver(); slot);
CollectCallFeedback(target, receiver, context, feedback_vector, slot); }
TailCallBuiltin(Builtins::kCall_ReceiverIsNotNullOrUndefined, context, target,
argc); TF_BUILTIN(Call_ReceiverIsAny_Baseline_Compact,
CallOrConstructBuiltinsAssembler) {
CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsAny);
} }
TF_BUILTIN(Call_ReceiverIsAny_Baseline, CallOrConstructBuiltinsAssembler) { TF_BUILTIN(Call_ReceiverIsAny_Baseline, CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kFunction);
auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
auto context = LoadContextFromBaseline();
auto feedback_vector = LoadFeedbackVectorFromBaseline();
auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot); auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
CodeStubArguments args(this, argc); CallReceiver<Descriptor>(Builtins::kCall_ReceiverIsAny, argc, slot);
auto receiver = args.GetReceiver();
CollectCallFeedback(target, receiver, context, feedback_vector, slot);
TailCallBuiltin(Builtins::kCall_ReceiverIsAny, context, target, argc);
} }
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback, TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback,
...@@ -457,6 +459,41 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread( ...@@ -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) { TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) {
auto target = Parameter<Object>(Descriptor::kTarget); auto target = Parameter<Object>(Descriptor::kTarget);
base::Optional<TNode<Object>> new_target = base::nullopt; base::Optional<TNode<Object>> new_target = base::nullopt;
......
...@@ -30,6 +30,13 @@ class CallOrConstructBuiltinsAssembler : public CodeStubAssembler { ...@@ -30,6 +30,13 @@ class CallOrConstructBuiltinsAssembler : public CodeStubAssembler {
TNode<Object> spread, TNode<Int32T> args_count, TNode<Object> spread, TNode<Int32T> args_count,
TNode<Context> context); 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 { enum class CallFunctionTemplateMode : uint8_t {
kCheckAccess, kCheckAccess,
kCheckCompatibleReceiver, kCheckCompatibleReceiver,
......
...@@ -50,8 +50,13 @@ namespace internal { ...@@ -50,8 +50,13 @@ namespace internal {
ASM(Call_ReceiverIsNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsNullOrUndefined, CallTrampoline) \
ASM(Call_ReceiverIsNotNullOrUndefined, CallTrampoline) \ ASM(Call_ReceiverIsNotNullOrUndefined, CallTrampoline) \
ASM(Call_ReceiverIsAny, CallTrampoline) \ ASM(Call_ReceiverIsAny, CallTrampoline) \
TFC(Call_ReceiverIsNullOrUndefined_Baseline_Compact, \
CallTrampoline_Baseline_Compact) \
TFC(Call_ReceiverIsNullOrUndefined_Baseline, CallTrampoline_Baseline) \ TFC(Call_ReceiverIsNullOrUndefined_Baseline, CallTrampoline_Baseline) \
TFC(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact, \
CallTrampoline_Baseline_Compact) \
TFC(Call_ReceiverIsNotNullOrUndefined_Baseline, CallTrampoline_Baseline) \ TFC(Call_ReceiverIsNotNullOrUndefined_Baseline, CallTrampoline_Baseline) \
TFC(Call_ReceiverIsAny_Baseline_Compact, CallTrampoline_Baseline_Compact) \
TFC(Call_ReceiverIsAny_Baseline, CallTrampoline_Baseline) \ TFC(Call_ReceiverIsAny_Baseline, CallTrampoline_Baseline) \
TFC(Call_ReceiverIsNullOrUndefined_WithFeedback, \ TFC(Call_ReceiverIsNullOrUndefined_WithFeedback, \
CallTrampoline_WithFeedback) \ CallTrampoline_WithFeedback) \
......
...@@ -40,6 +40,7 @@ namespace internal { ...@@ -40,6 +40,7 @@ namespace internal {
V(CallFunctionTemplate) \ V(CallFunctionTemplate) \
V(CallTrampoline) \ V(CallTrampoline) \
V(CallTrampoline_Baseline) \ V(CallTrampoline_Baseline) \
V(CallTrampoline_Baseline_Compact) \
V(CallTrampoline_WithFeedback) \ V(CallTrampoline_WithFeedback) \
V(CallVarargs) \ V(CallVarargs) \
V(CallWithArrayLike) \ V(CallWithArrayLike) \
...@@ -1841,6 +1842,28 @@ class BinaryOp_WithFeedbackDescriptor ...@@ -1841,6 +1842,28 @@ class BinaryOp_WithFeedbackDescriptor
DECLARE_DESCRIPTOR(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 class CallTrampoline_BaselineDescriptor
: public StaticCallInterfaceDescriptor<CallTrampoline_BaselineDescriptor> { : public StaticCallInterfaceDescriptor<CallTrampoline_BaselineDescriptor> {
public: 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