Commit 149e4935 authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

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: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64733}
parent 0ec75c91
...@@ -2231,8 +2231,9 @@ void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode, ...@@ -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() { ...@@ -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) { ...@@ -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
......
This diff is collapsed.
...@@ -7,6 +7,7 @@ ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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) { ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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;
......
// 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 @@ ...@@ -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 { ...@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment