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:
parent
03498726be
commit
7ce4dfd872
@ -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,10 +2787,29 @@ 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()) {
|
||||||
return;
|
// 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:
|
default:
|
||||||
@ -2889,8 +2818,7 @@ void MaglevGraphBuilder::BuildCall(ValueNode* target_node, CallArguments& args,
|
|||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
@ -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,40 +1024,133 @@ 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) \
|
||||||
V(StringFromCharCode) \
|
V(StringFromCharCode) \
|
||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user