[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 <verwaest@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#74505}
This commit is contained in:
parent
9153bc385c
commit
0adb40efb6
@ -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) {
|
||||
CallBuiltin<ConvertReceiverModeToBuiltin(kMode)>(
|
||||
RegisterOperand(0), // kFunction
|
||||
arg_count, // kActualArgumentsCount
|
||||
slot, // kSlot
|
||||
args...); // Arguments
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user