Preserve feedback and speculation mode for JSCall
Changing the target of JSCall nodes (e.g. while lowering higher order calls) now preserves feedback and speculation mode to allow further (speculative) optimizations. A flag is introduced to mark feedback unrelated to the call target after such a transformation. This flag is used to prevent access to the feedback without the need to invalidate it. Bug: v8:9702 Change-Id: I311d3a4b1b22d6f65e5837a23b0b7585c8d75eed Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1844788 Commit-Queue: Nico Hartmann <nicohartmann@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#64733}
This commit is contained in:
parent
0ec75c9173
commit
149e4935ba
@ -2231,8 +2231,9 @@ void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode,
|
|||||||
FeedbackSource feedback = CreateFeedbackSource(slot_id);
|
FeedbackSource feedback = CreateFeedbackSource(slot_id);
|
||||||
CallFrequency frequency = ComputeCallFrequency(slot_id);
|
CallFrequency frequency = ComputeCallFrequency(slot_id);
|
||||||
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
|
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
|
||||||
const Operator* op = javascript()->Call(arg_count, frequency, feedback,
|
const Operator* op =
|
||||||
receiver_mode, speculation_mode);
|
javascript()->Call(arg_count, frequency, feedback, receiver_mode,
|
||||||
|
speculation_mode, CallFeedbackRelation::kRelated);
|
||||||
|
|
||||||
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
|
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
|
||||||
op, args, static_cast<int>(arg_count), feedback.slot);
|
op, args, static_cast<int>(arg_count), feedback.slot);
|
||||||
@ -2415,8 +2416,9 @@ void BytecodeGraphBuilder::VisitCallWithSpread() {
|
|||||||
int const slot_id = bytecode_iterator().GetIndexOperand(3);
|
int const slot_id = bytecode_iterator().GetIndexOperand(3);
|
||||||
FeedbackSource feedback = CreateFeedbackSource(slot_id);
|
FeedbackSource feedback = CreateFeedbackSource(slot_id);
|
||||||
CallFrequency frequency = ComputeCallFrequency(slot_id);
|
CallFrequency frequency = ComputeCallFrequency(slot_id);
|
||||||
|
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
|
||||||
const Operator* op = javascript()->CallWithSpread(
|
const Operator* op = javascript()->CallWithSpread(
|
||||||
static_cast<int>(reg_count + 1), frequency, feedback);
|
static_cast<int>(reg_count + 1), frequency, feedback, speculation_mode);
|
||||||
|
|
||||||
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
|
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
|
||||||
op, args, static_cast<int>(arg_count), feedback.slot);
|
op, args, static_cast<int>(arg_count), feedback.slot);
|
||||||
|
@ -36,6 +36,24 @@ inline size_t hash_value(StackCheckKind kind) {
|
|||||||
return static_cast<size_t>(kind);
|
return static_cast<size_t>(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The CallFeedbackRelation states whether the target feedback stored with a
|
||||||
|
// JSCall is related to the call. If, during lowering, a JSCall (e.g. of a
|
||||||
|
// higher order function) is replaced by a JSCall with another target, the
|
||||||
|
// feedback has to be kept but is now unrelated.
|
||||||
|
enum class CallFeedbackRelation { kRelated, kUnrelated };
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os,
|
||||||
|
CallFeedbackRelation call_feedback_relation) {
|
||||||
|
switch (call_feedback_relation) {
|
||||||
|
case CallFeedbackRelation::kRelated:
|
||||||
|
return os << "CallFeedbackRelation::kRelated";
|
||||||
|
case CallFeedbackRelation::kUnrelated:
|
||||||
|
return os << "CallFeedbackRelation::kUnrelated";
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -314,8 +314,10 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
while (arity-- > 3) node->RemoveInput(3);
|
while (arity-- > 3) node->RemoveInput(3);
|
||||||
|
|
||||||
// Morph the {node} to a {JSCallWithArrayLike}.
|
// Morph the {node} to a {JSCallWithArrayLike}.
|
||||||
NodeProperties::ChangeOp(node,
|
NodeProperties::ChangeOp(
|
||||||
javascript()->CallWithArrayLike(p.frequency()));
|
node, javascript()->CallWithArrayLike(
|
||||||
|
p.frequency(), p.feedback(), p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
Reduction const reduction = ReduceJSCallWithArrayLike(node);
|
Reduction const reduction = ReduceJSCallWithArrayLike(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
} else {
|
} else {
|
||||||
@ -342,8 +344,11 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
Node* effect0 = effect;
|
Node* effect0 = effect;
|
||||||
Node* control0 = control;
|
Node* control0 = control;
|
||||||
Node* value0 = effect0 = control0 = graph()->NewNode(
|
Node* value0 = effect0 = control0 = graph()->NewNode(
|
||||||
javascript()->CallWithArrayLike(p.frequency()), target, this_argument,
|
javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
|
||||||
arguments_list, context, frame_state, effect0, control0);
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
target, this_argument, arguments_list, context, frame_state, effect0,
|
||||||
|
control0);
|
||||||
|
|
||||||
// Lower to {JSCall} if {arguments_list} is either null or undefined.
|
// Lower to {JSCall} if {arguments_list} is either null or undefined.
|
||||||
Node* effect1 = effect;
|
Node* effect1 = effect;
|
||||||
@ -387,14 +392,10 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Change {node} to the new {JSCall} operator.
|
// Change {node} to the new {JSCall} operator.
|
||||||
// TODO(mslekova): Since this introduces a Call that will get optimized by
|
|
||||||
// the JSCallReducer, we basically might have to do all the serialization
|
|
||||||
// that we do for that here as well. The only difference is that here we
|
|
||||||
// disable speculation (cf. the empty FeedbackSource above), causing the
|
|
||||||
// JSCallReducer to do much less work. We should revisit this later.
|
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node,
|
node, javascript()->Call(arity, p.frequency(), p.feedback(), convert_mode,
|
||||||
javascript()->Call(arity, p.frequency(), FeedbackSource(), convert_mode));
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
// Try to further reduce the JSCall {node}.
|
// Try to further reduce the JSCall {node}.
|
||||||
Reduction const reduction = ReduceJSCall(node);
|
Reduction const reduction = ReduceJSCall(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
@ -569,8 +570,9 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
|
|||||||
--arity;
|
--arity;
|
||||||
}
|
}
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node,
|
node, javascript()->Call(arity, p.frequency(), p.feedback(), convert_mode,
|
||||||
javascript()->Call(arity, p.frequency(), FeedbackSource(), convert_mode));
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
// Try to further reduce the JSCall {node}.
|
// Try to further reduce the JSCall {node}.
|
||||||
Reduction const reduction = ReduceJSCall(node);
|
Reduction const reduction = ReduceJSCall(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
@ -801,8 +803,10 @@ Reduction JSCallReducer::ReduceReflectApply(Node* node) {
|
|||||||
while (arity-- > 3) {
|
while (arity-- > 3) {
|
||||||
node->RemoveInput(arity);
|
node->RemoveInput(arity);
|
||||||
}
|
}
|
||||||
NodeProperties::ChangeOp(node,
|
NodeProperties::ChangeOp(
|
||||||
javascript()->CallWithArrayLike(p.frequency()));
|
node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
|
||||||
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
Reduction const reduction = ReduceJSCallWithArrayLike(node);
|
Reduction const reduction = ReduceJSCallWithArrayLike(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
}
|
}
|
||||||
@ -1194,8 +1198,11 @@ Reduction JSCallReducer::ReduceArrayForEach(
|
|||||||
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
control = effect = graph()->NewNode(
|
control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state, effect,
|
||||||
|
control);
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
Node* on_exception = nullptr;
|
Node* on_exception = nullptr;
|
||||||
@ -1448,10 +1455,12 @@ Reduction JSCallReducer::ReduceArrayReduce(
|
|||||||
&checkpoint_params[0], stack_parameters - 1, outer_frame_state,
|
&checkpoint_params[0], stack_parameters - 1, outer_frame_state,
|
||||||
ContinuationFrameStateMode::LAZY);
|
ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
next_cur = control = effect =
|
next_cur = control = effect = graph()->NewNode(
|
||||||
graph()->NewNode(javascript()->Call(6, p.frequency()), fncallback,
|
javascript()->Call(6, p.frequency(), p.feedback(),
|
||||||
jsgraph()->UndefinedConstant(), cur, element, k,
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
receiver, context, frame_state, effect, control);
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, jsgraph()->UndefinedConstant(), cur, element, k, receiver,
|
||||||
|
context, frame_state, effect, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
@ -1643,8 +1652,11 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
|||||||
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
Node* callback_value = control = effect = graph()->NewNode(
|
Node* callback_value = control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state, effect,
|
||||||
|
control);
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
Node* on_exception = nullptr;
|
Node* on_exception = nullptr;
|
||||||
@ -1864,8 +1876,11 @@ Reduction JSCallReducer::ReduceArrayFilter(
|
|||||||
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
callback_value = control = effect = graph()->NewNode(
|
callback_value = control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state,
|
||||||
|
effect, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
@ -2074,8 +2089,11 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
|
|||||||
ContinuationFrameStateMode::LAZY);
|
ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
callback_value = control = effect = graph()->NewNode(
|
callback_value = control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state,
|
||||||
|
effect, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
@ -2392,8 +2410,11 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
|||||||
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
callback_value = control = effect = graph()->NewNode(
|
callback_value = control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state,
|
||||||
|
effect, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
@ -2726,8 +2747,11 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
|||||||
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
outer_frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
callback_value = control = effect = graph()->NewNode(
|
callback_value = control = effect = graph()->NewNode(
|
||||||
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
|
javascript()->Call(5, p.frequency(), p.feedback(),
|
||||||
receiver, context, frame_state, effect, control);
|
ConvertReceiverMode::kAny, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated),
|
||||||
|
fncallback, this_arg, element, k, receiver, context, frame_state,
|
||||||
|
effect, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewire potential exception edges.
|
// Rewire potential exception edges.
|
||||||
@ -3003,11 +3027,14 @@ bool IsSafeArgumentsElements(Node* node) {
|
|||||||
|
|
||||||
Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
Node* node, int arity, CallFrequency const& frequency,
|
Node* node, int arity, CallFrequency const& frequency,
|
||||||
FeedbackSource const& feedback) {
|
FeedbackSource const& feedback, SpeculationMode speculation_mode,
|
||||||
|
CallFeedbackRelation feedback_relation) {
|
||||||
DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
||||||
node->opcode() == IrOpcode::kJSCallWithSpread ||
|
node->opcode() == IrOpcode::kJSCallWithSpread ||
|
||||||
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
|
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
|
||||||
node->opcode() == IrOpcode::kJSConstructWithSpread);
|
node->opcode() == IrOpcode::kJSConstructWithSpread);
|
||||||
|
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
|
||||||
|
feedback.IsValid());
|
||||||
|
|
||||||
Node* arguments_list = NodeProperties::GetValueInput(node, arity);
|
Node* arguments_list = NodeProperties::GetValueInput(node, arity);
|
||||||
if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
|
if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
|
||||||
@ -3145,7 +3172,9 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
|||||||
if (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
if (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
||||||
node->opcode() == IrOpcode::kJSCallWithSpread) {
|
node->opcode() == IrOpcode::kJSCallWithSpread) {
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(arity + 1, frequency, feedback));
|
node, javascript()->Call(arity + 1, frequency, feedback,
|
||||||
|
ConvertReceiverMode::kAny, speculation_mode,
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
Reduction const reduction = ReduceJSCall(node);
|
Reduction const reduction = ReduceJSCall(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
} else {
|
} else {
|
||||||
@ -3286,8 +3315,9 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(arity, p.frequency(), FeedbackSource(),
|
node, javascript()->Call(arity, p.frequency(), p.feedback(),
|
||||||
convert_mode));
|
convert_mode, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
|
|
||||||
// Try to further reduce the JSCall {node}.
|
// Try to further reduce the JSCall {node}.
|
||||||
Reduction const reduction = ReduceJSCall(node);
|
Reduction const reduction = ReduceJSCall(node);
|
||||||
@ -3334,25 +3364,30 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
|
|||||||
? ConvertReceiverMode::kAny
|
? ConvertReceiverMode::kAny
|
||||||
: ConvertReceiverMode::kNotNullOrUndefined;
|
: ConvertReceiverMode::kNotNullOrUndefined;
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(arity, p.frequency(), FeedbackSource(),
|
node, javascript()->Call(arity, p.frequency(), p.feedback(),
|
||||||
convert_mode));
|
convert_mode, p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
|
|
||||||
// Try to further reduce the JSCall {node}.
|
// Try to further reduce the JSCall {node}.
|
||||||
Reduction const reduction = ReduceJSCall(node);
|
Reduction const reduction = ReduceJSCall(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.feedback().IsValid()) return NoChange();
|
if (!ShouldUseCallICFeedback(target) ||
|
||||||
|
p.feedback_relation() != CallFeedbackRelation::kRelated ||
|
||||||
|
!p.feedback().IsValid()) {
|
||||||
|
return NoChange();
|
||||||
|
}
|
||||||
|
|
||||||
ProcessedFeedback const& feedback =
|
ProcessedFeedback const& feedback =
|
||||||
broker()->GetFeedbackForCall(FeedbackSource(p.feedback()));
|
broker()->GetFeedbackForCall(p.feedback());
|
||||||
if (feedback.IsInsufficient()) {
|
if (feedback.IsInsufficient()) {
|
||||||
return ReduceSoftDeoptimize(
|
return ReduceSoftDeoptimize(
|
||||||
node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
|
node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
|
base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
|
||||||
if (feedback_target.has_value() && ShouldUseCallICFeedback(target) &&
|
if (feedback_target.has_value() && feedback_target->map().is_callable()) {
|
||||||
feedback_target->map().is_callable()) {
|
|
||||||
Node* target_function = jsgraph()->Constant(*feedback_target);
|
Node* target_function = jsgraph()->Constant(*feedback_target);
|
||||||
|
|
||||||
// Check that the {target} is still the {target_function}.
|
// Check that the {target} is still the {target_function}.
|
||||||
@ -3728,9 +3763,12 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
|
|||||||
|
|
||||||
Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
|
Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
|
||||||
DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
|
DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
|
||||||
CallFrequency frequency = CallFrequencyOf(node->op());
|
const CallParameters& p = CallParametersOf(node->op());
|
||||||
return ReduceCallOrConstructWithArrayLikeOrSpread(node, 2, frequency,
|
int arity = static_cast<int>(p.arity());
|
||||||
FeedbackSource());
|
DCHECK_EQ(arity, 2);
|
||||||
|
return ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
|
node, arity, p.frequency(), p.feedback(), p.speculation_mode(),
|
||||||
|
p.feedback_relation());
|
||||||
}
|
}
|
||||||
|
|
||||||
Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
|
Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
|
||||||
@ -3740,8 +3778,9 @@ Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
|
|||||||
int arity = static_cast<int>(p.arity() - 1);
|
int arity = static_cast<int>(p.arity() - 1);
|
||||||
CallFrequency frequency = p.frequency();
|
CallFrequency frequency = p.frequency();
|
||||||
FeedbackSource feedback = p.feedback();
|
FeedbackSource feedback = p.feedback();
|
||||||
return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
|
return ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
feedback);
|
node, arity, frequency, feedback, p.speculation_mode(),
|
||||||
|
p.feedback_relation());
|
||||||
}
|
}
|
||||||
|
|
||||||
Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
|
Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
|
||||||
@ -4287,8 +4326,9 @@ Reduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) {
|
|||||||
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
|
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
|
||||||
DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
|
DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
|
||||||
CallFrequency frequency = CallFrequencyOf(node->op());
|
CallFrequency frequency = CallFrequencyOf(node->op());
|
||||||
return ReduceCallOrConstructWithArrayLikeOrSpread(node, 1, frequency,
|
return ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
FeedbackSource());
|
node, 1, frequency, FeedbackSource(),
|
||||||
|
SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kRelated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
|
Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
|
||||||
@ -4298,8 +4338,9 @@ Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
|
|||||||
int arity = static_cast<int>(p.arity() - 2);
|
int arity = static_cast<int>(p.arity() - 2);
|
||||||
CallFrequency frequency = p.frequency();
|
CallFrequency frequency = p.frequency();
|
||||||
FeedbackSource feedback = p.feedback();
|
FeedbackSource feedback = p.feedback();
|
||||||
return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
|
return ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
feedback);
|
node, arity, frequency, feedback, SpeculationMode::kDisallowSpeculation,
|
||||||
|
CallFeedbackRelation::kRelated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
|
Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
|
||||||
@ -5757,8 +5798,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
|
|||||||
// 9. Call executor with both resolving functions
|
// 9. Call executor with both resolving functions
|
||||||
effect = control = graph()->NewNode(
|
effect = control = graph()->NewNode(
|
||||||
javascript()->Call(4, p.frequency(), FeedbackSource(),
|
javascript()->Call(4, p.frequency(), FeedbackSource(),
|
||||||
ConvertReceiverMode::kNullOrUndefined,
|
ConvertReceiverMode::kNullOrUndefined),
|
||||||
SpeculationMode::kDisallowSpeculation),
|
|
||||||
executor, jsgraph()->UndefinedConstant(), resolve, reject, context,
|
executor, jsgraph()->UndefinedConstant(), resolve, reject, context,
|
||||||
frame_state, effect, control);
|
frame_state, effect, control);
|
||||||
|
|
||||||
@ -5770,8 +5810,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
|
|||||||
// 10a. Call reject if the call to executor threw.
|
// 10a. Call reject if the call to executor threw.
|
||||||
exception_effect = exception_control = graph()->NewNode(
|
exception_effect = exception_control = graph()->NewNode(
|
||||||
javascript()->Call(3, p.frequency(), FeedbackSource(),
|
javascript()->Call(3, p.frequency(), FeedbackSource(),
|
||||||
ConvertReceiverMode::kNullOrUndefined,
|
ConvertReceiverMode::kNullOrUndefined),
|
||||||
SpeculationMode::kDisallowSpeculation),
|
|
||||||
reject, jsgraph()->UndefinedConstant(), reason, context, frame_state,
|
reject, jsgraph()->UndefinedConstant(), reason, context, frame_state,
|
||||||
exception_effect, exception_control);
|
exception_effect, exception_control);
|
||||||
|
|
||||||
@ -5862,7 +5901,8 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
|
|||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
||||||
ConvertReceiverMode::kNotNullOrUndefined,
|
ConvertReceiverMode::kNotNullOrUndefined,
|
||||||
p.speculation_mode()));
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
Reduction const reduction = ReducePromisePrototypeThen(node);
|
Reduction const reduction = ReducePromisePrototypeThen(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
}
|
}
|
||||||
@ -5989,7 +6029,8 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
|||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
||||||
ConvertReceiverMode::kNotNullOrUndefined,
|
ConvertReceiverMode::kNotNullOrUndefined,
|
||||||
p.speculation_mode()));
|
p.speculation_mode(),
|
||||||
|
CallFeedbackRelation::kUnrelated));
|
||||||
Reduction const reduction = ReducePromisePrototypeThen(node);
|
Reduction const reduction = ReducePromisePrototypeThen(node);
|
||||||
return reduction.Changed() ? reduction : Changed(node);
|
return reduction.Changed() ? reduction : Changed(node);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "src/base/flags.h"
|
#include "src/base/flags.h"
|
||||||
#include "src/compiler/frame-states.h"
|
#include "src/compiler/frame-states.h"
|
||||||
|
#include "src/compiler/globals.h"
|
||||||
#include "src/compiler/graph-reducer.h"
|
#include "src/compiler/graph-reducer.h"
|
||||||
#include "src/compiler/node-properties.h"
|
#include "src/compiler/node-properties.h"
|
||||||
#include "src/deoptimizer/deoptimize-reason.h"
|
#include "src/deoptimizer/deoptimize-reason.h"
|
||||||
@ -106,7 +107,8 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
|
|||||||
|
|
||||||
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
|
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||||
Node* node, int arity, CallFrequency const& frequency,
|
Node* node, int arity, CallFrequency const& frequency,
|
||||||
FeedbackSource const& feedback);
|
FeedbackSource const& feedback, SpeculationMode speculation_mode,
|
||||||
|
CallFeedbackRelation feedback_relation);
|
||||||
Reduction ReduceJSConstruct(Node* node);
|
Reduction ReduceJSConstruct(Node* node);
|
||||||
Reduction ReduceJSConstructWithArrayLike(Node* node);
|
Reduction ReduceJSConstructWithArrayLike(Node* node);
|
||||||
Reduction ReduceJSConstructWithSpread(Node* node);
|
Reduction ReduceJSConstructWithSpread(Node* node);
|
||||||
|
@ -1439,7 +1439,8 @@ Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) {
|
|||||||
: feedback.AsCall().speculation_mode();
|
: feedback.AsCall().speculation_mode();
|
||||||
const Operator* call_op =
|
const Operator* call_op =
|
||||||
javascript()->Call(2, CallFrequency(), p.callFeedback(),
|
javascript()->Call(2, CallFrequency(), p.callFeedback(),
|
||||||
ConvertReceiverMode::kNotNullOrUndefined, mode);
|
ConvertReceiverMode::kNotNullOrUndefined, mode,
|
||||||
|
CallFeedbackRelation::kRelated);
|
||||||
Node* call_property = graph()->NewNode(call_op, load_property, receiver,
|
Node* call_property = graph()->NewNode(call_op, load_property, receiver,
|
||||||
context, frame_state, effect, control);
|
context, frame_state, effect, control);
|
||||||
effect = call_property;
|
effect = call_property;
|
||||||
|
@ -23,8 +23,7 @@ std::ostream& operator<<(std::ostream& os, CallFrequency const& f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CallFrequency CallFrequencyOf(Operator const* op) {
|
CallFrequency CallFrequencyOf(Operator const* op) {
|
||||||
DCHECK(op->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
DCHECK_EQ(op->opcode(), IrOpcode::kJSConstructWithArrayLike);
|
||||||
op->opcode() == IrOpcode::kJSConstructWithArrayLike);
|
|
||||||
return OpParameter<CallFrequency>(op);
|
return OpParameter<CallFrequency>(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +65,13 @@ ConstructParameters const& ConstructParametersOf(Operator const* op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, CallParameters const& p) {
|
std::ostream& operator<<(std::ostream& os, CallParameters const& p) {
|
||||||
return os << p.arity() << ", " << p.frequency() << ", " << p.convert_mode();
|
return os << p.arity() << ", " << p.frequency() << ", " << p.convert_mode()
|
||||||
|
<< ", " << p.speculation_mode() << ", " << p.feedback_relation();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CallParameters& CallParametersOf(const Operator* op) {
|
const CallParameters& CallParametersOf(const Operator* op) {
|
||||||
DCHECK(op->opcode() == IrOpcode::kJSCall ||
|
DCHECK(op->opcode() == IrOpcode::kJSCall ||
|
||||||
|
op->opcode() == IrOpcode::kJSCallWithArrayLike ||
|
||||||
op->opcode() == IrOpcode::kJSCallWithSpread);
|
op->opcode() == IrOpcode::kJSCallWithSpread);
|
||||||
return OpParameter<CallParameters>(op);
|
return OpParameter<CallParameters>(op);
|
||||||
}
|
}
|
||||||
@ -882,15 +883,12 @@ const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity,
|
|||||||
parameters); // parameter
|
parameters); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* JSOperatorBuilder::Call(size_t arity,
|
const Operator* JSOperatorBuilder::Call(
|
||||||
CallFrequency const& frequency,
|
size_t arity, CallFrequency const& frequency,
|
||||||
FeedbackSource const& feedback,
|
FeedbackSource const& feedback, ConvertReceiverMode convert_mode,
|
||||||
ConvertReceiverMode convert_mode,
|
SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation) {
|
||||||
SpeculationMode speculation_mode) {
|
|
||||||
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
|
|
||||||
feedback.IsValid());
|
|
||||||
CallParameters parameters(arity, frequency, feedback, convert_mode,
|
CallParameters parameters(arity, frequency, feedback, convert_mode,
|
||||||
speculation_mode);
|
speculation_mode, feedback_relation);
|
||||||
return new (zone()) Operator1<CallParameters>( // --
|
return new (zone()) Operator1<CallParameters>( // --
|
||||||
IrOpcode::kJSCall, Operator::kNoProperties, // opcode
|
IrOpcode::kJSCall, Operator::kNoProperties, // opcode
|
||||||
"JSCall", // name
|
"JSCall", // name
|
||||||
@ -899,21 +897,26 @@ const Operator* JSOperatorBuilder::Call(size_t arity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Operator* JSOperatorBuilder::CallWithArrayLike(
|
const Operator* JSOperatorBuilder::CallWithArrayLike(
|
||||||
CallFrequency const& frequency) {
|
const CallFrequency& frequency, const FeedbackSource& feedback,
|
||||||
return new (zone()) Operator1<CallFrequency>( // --
|
SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation) {
|
||||||
|
CallParameters parameters(2, frequency, feedback, ConvertReceiverMode::kAny,
|
||||||
|
speculation_mode, feedback_relation);
|
||||||
|
return new (zone()) Operator1<CallParameters>( // --
|
||||||
IrOpcode::kJSCallWithArrayLike, Operator::kNoProperties, // opcode
|
IrOpcode::kJSCallWithArrayLike, Operator::kNoProperties, // opcode
|
||||||
"JSCallWithArrayLike", // name
|
"JSCallWithArrayLike", // name
|
||||||
3, 1, 1, 1, 1, 2, // counts
|
3, 1, 1, 1, 1, 2, // counts
|
||||||
frequency); // parameter
|
parameters); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operator* JSOperatorBuilder::CallWithSpread(
|
const Operator* JSOperatorBuilder::CallWithSpread(
|
||||||
uint32_t arity, CallFrequency const& frequency,
|
uint32_t arity, CallFrequency const& frequency,
|
||||||
FeedbackSource const& feedback, SpeculationMode speculation_mode) {
|
FeedbackSource const& feedback, SpeculationMode speculation_mode,
|
||||||
|
CallFeedbackRelation feedback_relation) {
|
||||||
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
|
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
|
||||||
feedback.IsValid());
|
feedback.IsValid());
|
||||||
CallParameters parameters(arity, frequency, feedback,
|
CallParameters parameters(arity, frequency, feedback,
|
||||||
ConvertReceiverMode::kAny, speculation_mode);
|
ConvertReceiverMode::kAny, speculation_mode,
|
||||||
|
feedback_relation);
|
||||||
return new (zone()) Operator1<CallParameters>( // --
|
return new (zone()) Operator1<CallParameters>( // --
|
||||||
IrOpcode::kJSCallWithSpread, Operator::kNoProperties, // opcode
|
IrOpcode::kJSCallWithSpread, Operator::kNoProperties, // opcode
|
||||||
"JSCallWithSpread", // name
|
"JSCallWithSpread", // name
|
||||||
|
@ -165,12 +165,20 @@ class CallParameters final {
|
|||||||
CallParameters(size_t arity, CallFrequency const& frequency,
|
CallParameters(size_t arity, CallFrequency const& frequency,
|
||||||
FeedbackSource const& feedback,
|
FeedbackSource const& feedback,
|
||||||
ConvertReceiverMode convert_mode,
|
ConvertReceiverMode convert_mode,
|
||||||
SpeculationMode speculation_mode)
|
SpeculationMode speculation_mode,
|
||||||
|
CallFeedbackRelation feedback_relation)
|
||||||
: bit_field_(ArityField::encode(arity) |
|
: bit_field_(ArityField::encode(arity) |
|
||||||
|
CallFeedbackRelationField::encode(feedback_relation) |
|
||||||
SpeculationModeField::encode(speculation_mode) |
|
SpeculationModeField::encode(speculation_mode) |
|
||||||
ConvertReceiverModeField::encode(convert_mode)),
|
ConvertReceiverModeField::encode(convert_mode)),
|
||||||
frequency_(frequency),
|
frequency_(frequency),
|
||||||
feedback_(feedback) {}
|
feedback_(feedback) {
|
||||||
|
// CallFeedbackRelation is ignored if the feedback slot is invalid.
|
||||||
|
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
|
||||||
|
feedback.IsValid());
|
||||||
|
DCHECK_IMPLIES(!feedback.IsValid(),
|
||||||
|
feedback_relation == CallFeedbackRelation::kUnrelated);
|
||||||
|
}
|
||||||
|
|
||||||
size_t arity() const { return ArityField::decode(bit_field_); }
|
size_t arity() const { return ArityField::decode(bit_field_); }
|
||||||
CallFrequency const& frequency() const { return frequency_; }
|
CallFrequency const& frequency() const { return frequency_; }
|
||||||
@ -183,6 +191,10 @@ class CallParameters final {
|
|||||||
return SpeculationModeField::decode(bit_field_);
|
return SpeculationModeField::decode(bit_field_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CallFeedbackRelation feedback_relation() const {
|
||||||
|
return CallFeedbackRelationField::decode(bit_field_);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(CallParameters const& that) const {
|
bool operator==(CallParameters const& that) const {
|
||||||
return this->bit_field_ == that.bit_field_ &&
|
return this->bit_field_ == that.bit_field_ &&
|
||||||
this->frequency_ == that.frequency_ &&
|
this->frequency_ == that.frequency_ &&
|
||||||
@ -197,7 +209,8 @@ class CallParameters final {
|
|||||||
feedback_hash(p.feedback_));
|
feedback_hash(p.feedback_));
|
||||||
}
|
}
|
||||||
|
|
||||||
using ArityField = BitField<size_t, 0, 28>;
|
using ArityField = BitField<size_t, 0, 27>;
|
||||||
|
using CallFeedbackRelationField = BitField<CallFeedbackRelation, 27, 1>;
|
||||||
using SpeculationModeField = BitField<SpeculationMode, 28, 1>;
|
using SpeculationModeField = BitField<SpeculationMode, 28, 1>;
|
||||||
using ConvertReceiverModeField = BitField<ConvertReceiverMode, 29, 2>;
|
using ConvertReceiverModeField = BitField<ConvertReceiverMode, 29, 2>;
|
||||||
|
|
||||||
@ -815,12 +828,19 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
|||||||
size_t arity, CallFrequency const& frequency = CallFrequency(),
|
size_t arity, CallFrequency const& frequency = CallFrequency(),
|
||||||
FeedbackSource const& feedback = FeedbackSource(),
|
FeedbackSource const& feedback = FeedbackSource(),
|
||||||
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny,
|
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny,
|
||||||
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation);
|
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation,
|
||||||
const Operator* CallWithArrayLike(CallFrequency const& frequency);
|
CallFeedbackRelation feedback_relation =
|
||||||
|
CallFeedbackRelation::kUnrelated);
|
||||||
|
const Operator* CallWithArrayLike(
|
||||||
|
CallFrequency const& frequency,
|
||||||
|
const FeedbackSource& feedback = FeedbackSource{},
|
||||||
|
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation,
|
||||||
|
CallFeedbackRelation feedback_relation = CallFeedbackRelation::kRelated);
|
||||||
const Operator* CallWithSpread(
|
const Operator* CallWithSpread(
|
||||||
uint32_t arity, CallFrequency const& frequency = CallFrequency(),
|
uint32_t arity, CallFrequency const& frequency = CallFrequency(),
|
||||||
FeedbackSource const& feedback = FeedbackSource(),
|
FeedbackSource const& feedback = FeedbackSource(),
|
||||||
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation);
|
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation,
|
||||||
|
CallFeedbackRelation feedback_relation = CallFeedbackRelation::kRelated);
|
||||||
const Operator* CallRuntime(Runtime::FunctionId id);
|
const Operator* CallRuntime(Runtime::FunctionId id);
|
||||||
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
|
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
|
||||||
const Operator* CallRuntime(const Runtime::Function* function, size_t arity);
|
const Operator* CallRuntime(const Runtime::Function* function, size_t arity);
|
||||||
|
@ -1804,8 +1804,9 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
|
|||||||
// Maybe we did at least learn something about the {receiver}.
|
// Maybe we did at least learn something about the {receiver}.
|
||||||
if (p.convert_mode() != convert_mode) {
|
if (p.convert_mode() != convert_mode) {
|
||||||
NodeProperties::ChangeOp(
|
NodeProperties::ChangeOp(
|
||||||
node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
|
node,
|
||||||
convert_mode, p.speculation_mode()));
|
javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
|
||||||
|
p.speculation_mode(), p.feedback_relation()));
|
||||||
return Changed(node);
|
return Changed(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2138,14 +2138,12 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
new_arguments.push_back(arguments[0]); // O
|
new_arguments.push_back(arguments[0]); // O
|
||||||
for (auto constant : callback.constants()) {
|
for (auto constant : callback.constants()) {
|
||||||
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
||||||
new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation,
|
|
||||||
kMissingArgumentsAreUndefined);
|
kMissingArgumentsAreUndefined);
|
||||||
}
|
}
|
||||||
for (auto blueprint : callback.function_blueprints()) {
|
for (auto blueprint : callback.function_blueprints()) {
|
||||||
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
|
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
|
||||||
new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation,
|
|
||||||
kMissingArgumentsAreUndefined);
|
kMissingArgumentsAreUndefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2165,14 +2163,12 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
new_arguments.push_back(arguments[0]); // O
|
new_arguments.push_back(arguments[0]); // O
|
||||||
for (auto constant : callback.constants()) {
|
for (auto constant : callback.constants()) {
|
||||||
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
||||||
new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation,
|
|
||||||
kMissingArgumentsAreUndefined);
|
kMissingArgumentsAreUndefined);
|
||||||
}
|
}
|
||||||
for (auto blueprint : callback.function_blueprints()) {
|
for (auto blueprint : callback.function_blueprints()) {
|
||||||
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
|
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
|
||||||
new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation,
|
|
||||||
kMissingArgumentsAreUndefined);
|
kMissingArgumentsAreUndefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2189,8 +2185,7 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
HintsVector new_arguments({new_receiver}, zone());
|
HintsVector new_arguments({new_receiver}, zone());
|
||||||
for (auto constant : arguments[0].constants()) {
|
for (auto constant : arguments[0].constants()) {
|
||||||
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
||||||
new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation,
|
|
||||||
kMissingArgumentsAreUnknown);
|
kMissingArgumentsAreUnknown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2222,9 +2217,9 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
HintsVector new_arguments(arguments.begin() + 1, arguments.end(),
|
HintsVector new_arguments(arguments.begin() + 1, arguments.end(),
|
||||||
zone());
|
zone());
|
||||||
for (auto constant : arguments[0].constants()) {
|
for (auto constant : arguments[0].constants()) {
|
||||||
ProcessCalleeForCallOrConstruct(
|
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
|
||||||
constant, base::nullopt, new_arguments,
|
new_arguments, speculation_mode,
|
||||||
SpeculationMode::kDisallowSpeculation, padding);
|
padding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
250
test/mjsunit/compiler/opt-higher-order-functions.js
Normal file
250
test/mjsunit/compiler/opt-higher-order-functions.js
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax --opt --no-always-opt
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
const mathAbs = Math.abs;
|
||||||
|
const mathImul = Math.imul;
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: FunctionPrototypeApply
|
||||||
|
function TestFunctionPrototypeApplyHelper() {
|
||||||
|
return mathAbs.apply(undefined, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TestFunctionPrototypeApply(x) {
|
||||||
|
return TestFunctionPrototypeApplyHelper(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestFunctionPrototypeApplyHelper);
|
||||||
|
%PrepareFunctionForOptimization(TestFunctionPrototypeApply);
|
||||||
|
assertEquals(TestFunctionPrototypeApply(-13), 13);
|
||||||
|
assertEquals(TestFunctionPrototypeApply(42), 42);
|
||||||
|
%OptimizeFunctionOnNextCall(TestFunctionPrototypeApply);
|
||||||
|
assertEquals(TestFunctionPrototypeApply(-13), 13);
|
||||||
|
assertOptimized(TestFunctionPrototypeApply);
|
||||||
|
TestFunctionPrototypeApply("abc");
|
||||||
|
assertUnoptimized(TestFunctionPrototypeApply);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: FunctionPrototypeCall
|
||||||
|
function TestFunctionPrototypeCall(x) {
|
||||||
|
return mathAbs.call(undefined, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestFunctionPrototypeCall);
|
||||||
|
TestFunctionPrototypeCall(42);
|
||||||
|
TestFunctionPrototypeCall(52);
|
||||||
|
%OptimizeFunctionOnNextCall(TestFunctionPrototypeCall);
|
||||||
|
TestFunctionPrototypeCall(12);
|
||||||
|
assertOptimized(TestFunctionPrototypeCall);
|
||||||
|
TestFunctionPrototypeCall("abc");
|
||||||
|
assertUnoptimized(TestFunctionPrototypeCall);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayForEach
|
||||||
|
function TestArrayForEach(x) {
|
||||||
|
x.forEach(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayForEach);
|
||||||
|
TestArrayForEach([1, 3, -4]);
|
||||||
|
TestArrayForEach([-9, 9, 0]);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayForEach);
|
||||||
|
TestArrayForEach([1, 3, -4]);
|
||||||
|
assertOptimized(TestArrayForEach);
|
||||||
|
TestArrayForEach(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayForEach);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayReduce
|
||||||
|
function TestArrayReduce(x) {
|
||||||
|
return x.reduce(mathImul);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayReduce);
|
||||||
|
assertEquals(TestArrayReduce([1, 2, -3, 4]), -24);
|
||||||
|
assertEquals(TestArrayReduce([3, 5, 7]), 105);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayReduce);
|
||||||
|
assertEquals(TestArrayReduce([1, 2, -3, 4]), -24);
|
||||||
|
assertOptimized(TestArrayReduce);
|
||||||
|
TestArrayReduce(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayReduce);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayReduceRight
|
||||||
|
function TestArrayReduceRight(x) {
|
||||||
|
return x.reduceRight(mathImul);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayReduceRight);
|
||||||
|
assertEquals(TestArrayReduceRight([1, 2, -3, 4]), -24);
|
||||||
|
assertEquals(TestArrayReduceRight([3, 5, 7]), 105);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayReduceRight);
|
||||||
|
assertEquals(TestArrayReduceRight([1, 2, -3, 4]), -24);
|
||||||
|
assertOptimized(TestArrayReduceRight);
|
||||||
|
TestArrayReduceRight(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayReduceRight);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayMap
|
||||||
|
function TestArrayMap(x) {
|
||||||
|
return x.map(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayMap);
|
||||||
|
assertEquals(TestArrayMap([1, -2, -3, 4]), [1, 2, 3, 4]);
|
||||||
|
assertEquals(TestArrayMap([5, -5, 5, -5]), [5, 5, 5, 5]);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayMap);
|
||||||
|
assertEquals(TestArrayMap([1, -2, 3, -4]), [1, 2, 3, 4]);
|
||||||
|
assertOptimized(TestArrayMap);
|
||||||
|
TestArrayMap(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayMap);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayFilter
|
||||||
|
function TestArrayFilter(x) {
|
||||||
|
return x.filter(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayFilter);
|
||||||
|
assertEquals(TestArrayFilter([-2, 0, 3, -4]), [-2, 3, -4]);
|
||||||
|
assertEquals(TestArrayFilter([0, 1, 1, 0]), [1, 1]);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayFilter);
|
||||||
|
assertEquals(TestArrayFilter([-2, 0, 3, -4]), [-2, 3, -4]);
|
||||||
|
assertOptimized(TestArrayFilter);
|
||||||
|
TestArrayFilter(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayFilter);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayFind
|
||||||
|
function TestArrayFind(x) {
|
||||||
|
return x.find(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayFind);
|
||||||
|
assertEquals(TestArrayFind([0, 0, -3, 12]), -3);
|
||||||
|
assertEquals(TestArrayFind([0, -18]), -18);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayFind);
|
||||||
|
assertEquals(TestArrayFind([0, 0, -3, 12]), -3);
|
||||||
|
assertOptimized(TestArrayFind);
|
||||||
|
TestArrayFind(["", "abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayFind);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayFindIndex
|
||||||
|
function TestArrayFindIndex(x) {
|
||||||
|
return x.findIndex(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayFindIndex);
|
||||||
|
assertEquals(TestArrayFindIndex([0, 0, -3, 12]), 2);
|
||||||
|
assertEquals(TestArrayFindIndex([0, -18]), 1);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayFindIndex);
|
||||||
|
assertEquals(TestArrayFindIndex([0, 0, -3, 12]), 2);
|
||||||
|
assertOptimized(TestArrayFindIndex);
|
||||||
|
TestArrayFindIndex(["", "abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayFindIndex);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArrayEvery
|
||||||
|
function TestArrayEvery(x) {
|
||||||
|
return x.every(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArrayEvery);
|
||||||
|
assertEquals(TestArrayEvery([3, 0, -9]), false);
|
||||||
|
assertEquals(TestArrayEvery([2, 12, -1]), true);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArrayEvery);
|
||||||
|
assertEquals(TestArrayEvery([3, 0, -9]), false);
|
||||||
|
assertOptimized(TestArrayEvery);
|
||||||
|
TestArrayEvery(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArrayEvery);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ArraySome
|
||||||
|
function TestArraySome(x) {
|
||||||
|
return x.some(mathAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestArraySome);
|
||||||
|
assertEquals(TestArraySome([3, 0, -9]), true);
|
||||||
|
assertEquals(TestArraySome([0, 0]), false);
|
||||||
|
%OptimizeFunctionOnNextCall(TestArraySome);
|
||||||
|
assertEquals(TestArraySome([3, 0, -9]), true);
|
||||||
|
assertOptimized(TestArraySome);
|
||||||
|
TestArraySome(["abc", "xy"]);
|
||||||
|
assertUnoptimized(TestArraySome);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: JSCall (JSFunction)
|
||||||
|
const boundMathImul = mathImul.bind(undefined, -3);
|
||||||
|
function TestJSCallWithJSFunction(x) {
|
||||||
|
return boundMathImul(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestJSCallWithJSFunction);
|
||||||
|
assertEquals(TestJSCallWithJSFunction(-14), 42);
|
||||||
|
assertEquals(TestJSCallWithJSFunction(14), -42);
|
||||||
|
%OptimizeFunctionOnNextCall(TestJSCallWithJSFunction);
|
||||||
|
assertEquals(TestJSCallWithJSFunction(-14), 42);
|
||||||
|
assertOptimized(TestJSCallWithJSFunction);
|
||||||
|
TestJSCallWithJSFunction("abc");
|
||||||
|
assertUnoptimized(TestJSCallWithJSFunction);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: JSCall (JSBoundFunction)
|
||||||
|
function TestJSCallWithJSBoundFunction(x) {
|
||||||
|
return mathImul.bind(undefined, -3)(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestJSCallWithJSBoundFunction);
|
||||||
|
assertEquals(TestJSCallWithJSBoundFunction(-14), 42);
|
||||||
|
assertEquals(TestJSCallWithJSBoundFunction(14), -42);
|
||||||
|
%OptimizeFunctionOnNextCall(TestJSCallWithJSBoundFunction);
|
||||||
|
assertEquals(TestJSCallWithJSBoundFunction(-14), 42);
|
||||||
|
assertOptimized(TestJSCallWithJSBoundFunction);
|
||||||
|
TestJSCallWithJSBoundFunction("abc");
|
||||||
|
assertUnoptimized(TestJSCallWithJSBoundFunction);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: ReflectApply
|
||||||
|
function TestReflectApplyHelper() {
|
||||||
|
return Reflect.apply(mathAbs, undefined, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TestReflectApply(x) {
|
||||||
|
return TestReflectApplyHelper(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestReflectApplyHelper);
|
||||||
|
%PrepareFunctionForOptimization(TestReflectApply);
|
||||||
|
assertEquals(TestReflectApply(-9), 9);
|
||||||
|
assertEquals(TestReflectApply(7), 7);
|
||||||
|
%OptimizeFunctionOnNextCall(TestReflectApply);
|
||||||
|
assertEquals(TestReflectApply(-9), 9);
|
||||||
|
assertOptimized(TestReflectApply);
|
||||||
|
TestReflectApply("abc");
|
||||||
|
assertUnoptimized(TestReflectApply);
|
||||||
|
|
||||||
|
|
||||||
|
// Testing: CallWithSpread
|
||||||
|
function TestCallWithSpreadHelper() {
|
||||||
|
return mathImul(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TestCallWithSpread(x) {
|
||||||
|
return TestCallWithSpreadHelper(x, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(TestCallWithSpreadHelper);
|
||||||
|
%PrepareFunctionForOptimization(TestCallWithSpread);
|
||||||
|
assertEquals(TestCallWithSpread(-13), 169);
|
||||||
|
assertEquals(TestCallWithSpread(7), 49);
|
||||||
|
%OptimizeFunctionOnNextCall(TestCallWithSpread);
|
||||||
|
assertEquals(TestCallWithSpread(-13), 169);
|
||||||
|
assertOptimized(TestCallWithSpread);
|
||||||
|
TestCallWithSpread("abc");
|
||||||
|
assertUnoptimized(TestCallWithSpread);
|
@ -1106,6 +1106,9 @@
|
|||||||
'compiler/diamond-followedby-branch': [SKIP],
|
'compiler/diamond-followedby-branch': [SKIP],
|
||||||
'compiler/load-elimination-const-field': [SKIP],
|
'compiler/load-elimination-const-field': [SKIP],
|
||||||
'compiler/constant-fold-add-static': [SKIP],
|
'compiler/constant-fold-add-static': [SKIP],
|
||||||
|
|
||||||
|
# Some tests rely on inlining.
|
||||||
|
'compiler/opt-higher-order-functions': [SKIP],
|
||||||
}], # variant == turboprop
|
}], # variant == turboprop
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
@ -115,9 +115,9 @@ class JSCallReducerTest : public TypedGraphTest {
|
|||||||
Handle<FeedbackVector> vector =
|
Handle<FeedbackVector> vector =
|
||||||
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
|
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
|
||||||
FeedbackSource feedback(vector, FeedbackSlot(0));
|
FeedbackSource feedback(vector, FeedbackSlot(0));
|
||||||
return javascript()->Call(arity, CallFrequency(), feedback,
|
return javascript()->Call(
|
||||||
ConvertReceiverMode::kAny,
|
arity, CallFrequency(), feedback, ConvertReceiverMode::kAny,
|
||||||
SpeculationMode::kAllowSpeculation);
|
SpeculationMode::kAllowSpeculation, CallFeedbackRelation::kRelated);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user