[maglev] Unify BuildCall

... using a CallArguments class that abstract receiver and
interpreter register logic.

Bug: v8:7700
Change-Id: I06e3fed2700c0e1bde5e0802889e9c05ebc55257
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4003217
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84049}
This commit is contained in:
Victor Gomes 2022-11-03 16:42:58 +01:00 committed by V8 LUCI CQ
parent 10483f7a40
commit 7ab1dc6a9a
2 changed files with 175 additions and 137 deletions

View File

@ -2577,83 +2577,24 @@ void MaglevGraphBuilder::InlineCallFromRegisters(
->SetToBlockAndReturnNext(current_block_);
}
// TODO(v8:7700): Read feedback and implement inlining
void MaglevGraphBuilder::BuildCallFromRegisterList(
ConvertReceiverMode receiver_mode) {
ValueNode* function = LoadRegisterTagged(0);
interpreter::RegisterList args = iterator_.GetRegisterListOperand(1);
ValueNode* context = GetContext();
Call::TargetType target_type = Call::TargetType::kAny;
FeedbackSlot slot = GetSlotOperand(3);
compiler::FeedbackSource feedback_source(feedback(), slot);
const compiler::ProcessedFeedback& processed_feedback =
broker()->GetFeedbackForCall(feedback_source);
if (processed_feedback.kind() == compiler::ProcessedFeedback::kCall) {
const compiler::CallFeedback& call_feedback = processed_feedback.AsCall();
CallFeedbackContent content = call_feedback.call_feedback_content();
if (content == CallFeedbackContent::kTarget) {
base::Optional<compiler::HeapObjectRef> maybe_target =
call_feedback.target();
if (maybe_target.has_value()) {
compiler::HeapObjectRef target = maybe_target.value();
if (target.IsJSFunction()) {
// Reset the feedback source
feedback_source = compiler::FeedbackSource();
target_type = Call::TargetType::kJSFunction;
if (!function->Is<Constant>()) {
AddNewNode<CheckValue>({function}, target);
} else if (!function->Cast<Constant>()->object().equals(target)) {
EmitUnconditionalDeopt(DeoptimizeReason::kUnknown);
return;
}
}
}
}
}
size_t input_count = args.register_count() + Call::kFixedInputCount;
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
input_count++;
}
Call* call = CreateNewNode<Call>(input_count, receiver_mode, target_type,
feedback_source, function, context);
int arg_index = 0;
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
call->set_arg(arg_index++, GetRootConstant(RootIndex::kUndefinedValue));
}
for (int i = 0; i < args.register_count(); ++i) {
call->set_arg(arg_index++, GetTaggedValue(args[i]));
}
SetAccumulator(AddNode(call));
}
bool MaglevGraphBuilder::TryInlineBuiltin(base::Optional<int> receiver_index,
int first_arg_index, int argc_count,
Builtin builtin) {
bool MaglevGraphBuilder::TryInlineBuiltin(Builtin builtin,
const CallArguments& args) {
switch (builtin) {
case Builtin::kStringFromCharCode:
if (argc_count != 1) return false;
SetAccumulator(AddNewNode<BuiltinStringFromCharCode>(
{LoadRegisterInt32(first_arg_index)}));
if (args.count() != 1) return false;
SetAccumulator(
AddNewNode<BuiltinStringFromCharCode>({GetInt32(args[0])}));
return true;
case Builtin::kStringPrototypeCharCodeAt: {
// TODO(victorgomes): Not sure how this can happen!
// Maybe emit an eager deopt?
if (!receiver_index.has_value()) return false;
ValueNode* receiver = LoadRegisterTagged(*receiver_index);
case Builtin::kStringPrototypeCharCodeAt: {
ValueNode* receiver = GetTaggedReceiver(args);
ValueNode* index;
if (argc_count == 0) {
if (args.count() == 0) {
// Index is the undefined object.
// ToIntegerOrInfinity(undefined) = 0.
index = GetInt32Constant(0);
} else {
index = GetInt32ElementIndex(first_arg_index);
index = GetInt32ElementIndex(args[0]);
}
// Any other argument is ignored.
@ -2669,6 +2610,7 @@ bool MaglevGraphBuilder::TryInlineBuiltin(base::Optional<int> receiver_index,
AddNewNode<BuiltinStringPrototypeCharCodeAt>({receiver, index}));
return true;
}
default:
// TODO(v8:7700): Inline more builtins.
return false;
@ -2676,20 +2618,19 @@ bool MaglevGraphBuilder::TryInlineBuiltin(base::Optional<int> receiver_index,
}
ValueNode* MaglevGraphBuilder::GetConvertReceiver(
compiler::JSFunctionRef function, ConvertReceiverMode mode,
int operand_index) {
compiler::JSFunctionRef function, const CallArguments& args) {
compiler::SharedFunctionInfoRef shared = function.shared();
if (shared.native() || shared.language_mode() == LanguageMode::kStrict) {
if (mode == ConvertReceiverMode::kNullOrUndefined) {
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
return GetRootConstant(RootIndex::kUndefinedValue);
} else {
return LoadRegisterTagged(operand_index);
return GetTaggedValue(*args.receiver());
}
}
if (mode == ConvertReceiverMode::kNullOrUndefined) {
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
return GetConstant(function.native_context().global_proxy_object());
}
ValueNode* receiver = LoadRegisterTagged(operand_index);
ValueNode* receiver = GetTaggedValue(*args.receiver());
if (CheckType(receiver, NodeType::kJSReceiver)) return receiver;
if (Constant* constant = receiver->TryCast<Constant>()) {
const Handle<HeapObject> object = constant->object().object();
@ -2699,45 +2640,32 @@ ValueNode* MaglevGraphBuilder::GetConvertReceiver(
return constant;
}
}
return AddNewNode<ConvertReceiver>({receiver}, function, mode);
return AddNewNode<ConvertReceiver>({receiver}, function,
args.receiver_mode());
}
bool MaglevGraphBuilder::TryBuildCallKnownJSFunction(
compiler::JSFunctionRef function, int argc_count,
ConvertReceiverMode receiver_mode) {
compiler::JSFunctionRef function, const CallArguments& args) {
// Don't inline CallFunction stub across native contexts.
if (function.native_context() != broker()->target_native_context()) {
return false;
}
ValueNode* receiver = GetConvertReceiver(function, receiver_mode, 1);
size_t input_count = argc_count + CallKnownJSFunction::kFixedInputCount;
ValueNode* receiver = GetConvertReceiver(function, args);
size_t input_count = args.count() + CallKnownJSFunction::kFixedInputCount;
CallKnownJSFunction* call =
CreateNewNode<CallKnownJSFunction>(input_count, function, receiver);
const int first_arg_operand_index =
(receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
for (int i = 0; i < argc_count; i++) {
call->set_arg(i, LoadRegisterTagged(first_arg_operand_index + i + 1));
for (int i = 0; i < args.count(); i++) {
call->set_arg(i, GetTaggedValue(args[i]));
}
SetAccumulator(AddNode(call));
return true;
}
void MaglevGraphBuilder::BuildCallFromRegisters(
int argc_count, ConvertReceiverMode receiver_mode) {
// Indices and counts of operands on the bytecode.
const int kFirstArgumentOperandIndex = 1;
const int kReceiverOperandCount =
(receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
const int kReceiverAndArgOperandCount = kReceiverOperandCount + argc_count;
const int kSlotOperandIndex =
kFirstArgumentOperandIndex + kReceiverAndArgOperandCount;
DCHECK_LE(argc_count, 2);
ValueNode* target_node = LoadRegisterTagged(0);
void MaglevGraphBuilder::BuildCall(ValueNode* target_node,
const CallArguments& args,
compiler::FeedbackSource& feedback_source) {
ValueNode* context = GetContext();
Call::TargetType target_type = Call::TargetType::kAny;
FeedbackSlot slot = GetSlotOperand(kSlotOperandIndex);
compiler::FeedbackSource feedback_source(feedback(), slot);
const compiler::ProcessedFeedback& processed_feedback =
broker()->GetFeedbackForCall(feedback_source);
@ -2760,14 +2688,6 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
if (!target.IsJSFunction()) break;
compiler::JSFunctionRef function = target.AsJSFunction();
if (v8_flags.maglev_inlining) {
base::Optional<compiler::FeedbackVectorRef> maybe_feedback_vector =
function.feedback_vector(broker()->dependencies());
if (maybe_feedback_vector.has_value()) {
return InlineCallFromRegisters(argc_count, receiver_mode, function);
}
}
// Reset the feedback source
feedback_source = compiler::FeedbackSource();
target_type = Call::TargetType::kJSFunction;
@ -2788,18 +2708,12 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
DCHECK(function.object()->IsCallable());
if (function.shared().HasBuiltinId()) {
base::Optional<int> receiver_index =
(kReceiverOperandCount == 0 ? base::Optional<int>()
: kFirstArgumentOperandIndex);
int first_arg_not_receiver_index =
kReceiverOperandCount + kFirstArgumentOperandIndex;
if (TryInlineBuiltin(receiver_index, first_arg_not_receiver_index,
argc_count, function.shared().builtin_id())) {
if (TryInlineBuiltin(function.shared().builtin_id(), args)) {
return;
}
}
if (TryBuildCallKnownJSFunction(function, argc_count, receiver_mode)) {
if (TryBuildCallKnownJSFunction(function, args)) {
return;
}
break;
@ -2808,26 +2722,69 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
default:
break;
}
// On fallthrough, create a generic call.
int argc_count_with_recv = argc_count + 1;
size_t input_count = argc_count_with_recv + Call::kFixedInputCount;
int arg_index = 0;
int reg_count = argc_count_with_recv;
Call* call = CreateNewNode<Call>(input_count, receiver_mode, target_type,
size_t input_count = args.count_with_receiver() + Call::kFixedInputCount;
Call* call =
CreateNewNode<Call>(input_count, args.receiver_mode(), target_type,
feedback_source, target_node, context);
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
reg_count = argc_count;
call->set_arg(arg_index++, GetRootConstant(RootIndex::kUndefinedValue));
int arg_index = 0;
call->set_arg(arg_index++, GetTaggedReceiver(args));
for (int i = 0; i < args.count(); ++i) {
call->set_arg(arg_index++, GetTaggedValue(args[i]));
}
for (int i = 0; i < reg_count; i++) {
call->set_arg(arg_index++, LoadRegisterTagged(i + 1));
}
SetAccumulator(AddNode(call));
}
void MaglevGraphBuilder::BuildCallFromRegisterList(
ConvertReceiverMode receiver_mode) {
ValueNode* target = LoadRegisterTagged(0);
interpreter::RegisterList reg_list = iterator_.GetRegisterListOperand(1);
FeedbackSlot slot = GetSlotOperand(3);
compiler::FeedbackSource feedback_source(feedback(), slot);
CallArguments args(receiver_mode, reg_list);
BuildCall(target, args, feedback_source);
}
void MaglevGraphBuilder::BuildCallFromRegisters(
int arg_count, ConvertReceiverMode receiver_mode) {
ValueNode* target = LoadRegisterTagged(0);
int receiver_count =
(receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
int slot_operand_index = arg_count + receiver_count + 1;
FeedbackSlot slot = GetSlotOperand(slot_operand_index);
compiler::FeedbackSource feedback_source(feedback(), slot);
switch (arg_count + receiver_count) {
case 0: {
CallArguments args(receiver_mode, arg_count);
BuildCall(target, args, feedback_source);
break;
}
case 1: {
CallArguments args(receiver_mode, arg_count,
iterator_.GetRegisterOperand(1));
BuildCall(target, args, feedback_source);
break;
}
case 2: {
CallArguments args(receiver_mode, arg_count,
iterator_.GetRegisterOperand(1),
iterator_.GetRegisterOperand(2));
BuildCall(target, args, feedback_source);
break;
}
case 3: {
CallArguments args(
receiver_mode, arg_count, iterator_.GetRegisterOperand(1),
iterator_.GetRegisterOperand(2), iterator_.GetRegisterOperand(3));
BuildCall(target, args, feedback_source);
break;
}
default:
UNREACHABLE();
}
}
void MaglevGraphBuilder::VisitCallAnyReceiver() {
BuildCallFromRegisterList(ConvertReceiverMode::kAny);
}

View File

@ -980,19 +980,101 @@ class MaglevGraphBuilder {
}
}
bool TryInlineBuiltin(base::Optional<int> receiver_index, int first_arg_index,
int argc_count, Builtin builtin);
void InlineCallFromRegisters(int argc_count,
ConvertReceiverMode receiver_mode,
compiler::JSFunctionRef function);
ValueNode* GetConvertReceiver(compiler::JSFunctionRef function,
ConvertReceiverMode mode, int operand_index);
bool TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
int argc_count,
ConvertReceiverMode receiver_mode);
class CallArguments {
public:
enum Mode {
kFromRegisters,
kFromRegisterList,
};
CallArguments(ConvertReceiverMode receiver_mode, int argc,
interpreter::Register r0 = interpreter::Register(),
interpreter::Register r1 = interpreter::Register(),
interpreter::Register r2 = interpreter::Register())
: receiver_mode_(receiver_mode),
call_mode_(kFromRegisters),
argc_(argc) {
DCHECK_LT(argc, 3);
regs_[0] = r0;
regs_[1] = r1;
regs_[2] = r2;
}
CallArguments(ConvertReceiverMode receiver_mode,
interpreter::RegisterList reglist)
: receiver_mode_(receiver_mode),
call_mode_(kFromRegisterList),
reglist_(reglist) {}
base::Optional<interpreter::Register> receiver() const {
if (receiver_mode_ == ConvertReceiverMode::kNullOrUndefined) {
return {};
}
if (call_mode_ == kFromRegisters) {
return regs_[0];
}
return reglist_[0];
}
int count() const {
if (call_mode_ == kFromRegisters) {
return argc_;
}
if (receiver_mode_ == ConvertReceiverMode::kNullOrUndefined) {
return reglist_.register_count();
}
return reglist_.register_count() - 1;
}
int count_with_receiver() const { return count() + 1; }
const interpreter::Register operator[](size_t i) const {
if (receiver_mode_ != ConvertReceiverMode::kNullOrUndefined) {
i++;
}
if (call_mode_ == kFromRegisters) {
DCHECK_LT(i, argc_ + 1);
return regs_[i];
}
return reglist_[i];
}
ConvertReceiverMode receiver_mode() const { return receiver_mode_; }
private:
const ConvertReceiverMode receiver_mode_;
const Mode call_mode_;
union {
struct {
interpreter::Register regs_[3];
int argc_;
};
interpreter::RegisterList reglist_;
};
};
ValueNode* GetTaggedReceiver(const CallArguments& args) {
auto maybe_receiver = args.receiver();
if (maybe_receiver.has_value()) {
return GetTaggedValue(*maybe_receiver);
}
DCHECK_EQ(args.receiver_mode(), ConvertReceiverMode::kNullOrUndefined);
return GetRootConstant(RootIndex::kUndefinedValue);
}
ValueNode* GetConvertReceiver(compiler::JSFunctionRef function,
const CallArguments& args);
bool TryInlineBuiltin(Builtin builtin, const CallArguments& args);
bool TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
const CallArguments& args);
void BuildCall(ValueNode* target_node, const CallArguments& args,
compiler::FeedbackSource& feedback_source);
void BuildCallFromRegisterList(ConvertReceiverMode receiver_mode);
void BuildCallFromRegisters(int argc_count,
ConvertReceiverMode receiver_mode);
@ -1014,8 +1096,7 @@ class MaglevGraphBuilder {
void BuildCheckMaps(ValueNode* object,
ZoneVector<compiler::MapRef> const& maps);
ValueNode* GetInt32ElementIndex(int operand_index) {
interpreter::Register reg = iterator_.GetRegisterOperand(operand_index);
ValueNode* GetInt32ElementIndex(interpreter::Register reg) {
ValueNode* index_object = current_interpreter_frame_.get(reg);
return GetInt32ElementIndex(index_object);
}