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,
FeedbackSource feedback = CreateFeedbackSource(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
const Operator* op = javascript()->Call(arg_count, frequency, feedback,
receiver_mode, speculation_mode);
const Operator* op =
javascript()->Call(arg_count, frequency, feedback, receiver_mode,
speculation_mode, CallFeedbackRelation::kRelated);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
op, args, static_cast<int>(arg_count), feedback.slot);
......@@ -2415,8 +2416,9 @@ void BytecodeGraphBuilder::VisitCallWithSpread() {
int const slot_id = bytecode_iterator().GetIndexOperand(3);
FeedbackSource feedback = CreateFeedbackSource(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
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(
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);
}
// 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 internal
} // namespace v8
......
This diff is collapsed.
......@@ -7,6 +7,7 @@
#include "src/base/flags.h"
#include "src/compiler/frame-states.h"
#include "src/compiler/globals.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/node-properties.h"
#include "src/deoptimizer/deoptimize-reason.h"
......@@ -106,7 +107,8 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency,
FeedbackSource const& feedback);
FeedbackSource const& feedback, SpeculationMode speculation_mode,
CallFeedbackRelation feedback_relation);
Reduction ReduceJSConstruct(Node* node);
Reduction ReduceJSConstructWithArrayLike(Node* node);
Reduction ReduceJSConstructWithSpread(Node* node);
......
......@@ -1439,7 +1439,8 @@ Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) {
: feedback.AsCall().speculation_mode();
const Operator* call_op =
javascript()->Call(2, CallFrequency(), p.callFeedback(),
ConvertReceiverMode::kNotNullOrUndefined, mode);
ConvertReceiverMode::kNotNullOrUndefined, mode,
CallFeedbackRelation::kRelated);
Node* call_property = graph()->NewNode(call_op, load_property, receiver,
context, frame_state, effect, control);
effect = call_property;
......
......@@ -23,8 +23,7 @@ std::ostream& operator<<(std::ostream& os, CallFrequency const& f) {
}
CallFrequency CallFrequencyOf(Operator const* op) {
DCHECK(op->opcode() == IrOpcode::kJSCallWithArrayLike ||
op->opcode() == IrOpcode::kJSConstructWithArrayLike);
DCHECK_EQ(op->opcode(), IrOpcode::kJSConstructWithArrayLike);
return OpParameter<CallFrequency>(op);
}
......@@ -66,11 +65,13 @@ ConstructParameters const& ConstructParametersOf(Operator const* op) {
}
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) {
DCHECK(op->opcode() == IrOpcode::kJSCall ||
op->opcode() == IrOpcode::kJSCallWithArrayLike ||
op->opcode() == IrOpcode::kJSCallWithSpread);
return OpParameter<CallParameters>(op);
}
......@@ -882,15 +883,12 @@ const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity,
parameters); // parameter
}
const Operator* JSOperatorBuilder::Call(size_t arity,
CallFrequency const& frequency,
FeedbackSource const& feedback,
ConvertReceiverMode convert_mode,
SpeculationMode speculation_mode) {
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
feedback.IsValid());
const Operator* JSOperatorBuilder::Call(
size_t arity, CallFrequency const& frequency,
FeedbackSource const& feedback, ConvertReceiverMode convert_mode,
SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation) {
CallParameters parameters(arity, frequency, feedback, convert_mode,
speculation_mode);
speculation_mode, feedback_relation);
return new (zone()) Operator1<CallParameters>( // --
IrOpcode::kJSCall, Operator::kNoProperties, // opcode
"JSCall", // name
......@@ -899,21 +897,26 @@ const Operator* JSOperatorBuilder::Call(size_t arity,
}
const Operator* JSOperatorBuilder::CallWithArrayLike(
CallFrequency const& frequency) {
return new (zone()) Operator1<CallFrequency>( // --
const CallFrequency& frequency, const FeedbackSource& feedback,
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
"JSCallWithArrayLike", // name
3, 1, 1, 1, 1, 2, // counts
frequency); // parameter
parameters); // parameter
}
const Operator* JSOperatorBuilder::CallWithSpread(
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,
feedback.IsValid());
CallParameters parameters(arity, frequency, feedback,
ConvertReceiverMode::kAny, speculation_mode);
ConvertReceiverMode::kAny, speculation_mode,
feedback_relation);
return new (zone()) Operator1<CallParameters>( // --
IrOpcode::kJSCallWithSpread, Operator::kNoProperties, // opcode
"JSCallWithSpread", // name
......
......@@ -165,12 +165,20 @@ class CallParameters final {
CallParameters(size_t arity, CallFrequency const& frequency,
FeedbackSource const& feedback,
ConvertReceiverMode convert_mode,
SpeculationMode speculation_mode)
SpeculationMode speculation_mode,
CallFeedbackRelation feedback_relation)
: bit_field_(ArityField::encode(arity) |
CallFeedbackRelationField::encode(feedback_relation) |
SpeculationModeField::encode(speculation_mode) |
ConvertReceiverModeField::encode(convert_mode)),
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_); }
CallFrequency const& frequency() const { return frequency_; }
......@@ -183,6 +191,10 @@ class CallParameters final {
return SpeculationModeField::decode(bit_field_);
}
CallFeedbackRelation feedback_relation() const {
return CallFeedbackRelationField::decode(bit_field_);
}
bool operator==(CallParameters const& that) const {
return this->bit_field_ == that.bit_field_ &&
this->frequency_ == that.frequency_ &&
......@@ -197,7 +209,8 @@ class CallParameters final {
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 ConvertReceiverModeField = BitField<ConvertReceiverMode, 29, 2>;
......@@ -815,12 +828,19 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
size_t arity, CallFrequency const& frequency = CallFrequency(),
FeedbackSource const& feedback = FeedbackSource(),
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny,
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation);
const Operator* CallWithArrayLike(CallFrequency const& frequency);
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation,
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(
uint32_t arity, CallFrequency const& frequency = CallFrequency(),
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, 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}.
if (p.convert_mode() != convert_mode) {
NodeProperties::ChangeOp(
node, javascript()->Call(p.arity(), p.frequency(), p.feedback(),
convert_mode, p.speculation_mode()));
node,
javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
p.speculation_mode(), p.feedback_relation()));
return Changed(node);
}
......
......@@ -2138,14 +2138,12 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
new_arguments.push_back(arguments[0]); // O
for (auto constant : callback.constants()) {
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
new_arguments,
SpeculationMode::kDisallowSpeculation,
new_arguments, speculation_mode,
kMissingArgumentsAreUndefined);
}
for (auto blueprint : callback.function_blueprints()) {
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
new_arguments,
SpeculationMode::kDisallowSpeculation,
new_arguments, speculation_mode,
kMissingArgumentsAreUndefined);
}
}
......@@ -2165,14 +2163,12 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
new_arguments.push_back(arguments[0]); // O
for (auto constant : callback.constants()) {
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
new_arguments,
SpeculationMode::kDisallowSpeculation,
new_arguments, speculation_mode,
kMissingArgumentsAreUndefined);
}
for (auto blueprint : callback.function_blueprints()) {
ProcessCalleeForCallOrConstruct(Callee(blueprint), base::nullopt,
new_arguments,
SpeculationMode::kDisallowSpeculation,
new_arguments, speculation_mode,
kMissingArgumentsAreUndefined);
}
}
......@@ -2189,8 +2185,7 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
HintsVector new_arguments({new_receiver}, zone());
for (auto constant : arguments[0].constants()) {
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
new_arguments,
SpeculationMode::kDisallowSpeculation,
new_arguments, speculation_mode,
kMissingArgumentsAreUnknown);
}
}
......@@ -2222,9 +2217,9 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
HintsVector new_arguments(arguments.begin() + 1, arguments.end(),
zone());
for (auto constant : arguments[0].constants()) {
ProcessCalleeForCallOrConstruct(
constant, base::nullopt, new_arguments,
SpeculationMode::kDisallowSpeculation, padding);
ProcessCalleeForCallOrConstruct(constant, base::nullopt,
new_arguments, speculation_mode,
padding);
}
}
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 @@
'compiler/diamond-followedby-branch': [SKIP],
'compiler/load-elimination-const-field': [SKIP],
'compiler/constant-fold-add-static': [SKIP],
# Some tests rely on inlining.
'compiler/opt-higher-order-functions': [SKIP],
}], # variant == turboprop
##############################################################################
......
......@@ -115,9 +115,9 @@ class JSCallReducerTest : public TypedGraphTest {
Handle<FeedbackVector> vector =
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
FeedbackSource feedback(vector, FeedbackSlot(0));
return javascript()->Call(arity, CallFrequency(), feedback,
ConvertReceiverMode::kAny,
SpeculationMode::kAllowSpeculation);
return javascript()->Call(
arity, CallFrequency(), feedback, ConvertReceiverMode::kAny,
SpeculationMode::kAllowSpeculation, CallFeedbackRelation::kRelated);
}
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