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

View File

@ -37,8 +37,6 @@ namespace v8 {
namespace internal { namespace internal {
namespace maglev { namespace maglev {
class CallArguments;
class MaglevGraphBuilder { class MaglevGraphBuilder {
public: public:
explicit MaglevGraphBuilder(LocalIsolate* local_isolate, explicit MaglevGraphBuilder(LocalIsolate* local_isolate,
@ -648,6 +646,9 @@ class MaglevGraphBuilder {
current_interpreter_frame_.set(dst, current_interpreter_frame_.get(src)); 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) { ValueNode* GetTaggedValue(ValueNode* value) {
switch (value->properties().value_representation()) { switch (value->properties().value_representation()) {
case ValueRepresentation::kTagged: case ValueRepresentation::kTagged:
@ -681,11 +682,6 @@ class MaglevGraphBuilder {
UNREACHABLE(); UNREACHABLE();
} }
ValueNode* GetTaggedValue(interpreter::Register reg) {
ValueNode* value = current_interpreter_frame_.get(reg);
return GetTaggedValue(value);
}
void SetKnownType(ValueNode* node, NodeType type) { void SetKnownType(ValueNode* node, NodeType type) {
NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(node); NodeInfo* known_info = known_node_aspects().GetOrCreateInfoFor(node);
known_info->type = type; known_info->type = type;
@ -745,8 +741,7 @@ class MaglevGraphBuilder {
} }
ValueNode* GetInt32(interpreter::Register reg) { ValueNode* GetInt32(interpreter::Register reg) {
ValueNode* value = current_interpreter_frame_.get(reg); return GetInt32(current_interpreter_frame_.get(reg));
return GetInt32(value);
} }
ValueNode* GetFloat64(ValueNode* value) { ValueNode* GetFloat64(ValueNode* value) {
@ -803,11 +798,6 @@ class MaglevGraphBuilder {
current_interpreter_frame_.accumulator(); current_interpreter_frame_.accumulator();
} }
ValueNode* LoadRegisterRaw(int operand_index) {
return current_interpreter_frame_.get(
iterator_.GetRegisterOperand(operand_index));
}
ValueNode* LoadRegisterTagged(int operand_index) { ValueNode* LoadRegisterTagged(int operand_index) {
return GetTaggedValue(iterator_.GetRegisterOperand(operand_index)); return GetTaggedValue(iterator_.GetRegisterOperand(operand_index));
} }
@ -832,14 +822,6 @@ class MaglevGraphBuilder {
StoreRegister(interpreter::Register::virtual_accumulator(), node); 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) { ValueNode* GetSecondValue(ValueNode* result) {
// GetSecondReturnedValue must be added just after a node that calls a // GetSecondReturnedValue must be added just after a node that calls a
// builtin that expects 2 returned values. It simply binds kReturnRegister1 // builtin that expects 2 returned values. It simply binds kReturnRegister1
@ -1042,15 +1024,111 @@ class MaglevGraphBuilder {
ConvertReceiverMode receiver_mode, ConvertReceiverMode receiver_mode,
compiler::JSFunctionRef function); compiler::JSFunctionRef function);
ValueNode* GetTaggedOrUndefined(ValueNode* maybe_value) { class CallArguments {
if (maybe_value == nullptr) { public:
return GetRootConstant(RootIndex::kUndefinedValue); enum Mode {
} kFromRegisters,
return GetTaggedValue(maybe_value); 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, ValueNode* GetConvertReceiver(compiler::JSFunctionRef function,
CallArguments& args); const CallArguments& args);
#define MAGLEV_REDUCED_BUILTIN(V) \ #define MAGLEV_REDUCED_BUILTIN(V) \
V(FunctionPrototypeCall) \ V(FunctionPrototypeCall) \
@ -1058,24 +1136,21 @@ class MaglevGraphBuilder {
V(StringPrototypeCharCodeAt) V(StringPrototypeCharCodeAt)
#define DEFINE_BUILTIN_REDUCER(Name) \ #define DEFINE_BUILTIN_REDUCER(Name) \
ValueNode* TryReduce##Name(compiler::JSFunctionRef builtin_target, \ bool TryReduce##Name(compiler::JSFunctionRef builtin_target, \
CallArguments& args, bool set_accumulator); const CallArguments& args);
MAGLEV_REDUCED_BUILTIN(DEFINE_BUILTIN_REDUCER) MAGLEV_REDUCED_BUILTIN(DEFINE_BUILTIN_REDUCER)
#undef DEFINE_BUILTIN_REDUCER #undef DEFINE_BUILTIN_REDUCER
ValueNode* TryReduceBuiltin(compiler::JSFunctionRef builtin_target, bool TryReduceBuiltin(compiler::JSFunctionRef builtin_target,
CallArguments& args, bool set_accumulator); const CallArguments& args);
ValueNode* TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
CallArguments& args, bool TryBuildCallKnownJSFunction(compiler::JSFunctionRef function,
bool set_accumulator); const CallArguments& args);
Call* BuildGenericCall(ValueNode* target, ValueNode* context,
Call::TargetType target_type, void BuildGenericCall(ValueNode* target, ValueNode* context,
const CallArguments& args, Call::TargetType target_type, const CallArguments& args,
const compiler::FeedbackSource& feedback_source = compiler::FeedbackSource& feedback_source);
compiler::FeedbackSource()); void BuildCall(ValueNode* target_node, const CallArguments& args,
ValueNode* ReduceCall(compiler::ObjectRef target, CallArguments& args,
bool set_accumulator = true);
void BuildCall(ValueNode* target_node, CallArguments& args,
compiler::FeedbackSource& feedback_source); compiler::FeedbackSource& feedback_source);
void BuildCallFromRegisterList(ConvertReceiverMode receiver_mode); void BuildCallFromRegisterList(ConvertReceiverMode receiver_mode);
void BuildCallFromRegisters(int argc_count, void BuildCallFromRegisters(int argc_count,