Revert "[maglev] Unify call building functions"

This reverts commit 109e19554b.

Reason for revert: https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux64%20UBSan/23984/overview

Original change's description:
> [maglev] Unify call building functions
>
> ... so that we have more reduce/inline opportunities.
> It changes CallArguments to hold a vector of ValueNodes.
>
> Change-Id: I9c282631c0dcc2756edc2e2c1f892c3855e1286d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4020381
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Commit-Queue: Victor Gomes <victorgomes@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#84205}

Change-Id: Iaa18aa8a9b30202c2a0bb74e242f038d29bc738b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4020427
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Owners-Override: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84214}
This commit is contained in:
Nico Hartmann 2022-11-11 14:27:34 +00:00 committed by V8 LUCI CQ
parent 03498726be
commit 7ce4dfd872
2 changed files with 234 additions and 220 deletions

View File

@ -86,72 +86,6 @@ class FunctionContextSpecialization final : public AllStatic {
} // namespace
class CallArguments {
public:
CallArguments(ConvertReceiverMode receiver_mode,
interpreter::RegisterList reglist,
const InterpreterFrameState& frame)
: receiver_mode_(receiver_mode), args_(reglist.register_count()) {
for (int i = 0; i < reglist.register_count(); i++) {
args_[i] = frame.get(reglist[i]);
}
DCHECK_IMPLIES(args_.size() == 0,
receiver_mode == ConvertReceiverMode::kNullOrUndefined);
}
CallArguments(ConvertReceiverMode receiver_mode,
std::initializer_list<ValueNode*> args)
: receiver_mode_(receiver_mode), args_(args) {}
ValueNode* receiver() const {
if (receiver_mode_ == ConvertReceiverMode::kNullOrUndefined) {
return nullptr;
}
return args_[0];
}
size_t count() const {
if (receiver_mode_ == ConvertReceiverMode::kNullOrUndefined) {
return args_.size();
}
return args_.size() - 1;
}
size_t count_with_receiver() const { return count() + 1; }
ValueNode* operator[](size_t i) const {
if (receiver_mode_ != ConvertReceiverMode::kNullOrUndefined) {
i++;
}
if (i >= args_.size()) return nullptr;
return args_[i];
}
ConvertReceiverMode receiver_mode() const { return receiver_mode_; }
void PopReceiver(ConvertReceiverMode new_receiver_mode) {
DCHECK_NE(receiver_mode_, ConvertReceiverMode::kNullOrUndefined);
DCHECK_NE(new_receiver_mode, ConvertReceiverMode::kNullOrUndefined);
if (count() == 0) {
// If there is no non-receiver argument to become the new receiver,
// consider the new receiver to be known undefined.
receiver_mode_ = ConvertReceiverMode::kNullOrUndefined;
} else {
// TODO(victorgomes): Do this better!
for (size_t i = 0; i < args_.size() - 1; i++) {
args_[i] = args_[i + 1];
}
args_.pop_back();
receiver_mode_ = new_receiver_mode;
}
}
private:
ConvertReceiverMode receiver_mode_;
base::SmallVector<ValueNode*, 8> args_;
};
MaglevGraphBuilder::MaglevGraphBuilder(LocalIsolate* local_isolate,
MaglevCompilationUnit* compilation_unit,
Graph* graph, MaglevGraphBuilder* parent)
@ -1578,8 +1512,12 @@ bool MaglevGraphBuilder::TryBuildPropertyGetterCall(
receiver == lookup_start_object
? ConvertReceiverMode::kNotNullOrUndefined
: ConvertReceiverMode::kAny;
CallArguments args(receiver_mode, {receiver});
ReduceCall(constant.AsJSFunction(), args);
Call* call = CreateNewNode<Call>(Call::kFixedInputCount + 1, receiver_mode,
Call::TargetType::kJSFunction,
compiler::FeedbackSource(),
GetConstant(constant), GetContext());
call->set_arg(0, receiver);
SetAccumulator(AddNode(call));
return true;
} else {
// TODO(victorgomes): API calls.
@ -1592,9 +1530,13 @@ bool MaglevGraphBuilder::TryBuildPropertySetterCall(
ValueNode* value) {
compiler::ObjectRef constant = access_info.constant().value();
if (constant.IsJSFunction()) {
CallArguments args(ConvertReceiverMode::kNotNullOrUndefined,
{receiver, value});
ReduceCall(constant.AsJSFunction(), args);
Call* call = CreateNewNode<Call>(
Call::kFixedInputCount + 2, ConvertReceiverMode::kNotNullOrUndefined,
Call::TargetType::kJSFunction, compiler::FeedbackSource(),
GetConstant(constant), GetContext());
call->set_arg(0, receiver);
call->set_arg(1, value);
SetAccumulator(AddNode(call));
return true;
} else {
// TODO(victorgomes): API calls.
@ -2693,17 +2635,16 @@ void MaglevGraphBuilder::InlineCallFromRegisters(
->SetToBlockAndReturnNext(current_block_);
}
ValueNode* MaglevGraphBuilder::TryReduceStringFromCharCode(
compiler::JSFunctionRef target, CallArguments& args, bool set_accumulator) {
if (args.count() != 1) return nullptr;
return SetAccumulatorIfNeeded(
AddNewNode<BuiltinStringFromCharCode>({GetInt32(args[0])}),
set_accumulator);
bool MaglevGraphBuilder::TryReduceStringFromCharCode(
compiler::JSFunctionRef target, const CallArguments& args) {
if (args.count() != 1) return false;
SetAccumulator(AddNewNode<BuiltinStringFromCharCode>({GetInt32(args[0])}));
return true;
}
ValueNode* MaglevGraphBuilder::TryReduceStringPrototypeCharCodeAt(
compiler::JSFunctionRef target, CallArguments& args, bool set_accumulator) {
ValueNode* receiver = GetTaggedOrUndefined(args.receiver());
bool MaglevGraphBuilder::TryReduceStringPrototypeCharCodeAt(
compiler::JSFunctionRef target, const CallArguments& args) {
ValueNode* receiver = GetTaggedReceiver(args);
ValueNode* index;
if (args.count() == 0) {
// Index is the undefined object. ToIntegerOrInfinity(undefined) = 0.
@ -2718,53 +2659,53 @@ ValueNode* MaglevGraphBuilder::TryReduceStringPrototypeCharCodeAt(
ValueNode* length = AddNewNode<StringLength>({receiver});
AddNewNode<CheckInt32Condition>({index, length}, AssertCondition::kLess,
DeoptimizeReason::kOutOfBounds);
return SetAccumulatorIfNeeded(
AddNewNode<BuiltinStringPrototypeCharCodeAt>({receiver, index}),
set_accumulator);
SetAccumulator(
AddNewNode<BuiltinStringPrototypeCharCodeAt>({receiver, index}));
return true;
}
ValueNode* MaglevGraphBuilder::TryReduceFunctionPrototypeCall(
compiler::JSFunctionRef target, CallArguments& args, bool set_accumulator) {
bool MaglevGraphBuilder::TryReduceFunctionPrototypeCall(
compiler::JSFunctionRef target, const CallArguments& args) {
// Use Function.prototype.call context, to ensure any exception is thrown in
// the correct context.
ValueNode* context = GetConstant(target.context());
ValueNode* receiver = GetTaggedOrUndefined(args.receiver());
args.PopReceiver(ConvertReceiverMode::kAny);
return SetAccumulatorIfNeeded(
BuildGenericCall(receiver, context, Call::TargetType::kAny, args),
set_accumulator);
ValueNode* receiver = GetTaggedReceiver(args);
compiler::FeedbackSource feedback_source;
BuildGenericCall(receiver, context, Call::TargetType::kAny,
args.PopReceiver(ConvertReceiverMode::kAny),
feedback_source);
return true;
}
ValueNode* MaglevGraphBuilder::TryReduceBuiltin(compiler::JSFunctionRef target,
CallArguments& args,
bool set_accumulator) {
if (!target.shared().HasBuiltinId()) return nullptr;
bool MaglevGraphBuilder::TryReduceBuiltin(compiler::JSFunctionRef target,
const CallArguments& args) {
if (!target.shared().HasBuiltinId()) return false;
switch (target.shared().builtin_id()) {
#define CASE(Name) \
case Builtin::k##Name: \
return TryReduce##Name(target, args, set_accumulator);
return TryReduce##Name(target, args);
MAGLEV_REDUCED_BUILTIN(CASE)
#undef CASE
default:
// TODO(v8:7700): Inline more builtins.
return nullptr;
return false;
}
}
ValueNode* MaglevGraphBuilder::GetConvertReceiver(
compiler::JSFunctionRef function, CallArguments& args) {
compiler::JSFunctionRef function, const CallArguments& args) {
compiler::SharedFunctionInfoRef shared = function.shared();
if (shared.native() || shared.language_mode() == LanguageMode::kStrict) {
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
return GetRootConstant(RootIndex::kUndefinedValue);
} else {
return GetTaggedValue(args.receiver());
return GetTaggedValue(*args.receiver());
}
}
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
return GetConstant(function.native_context().global_proxy_object());
}
ValueNode* receiver = GetTaggedValue(args.receiver());
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();
@ -2778,37 +2719,36 @@ ValueNode* MaglevGraphBuilder::GetConvertReceiver(
args.receiver_mode());
}
ValueNode* MaglevGraphBuilder::TryBuildCallKnownJSFunction(
compiler::JSFunctionRef function, CallArguments& args,
bool set_accumulator) {
bool MaglevGraphBuilder::TryBuildCallKnownJSFunction(
compiler::JSFunctionRef function, const CallArguments& args) {
// Don't inline CallFunction stub across native contexts.
if (function.native_context() != broker()->target_native_context()) {
return nullptr;
return false;
}
ValueNode* receiver = GetConvertReceiver(function, args);
size_t input_count = args.count() + CallKnownJSFunction::kFixedInputCount;
CallKnownJSFunction* call =
CreateNewNode<CallKnownJSFunction>(input_count, function, receiver);
for (int i = 0; i < static_cast<int>(args.count()); i++) {
for (int i = 0; i < args.count(); i++) {
call->set_arg(i, GetTaggedValue(args[i]));
}
return SetAccumulatorIfNeeded(AddNode(call), set_accumulator);
SetAccumulator(AddNode(call));
return true;
}
Call* MaglevGraphBuilder::BuildGenericCall(
void MaglevGraphBuilder::BuildGenericCall(
ValueNode* target, ValueNode* context, Call::TargetType target_type,
const CallArguments& args,
const compiler::FeedbackSource& feedback_source) {
const CallArguments& args, compiler::FeedbackSource& feedback_source) {
size_t input_count = args.count_with_receiver() + Call::kFixedInputCount;
Call* call =
CreateNewNode<Call>(input_count, args.receiver_mode(), target_type,
feedback_source, target, context);
int arg_index = 0;
call->set_arg(arg_index++, GetTaggedOrUndefined(args.receiver()));
for (size_t i = 0; i < args.count(); ++i) {
call->set_arg(arg_index++, GetTaggedReceiver(args));
for (int i = 0; i < args.count(); ++i) {
call->set_arg(arg_index++, GetTaggedValue(args[i]));
}
return AddNode(call);
SetAccumulator(AddNode(call));
}
bool MaglevGraphBuilder::BuildCheckValue(ValueNode* node,
@ -2822,38 +2762,8 @@ bool MaglevGraphBuilder::BuildCheckValue(ValueNode* node,
return true;
}
ValueNode* MaglevGraphBuilder::ReduceCall(compiler::ObjectRef object,
CallArguments& args,
bool set_accumulator) {
if (!object.IsJSFunction()) {
return BuildGenericCall(GetConstant(object), GetContext(),
Call::TargetType::kAny, args);
}
compiler::JSFunctionRef target = object.AsJSFunction();
// Do not reduce calls to functions with break points.
if (!target.shared().HasBreakInfo()) {
if (target.object()->IsJSClassConstructor()) {
// If we have a class constructor, we should raise an exception.
return SetAccumulatorIfNeeded(
BuildCallRuntime(Runtime::kThrowConstructorNonCallableError,
{GetConstant(target)}),
set_accumulator);
}
DCHECK(target.object()->IsCallable());
if (ValueNode* result = TryReduceBuiltin(target, args, set_accumulator)) {
return result;
}
if (ValueNode* result =
TryBuildCallKnownJSFunction(target, args, set_accumulator)) {
return result;
}
}
return BuildGenericCall(GetConstant(target), GetContext(),
Call::TargetType::kJSFunction, args);
}
void MaglevGraphBuilder::BuildCall(ValueNode* target_node, CallArguments& args,
void MaglevGraphBuilder::BuildCall(ValueNode* target_node,
const CallArguments& args,
compiler::FeedbackSource& feedback_source) {
Call::TargetType target_type = Call::TargetType::kAny;
const compiler::ProcessedFeedback& processed_feedback =
@ -2877,10 +2787,29 @@ void MaglevGraphBuilder::BuildCall(ValueNode* target_node, CallArguments& args,
if (!target.IsJSFunction()) break;
compiler::JSFunctionRef function = target.AsJSFunction();
// Do not reduce calls to functions with break points.
if (function.shared().HasBreakInfo()) break;
// Reset the feedback source
feedback_source = compiler::FeedbackSource();
target_type = Call::TargetType::kJSFunction;
if (!BuildCheckValue(target_node, target)) return;
ReduceCall(function, args, true);
return;
if (function.object()->IsJSClassConstructor()) {
// If we have a class constructor, we should raise an exception.
SetAccumulator(BuildCallRuntime(
Runtime::kThrowConstructorNonCallableError, {target_node}));
return;
}
DCHECK(function.object()->IsCallable());
if (TryReduceBuiltin(function, args)) {
return;
}
if (TryBuildCallKnownJSFunction(function, args)) {
return;
}
break;
}
default:
@ -2889,8 +2818,7 @@ void MaglevGraphBuilder::BuildCall(ValueNode* target_node, CallArguments& args,
// On fallthrough, create a generic call.
ValueNode* context = GetContext();
SetAccumulator(BuildGenericCall(target_node, context, target_type, args,
feedback_source));
BuildGenericCall(target_node, context, target_type, args, feedback_source);
}
void MaglevGraphBuilder::BuildCallFromRegisterList(
@ -2899,7 +2827,7 @@ void MaglevGraphBuilder::BuildCallFromRegisterList(
interpreter::RegisterList reg_list = iterator_.GetRegisterListOperand(1);
FeedbackSlot slot = GetSlotOperand(3);
compiler::FeedbackSource feedback_source(feedback(), slot);
CallArguments args(receiver_mode, reg_list, current_interpreter_frame_);
CallArguments args(receiver_mode, reg_list);
BuildCall(target, args, feedback_source);
}
@ -2909,29 +2837,32 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
const int receiver_count =
(receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
const int reg_count = arg_count + receiver_count;
FeedbackSlot slot = GetSlotOperand(reg_count + 1);
int slot_operand_index = arg_count + receiver_count + 1;
FeedbackSlot slot = GetSlotOperand(slot_operand_index);
compiler::FeedbackSource feedback_source(feedback(), slot);
switch (reg_count) {
case 0: {
DCHECK_EQ(receiver_mode, ConvertReceiverMode::kNullOrUndefined);
CallArguments args(receiver_mode, {});
CallArguments args(receiver_mode, reg_count);
BuildCall(target, args, feedback_source);
break;
}
case 1: {
CallArguments args(receiver_mode, {LoadRegisterRaw(1)});
CallArguments args(receiver_mode, reg_count,
iterator_.GetRegisterOperand(1));
BuildCall(target, args, feedback_source);
break;
}
case 2: {
CallArguments args(receiver_mode,
{LoadRegisterRaw(1), LoadRegisterRaw(2)});
CallArguments args(receiver_mode, reg_count,
iterator_.GetRegisterOperand(1),
iterator_.GetRegisterOperand(2));
BuildCall(target, args, feedback_source);
break;
}
case 3: {
CallArguments args(receiver_mode, {LoadRegisterRaw(1), LoadRegisterRaw(2),
LoadRegisterRaw(3)});
CallArguments args(
receiver_mode, reg_count, iterator_.GetRegisterOperand(1),
iterator_.GetRegisterOperand(2), iterator_.GetRegisterOperand(3));
BuildCall(target, args, feedback_source);
break;
}
@ -3008,11 +2939,21 @@ void MaglevGraphBuilder::VisitCallJSRuntime() {
ValueNode* callee = LoadAndCacheContextSlot(
context, NativeContext::OffsetOfElementAt(slot), kMutable);
// Call the function.
interpreter::RegisterList reglist = iterator_.GetRegisterListOperand(1);
CallArguments args(ConvertReceiverMode::kNullOrUndefined, reglist,
current_interpreter_frame_);
SetAccumulator(BuildGenericCall(callee, GetContext(),
Call::TargetType::kJSFunction, args));
interpreter::RegisterList args = iterator_.GetRegisterListOperand(1);
int kTheReceiver = 1;
size_t input_count =
args.register_count() + Call::kFixedInputCount + kTheReceiver;
Call* call =
CreateNewNode<Call>(input_count, ConvertReceiverMode::kNullOrUndefined,
Call::TargetType::kJSFunction,
compiler::FeedbackSource(), callee, GetContext());
int arg_index = 0;
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));
}
void MaglevGraphBuilder::VisitCallRuntimeForPair() {
@ -3468,25 +3409,23 @@ bool MaglevGraphBuilder::TryBuildFastInstanceOf(
}
// Call @@hasInstance
CallArguments args(ConvertReceiverMode::kNotNullOrUndefined,
{callable_node, object});
ValueNode* call =
ReduceCall(has_instance_field->AsJSFunction(), args, false);
Call* call = AddNewNode<Call>(
Call::kFixedInputCount + 2, ConvertReceiverMode::kNotNullOrUndefined,
Call::TargetType::kJSFunction, compiler::FeedbackSource(),
GetConstant(*has_instance_field), GetContext());
call->set_arg(0, callable_node);
call->set_arg(1, object);
// Make sure that a lazy deopt after the @@hasInstance call also performs
// ToBoolean before returning to the interpreter.
// TODO(leszeks): Wrap this in a helper.
if (call->properties().can_lazy_deopt()) {
new (call->lazy_deopt_info()) LazyDeoptInfo(
zone(),
BuiltinContinuationDeoptFrame(
Builtin::kToBooleanLazyDeoptContinuation, {}, GetContext(),
zone()->New<InterpretedDeoptFrame>(
call->lazy_deopt_info()->top_frame().as_interpreted())));
}
new (call->lazy_deopt_info()) LazyDeoptInfo(
zone(),
BuiltinContinuationDeoptFrame(
Builtin::kToBooleanLazyDeoptContinuation, {}, GetContext(),
zone()->New<InterpretedDeoptFrame>(
call->lazy_deopt_info()->top_frame().as_interpreted())));
// TODO(v8:7700): Do we need to call ToBoolean here? If we have reduce the
// call further, we might already have a boolean constant as result.
SetAccumulator(AddNewNode<ToBoolean>({call}));
return true;
}

View File

@ -37,8 +37,6 @@ namespace v8 {
namespace internal {
namespace maglev {
class CallArguments;
class MaglevGraphBuilder {
public:
explicit MaglevGraphBuilder(LocalIsolate* local_isolate,
@ -648,6 +646,9 @@ class MaglevGraphBuilder {
current_interpreter_frame_.set(dst, current_interpreter_frame_.get(src));
}
ValueNode* GetTaggedValue(interpreter::Register reg) {
return GetTaggedValue(current_interpreter_frame_.get(reg));
}
ValueNode* GetTaggedValue(ValueNode* value) {
switch (value->properties().value_representation()) {
case ValueRepresentation::kTagged:
@ -681,11 +682,6 @@ class MaglevGraphBuilder {
UNREACHABLE();
}
ValueNode* GetTaggedValue(interpreter::Register reg) {
ValueNode* value = current_interpreter_frame_.get(reg);
return GetTaggedValue(value);
}
void SetKnownType(ValueNode* node, NodeType type) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(node);
known_info->type = type;
@ -745,8 +741,7 @@ class MaglevGraphBuilder {
}
ValueNode* GetInt32(interpreter::Register reg) {
ValueNode* value = current_interpreter_frame_.get(reg);
return GetInt32(value);
return GetInt32(current_interpreter_frame_.get(reg));
}
ValueNode* GetFloat64(ValueNode* value) {
@ -803,11 +798,6 @@ class MaglevGraphBuilder {
current_interpreter_frame_.accumulator();
}
ValueNode* LoadRegisterRaw(int operand_index) {
return current_interpreter_frame_.get(
iterator_.GetRegisterOperand(operand_index));
}
ValueNode* LoadRegisterTagged(int operand_index) {
return GetTaggedValue(iterator_.GetRegisterOperand(operand_index));
}
@ -832,14 +822,6 @@ class MaglevGraphBuilder {
StoreRegister(interpreter::Register::virtual_accumulator(), node);
}
template <typename NodeT>
NodeT* SetAccumulatorIfNeeded(NodeT* node, bool set_accumulator) {
if (set_accumulator) {
SetAccumulator(node);
}
return node;
}
ValueNode* GetSecondValue(ValueNode* result) {
// GetSecondReturnedValue must be added just after a node that calls a
// builtin that expects 2 returned values. It simply binds kReturnRegister1
@ -1042,40 +1024,133 @@ class MaglevGraphBuilder {
ConvertReceiverMode receiver_mode,
compiler::JSFunctionRef function);
ValueNode* GetTaggedOrUndefined(ValueNode* maybe_value) {
if (maybe_value == nullptr) {
return GetRootConstant(RootIndex::kUndefinedValue);
}
return GetTaggedValue(maybe_value);
}
class CallArguments {
public:
enum Mode {
kFromRegisters,
kFromRegisterList,
};
CallArguments(ConvertReceiverMode receiver_mode, int reg_count,
interpreter::Register r0 = interpreter::Register(),
interpreter::Register r1 = interpreter::Register(),
interpreter::Register r2 = interpreter::Register())
: receiver_mode_(receiver_mode),
call_mode_(kFromRegisters),
reg_count_(reg_count) {
DCHECK_GE(reg_count, 0);
DCHECK_LT(reg_count, 4);
DCHECK_IMPLIES(receiver_mode_ != ConvertReceiverMode::kNullOrUndefined,
reg_count > 0);
DCHECK_IMPLIES(reg_count > 0, r0.is_valid());
regs_[0] = r0;
DCHECK_IMPLIES(reg_count > 1, r1.is_valid());
regs_[1] = r1;
DCHECK_IMPLIES(reg_count > 2, r2.is_valid());
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) {
DCHECK_GT(reg_count_, 0);
return regs_[0];
}
return reglist_[0];
}
int count() const {
int register_count =
call_mode_ == kFromRegisters ? reg_count_ : reglist_.register_count();
if (receiver_mode_ == ConvertReceiverMode::kNullOrUndefined) {
return register_count;
}
return 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, reg_count_);
DCHECK_GE(i, 0);
return regs_[i];
}
return reglist_[i];
}
ConvertReceiverMode receiver_mode() const { return receiver_mode_; }
CallArguments PopReceiver(ConvertReceiverMode new_receiver_mode) const {
DCHECK_NE(receiver_mode_, ConvertReceiverMode::kNullOrUndefined);
DCHECK_NE(new_receiver_mode, ConvertReceiverMode::kNullOrUndefined);
// If there is no non-receiver argument to become the new receiver,
// consider the new receiver to be known undefined.
if (count() == 0) {
new_receiver_mode = ConvertReceiverMode::kNullOrUndefined;
}
if (call_mode_ == kFromRegisters) {
return CallArguments(new_receiver_mode, reg_count_ - 1, regs_[1],
regs_[2]);
}
return CallArguments(new_receiver_mode, reglist_.PopLeft());
}
private:
const ConvertReceiverMode receiver_mode_;
const Mode call_mode_;
union {
struct {
interpreter::Register regs_[3];
int reg_count_;
};
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,
CallArguments& args);
const CallArguments& args);
#define MAGLEV_REDUCED_BUILTIN(V) \
V(FunctionPrototypeCall) \
V(StringFromCharCode) \
V(StringPrototypeCharCodeAt)
#define DEFINE_BUILTIN_REDUCER(Name) \
ValueNode* TryReduce##Name(compiler::JSFunctionRef builtin_target, \
CallArguments& args, bool set_accumulator);
#define DEFINE_BUILTIN_REDUCER(Name) \
bool TryReduce##Name(compiler::JSFunctionRef builtin_target, \
const CallArguments& args);
MAGLEV_REDUCED_BUILTIN(DEFINE_BUILTIN_REDUCER)
#undef DEFINE_BUILTIN_REDUCER
ValueNode* TryReduceBuiltin(compiler::JSFunctionRef builtin_target,
CallArguments& args, bool set_accumulator);
ValueNode* TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
CallArguments& args,
bool set_accumulator);
Call* BuildGenericCall(ValueNode* target, ValueNode* context,
Call::TargetType target_type,
const CallArguments& args,
const compiler::FeedbackSource& feedback_source =
compiler::FeedbackSource());
ValueNode* ReduceCall(compiler::ObjectRef target, CallArguments& args,
bool set_accumulator = true);
void BuildCall(ValueNode* target_node, CallArguments& args,
bool TryReduceBuiltin(compiler::JSFunctionRef builtin_target,
const CallArguments& args);
bool TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
const CallArguments& args);
void BuildGenericCall(ValueNode* target, ValueNode* context,
Call::TargetType target_type, const CallArguments& args,
compiler::FeedbackSource& feedback_source);
void BuildCall(ValueNode* target_node, const CallArguments& args,
compiler::FeedbackSource& feedback_source);
void BuildCallFromRegisterList(ConvertReceiverMode receiver_mode);
void BuildCallFromRegisters(int argc_count,