[interpreter] Record type feedback in the handlers for Inc and Dec.
BUG=v8:5273 R=rmcilroy@chromium.org Review-Url: https://codereview.chromium.org/2250513005 Cr-Commit-Position: refs/heads/master@{#38751}
This commit is contained in:
parent
870763f5ce
commit
6949acab5c
@ -2382,7 +2382,9 @@ compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler,
|
||||
// static
|
||||
compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
|
||||
compiler::Node* value,
|
||||
compiler::Node* context) {
|
||||
compiler::Node* context,
|
||||
compiler::Node* type_feedback_vector,
|
||||
compiler::Node* slot_id) {
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
@ -2394,8 +2396,12 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
|
||||
// We might need to try again due to ToNumber conversion.
|
||||
Variable value_var(assembler, MachineRepresentation::kTagged);
|
||||
Variable result_var(assembler, MachineRepresentation::kTagged);
|
||||
Label start(assembler, &value_var);
|
||||
Variable var_type_feedback(assembler, MachineRepresentation::kWord32);
|
||||
Variable* loop_vars[] = {&value_var, &var_type_feedback};
|
||||
Label start(assembler, 2, loop_vars);
|
||||
value_var.Bind(value);
|
||||
var_type_feedback.Bind(
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kNone));
|
||||
assembler->Goto(&start);
|
||||
assembler->Bind(&start);
|
||||
{
|
||||
@ -2416,6 +2422,9 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
|
||||
assembler->Branch(overflow, &if_overflow, &if_notoverflow);
|
||||
|
||||
assembler->Bind(&if_notoverflow);
|
||||
var_type_feedback.Bind(assembler->Word32Or(
|
||||
var_type_feedback.value(),
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)));
|
||||
result_var.Bind(assembler->Projection(0, pair));
|
||||
assembler->Goto(&end);
|
||||
|
||||
@ -2448,6 +2457,8 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
|
||||
// Convert to a Number first and try again.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_type_feedback.Bind(
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kAny));
|
||||
value_var.Bind(assembler->CallStub(callable, context, value));
|
||||
assembler->Goto(&start);
|
||||
}
|
||||
@ -2459,18 +2470,25 @@ compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
|
||||
Node* finc_value = var_finc_value.value();
|
||||
Node* one = assembler->Float64Constant(1.0);
|
||||
Node* finc_result = assembler->Float64Add(finc_value, one);
|
||||
var_type_feedback.Bind(assembler->Word32Or(
|
||||
var_type_feedback.value(),
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kNumber)));
|
||||
result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result));
|
||||
assembler->Goto(&end);
|
||||
}
|
||||
|
||||
assembler->Bind(&end);
|
||||
assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector,
|
||||
slot_id);
|
||||
return result_var.value();
|
||||
}
|
||||
|
||||
// static
|
||||
compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
|
||||
compiler::Node* value,
|
||||
compiler::Node* context) {
|
||||
compiler::Node* context,
|
||||
compiler::Node* type_feedback_vector,
|
||||
compiler::Node* slot_id) {
|
||||
typedef CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
typedef CodeStubAssembler::Variable Variable;
|
||||
@ -2482,7 +2500,11 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
|
||||
// We might need to try again due to ToNumber conversion.
|
||||
Variable value_var(assembler, MachineRepresentation::kTagged);
|
||||
Variable result_var(assembler, MachineRepresentation::kTagged);
|
||||
Label start(assembler, &value_var);
|
||||
Variable var_type_feedback(assembler, MachineRepresentation::kWord32);
|
||||
Variable* loop_vars[] = {&value_var, &var_type_feedback};
|
||||
Label start(assembler, 2, loop_vars);
|
||||
var_type_feedback.Bind(
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kNone));
|
||||
value_var.Bind(value);
|
||||
assembler->Goto(&start);
|
||||
assembler->Bind(&start);
|
||||
@ -2504,6 +2526,9 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
|
||||
assembler->Branch(overflow, &if_overflow, &if_notoverflow);
|
||||
|
||||
assembler->Bind(&if_notoverflow);
|
||||
var_type_feedback.Bind(assembler->Word32Or(
|
||||
var_type_feedback.value(),
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kSignedSmall)));
|
||||
result_var.Bind(assembler->Projection(0, pair));
|
||||
assembler->Goto(&end);
|
||||
|
||||
@ -2536,6 +2561,8 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
|
||||
// Convert to a Number first and try again.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_type_feedback.Bind(
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kAny));
|
||||
value_var.Bind(assembler->CallStub(callable, context, value));
|
||||
assembler->Goto(&start);
|
||||
}
|
||||
@ -2547,11 +2574,16 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
|
||||
Node* fdec_value = var_fdec_value.value();
|
||||
Node* one = assembler->Float64Constant(1.0);
|
||||
Node* fdec_result = assembler->Float64Sub(fdec_value, one);
|
||||
var_type_feedback.Bind(assembler->Word32Or(
|
||||
var_type_feedback.value(),
|
||||
assembler->Int32Constant(BinaryOperationFeedback::kNumber)));
|
||||
result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result));
|
||||
assembler->Goto(&end);
|
||||
}
|
||||
|
||||
assembler->Bind(&end);
|
||||
assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector,
|
||||
slot_id);
|
||||
return result_var.value();
|
||||
}
|
||||
|
||||
|
@ -462,6 +462,19 @@ class CodeStub BASE_EMBEDDED {
|
||||
} \
|
||||
DEFINE_CODE_STUB(NAME, SUPER)
|
||||
|
||||
#define DEFINE_TURBOFAN_UNARY_OP_CODE_STUB_WITH_FEEDBACK(NAME, SUPER) \
|
||||
public: \
|
||||
static compiler::Node* Generate( \
|
||||
CodeStubAssembler* assembler, compiler::Node* value, \
|
||||
compiler::Node* context, compiler::Node* type_feedback_vector, \
|
||||
compiler::Node* slot_id); \
|
||||
void GenerateAssembly(CodeStubAssembler* assembler) const override { \
|
||||
assembler->Return( \
|
||||
Generate(assembler, assembler->Parameter(0), assembler->Parameter(1), \
|
||||
assembler->Parameter(2), assembler->Parameter(3))); \
|
||||
} \
|
||||
DEFINE_CODE_STUB(NAME, SUPER)
|
||||
|
||||
#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
|
||||
public: \
|
||||
Handle<Code> GenerateCode() override; \
|
||||
@ -895,7 +908,7 @@ class IncStub final : public TurboFanCodeStub {
|
||||
explicit IncStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(CountOp);
|
||||
DEFINE_TURBOFAN_UNARY_OP_CODE_STUB(Inc, TurboFanCodeStub);
|
||||
DEFINE_TURBOFAN_UNARY_OP_CODE_STUB_WITH_FEEDBACK(Inc, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class DecStub final : public TurboFanCodeStub {
|
||||
@ -903,7 +916,7 @@ class DecStub final : public TurboFanCodeStub {
|
||||
explicit DecStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(CountOp);
|
||||
DEFINE_TURBOFAN_UNARY_OP_CODE_STUB(Dec, TurboFanCodeStub);
|
||||
DEFINE_TURBOFAN_UNARY_OP_CODE_STUB_WITH_FEEDBACK(Dec, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class InstanceOfStub final : public TurboFanCodeStub {
|
||||
|
@ -1215,6 +1215,18 @@ BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint() {
|
||||
return hint;
|
||||
}
|
||||
|
||||
BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHintForIncDec() {
|
||||
FeedbackVectorSlot slot =
|
||||
feedback_vector()->ToSlot(bytecode_iterator().GetIndexOperand(0));
|
||||
DCHECK_EQ(FeedbackVectorSlotKind::GENERAL, feedback_vector()->GetKind(slot));
|
||||
Object* feedback = feedback_vector()->Get(slot);
|
||||
BinaryOperationHint hint = BinaryOperationHint::kAny;
|
||||
if (feedback->IsSmi()) {
|
||||
hint = BinaryOperationHintFromFeedback((Smi::cast(feedback))->value());
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitAdd() {
|
||||
BuildBinaryOp(javascript()->Add(GetBinaryOperationHint()));
|
||||
}
|
||||
@ -1302,15 +1314,17 @@ void BytecodeGraphBuilder::VisitInc() {
|
||||
FrameStateBeforeAndAfter states(this);
|
||||
// Note: Use subtract -1 here instead of add 1 to ensure we always convert to
|
||||
// a number, not a string.
|
||||
const Operator* js_op = javascript()->Subtract(BinaryOperationHint::kAny);
|
||||
const Operator* js_op =
|
||||
javascript()->Subtract(GetBinaryOperationHintForIncDec());
|
||||
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
|
||||
jsgraph()->Constant(-1.0));
|
||||
jsgraph()->Constant(-1));
|
||||
environment()->BindAccumulator(node, &states);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitDec() {
|
||||
FrameStateBeforeAndAfter states(this);
|
||||
const Operator* js_op = javascript()->Subtract(BinaryOperationHint::kAny);
|
||||
const Operator* js_op =
|
||||
javascript()->Subtract(GetBinaryOperationHintForIncDec());
|
||||
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
|
||||
jsgraph()->OneConstant());
|
||||
environment()->BindAccumulator(node, &states);
|
||||
|
@ -139,6 +139,10 @@ class BytecodeGraphBuilder {
|
||||
// type feedback.
|
||||
BinaryOperationHint GetBinaryOperationHint();
|
||||
|
||||
// Helper function to create an binary operation hint from the recorded
|
||||
// type feedback in Inc/Dec handlers.
|
||||
BinaryOperationHint GetBinaryOperationHintForIncDec();
|
||||
|
||||
// Control flow plumbing.
|
||||
void BuildJump();
|
||||
void BuildConditionalJump(Node* condition);
|
||||
|
@ -1119,6 +1119,18 @@ void Interpreter::DoUnaryOp(InterpreterAssembler* assembler) {
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
template <class Generator>
|
||||
void Interpreter::DoUnaryOpWithFeedback(InterpreterAssembler* assembler) {
|
||||
Node* value = __ GetAccumulator();
|
||||
Node* context = __ GetContext();
|
||||
Node* slot_index = __ BytecodeOperandIdx(0);
|
||||
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
|
||||
Node* result = Generator::Generate(assembler, value, context,
|
||||
type_feedback_vector, slot_index);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
// ToName
|
||||
//
|
||||
// Cast the object referenced by the accumulator to a name.
|
||||
@ -1150,14 +1162,14 @@ void Interpreter::DoToObject(InterpreterAssembler* assembler) {
|
||||
//
|
||||
// Increments value in the accumulator by one.
|
||||
void Interpreter::DoInc(InterpreterAssembler* assembler) {
|
||||
DoUnaryOp<IncStub>(assembler);
|
||||
DoUnaryOpWithFeedback<IncStub>(assembler);
|
||||
}
|
||||
|
||||
// Dec
|
||||
//
|
||||
// Decrements value in the accumulator by one.
|
||||
void Interpreter::DoDec(InterpreterAssembler* assembler) {
|
||||
DoUnaryOp<DecStub>(assembler);
|
||||
DoUnaryOpWithFeedback<DecStub>(assembler);
|
||||
}
|
||||
|
||||
// LogicalNot
|
||||
|
@ -97,6 +97,11 @@ class Interpreter {
|
||||
template <class Generator>
|
||||
void DoUnaryOp(InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform the unary operation via |Generator| while
|
||||
// gatering type feedback.
|
||||
template <class Generator>
|
||||
void DoUnaryOpWithFeedback(InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform the comparison operation associated with
|
||||
// |compare_op|.
|
||||
void DoCompareOp(Token::Value compare_op, InterpreterAssembler* assembler);
|
||||
|
@ -509,6 +509,229 @@ TEST(InterpreterParameter8) {
|
||||
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
|
||||
}
|
||||
|
||||
TEST(InterpreterBinaryOpTypeFeedback) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
i::Zone zone(isolate->allocator());
|
||||
|
||||
struct BinaryOpExpectation {
|
||||
Token::Value op;
|
||||
Handle<Object> arg1;
|
||||
Handle<Object> arg2;
|
||||
Handle<Object> result;
|
||||
int32_t feedback;
|
||||
};
|
||||
|
||||
BinaryOpExpectation const kTestCases[] = {
|
||||
// ADD
|
||||
{Token::Value::ADD, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(5), isolate),
|
||||
BinaryOperationFeedback::kSignedSmall},
|
||||
{Token::Value::ADD, Handle<Smi>(Smi::FromInt(Smi::kMaxValue), isolate),
|
||||
Handle<Smi>(Smi::FromInt(1), isolate),
|
||||
isolate->factory()->NewHeapNumber(Smi::kMaxValue + 1.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::ADD, isolate->factory()->NewHeapNumber(3.1415),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewHeapNumber(3.1415 + 3),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::ADD, isolate->factory()->NewHeapNumber(3.1415),
|
||||
isolate->factory()->NewHeapNumber(1.4142),
|
||||
isolate->factory()->NewHeapNumber(3.1415 + 1.4142),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::ADD, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewStringFromAsciiChecked("2"),
|
||||
isolate->factory()->NewStringFromAsciiChecked("22"),
|
||||
BinaryOperationFeedback::kAny},
|
||||
// SUB
|
||||
{Token::Value::SUB, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(-1), isolate),
|
||||
BinaryOperationFeedback::kSignedSmall},
|
||||
{Token::Value::SUB, Handle<Smi>(Smi::FromInt(Smi::kMinValue), isolate),
|
||||
Handle<Smi>(Smi::FromInt(1), isolate),
|
||||
isolate->factory()->NewHeapNumber(Smi::kMinValue - 1.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::SUB, isolate->factory()->NewHeapNumber(3.1415),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewHeapNumber(3.1415 - 3),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::SUB, isolate->factory()->NewHeapNumber(3.1415),
|
||||
isolate->factory()->NewHeapNumber(1.4142),
|
||||
isolate->factory()->NewHeapNumber(3.1415 - 1.4142),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::SUB, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewStringFromAsciiChecked("1"),
|
||||
Handle<Smi>(Smi::FromInt(1), isolate), BinaryOperationFeedback::kAny},
|
||||
// MUL
|
||||
{Token::Value::MUL, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(6), isolate),
|
||||
BinaryOperationFeedback::kSignedSmall},
|
||||
{Token::Value::MUL, Handle<Smi>(Smi::FromInt(Smi::kMinValue), isolate),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewHeapNumber(Smi::kMinValue * 2.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MUL, isolate->factory()->NewHeapNumber(3.1415),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewHeapNumber(3 * 3.1415),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MUL, isolate->factory()->NewHeapNumber(3.1415),
|
||||
isolate->factory()->NewHeapNumber(1.4142),
|
||||
isolate->factory()->NewHeapNumber(3.1415 * 1.4142),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MUL, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewStringFromAsciiChecked("1"),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate), BinaryOperationFeedback::kAny},
|
||||
// DIV
|
||||
{Token::Value::DIV, Handle<Smi>(Smi::FromInt(6), isolate),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
BinaryOperationFeedback::kSignedSmall},
|
||||
{Token::Value::DIV, Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewHeapNumber(3.0 / 2.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::DIV, isolate->factory()->NewHeapNumber(3.1415),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewHeapNumber(3.1415 / 3),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::DIV, isolate->factory()->NewHeapNumber(3.1415),
|
||||
isolate->factory()->NewHeapNumber(
|
||||
-std::numeric_limits<double>::infinity()),
|
||||
isolate->factory()->NewHeapNumber(-0.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::DIV, Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewStringFromAsciiChecked("1"),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate), BinaryOperationFeedback::kAny},
|
||||
// MOD
|
||||
{Token::Value::MOD, Handle<Smi>(Smi::FromInt(5), isolate),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
BinaryOperationFeedback::kSignedSmall},
|
||||
{Token::Value::MOD, Handle<Smi>(Smi::FromInt(-4), isolate),
|
||||
Handle<Smi>(Smi::FromInt(2), isolate),
|
||||
isolate->factory()->NewHeapNumber(-0.0),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MOD, isolate->factory()->NewHeapNumber(3.1415),
|
||||
Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewHeapNumber(fmod(3.1415, 3.0)),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MOD, isolate->factory()->NewHeapNumber(-3.1415),
|
||||
isolate->factory()->NewHeapNumber(-1.4142),
|
||||
isolate->factory()->NewHeapNumber(fmod(-3.1415, -1.4142)),
|
||||
BinaryOperationFeedback::kNumber},
|
||||
{Token::Value::MOD, Handle<Smi>(Smi::FromInt(3), isolate),
|
||||
isolate->factory()->NewStringFromAsciiChecked("-2"),
|
||||
Handle<Smi>(Smi::FromInt(1), isolate), BinaryOperationFeedback::kAny}};
|
||||
|
||||
for (const BinaryOpExpectation& test_case : kTestCases) {
|
||||
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 1);
|
||||
|
||||
i::FeedbackVectorSpec feedback_spec(&zone);
|
||||
i::FeedbackVectorSlot slot0 = feedback_spec.AddGeneralSlot();
|
||||
|
||||
Handle<i::TypeFeedbackVector> vector =
|
||||
i::NewTypeFeedbackVector(isolate, &feedback_spec);
|
||||
|
||||
Register reg(0);
|
||||
builder.LoadLiteral(test_case.arg1)
|
||||
.StoreAccumulatorInRegister(reg)
|
||||
.LoadLiteral(test_case.arg2)
|
||||
.BinaryOperation(test_case.op, reg, vector->GetIndex(slot0))
|
||||
.Return();
|
||||
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
|
||||
|
||||
InterpreterTester tester(isolate, bytecode_array, vector);
|
||||
auto callable = tester.GetCallable<>();
|
||||
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
Object* feedback0 = vector->Get(slot0);
|
||||
CHECK(feedback0->IsSmi());
|
||||
CHECK_EQ(test_case.feedback, static_cast<Smi*>(feedback0)->value());
|
||||
CHECK(Object::Equals(test_case.result, return_val).ToChecked());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InterpreterUnaryOpFeedback) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
i::Zone zone(isolate->allocator());
|
||||
|
||||
Handle<Smi> smi_one = Handle<Smi>(Smi::FromInt(1), isolate);
|
||||
Handle<Smi> smi_max = Handle<Smi>(Smi::FromInt(Smi::kMaxValue), isolate);
|
||||
Handle<Smi> smi_min = Handle<Smi>(Smi::FromInt(Smi::kMinValue), isolate);
|
||||
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(2.1);
|
||||
Handle<String> str = isolate->factory()->NewStringFromAsciiChecked("42");
|
||||
|
||||
struct TestCase {
|
||||
Token::Value op;
|
||||
Handle<Smi> smi_feedback_value;
|
||||
Handle<Smi> smi_to_number_feedback_value;
|
||||
Handle<HeapNumber> number_feedback_value;
|
||||
Handle<Object> any_feedback_value;
|
||||
};
|
||||
TestCase const kTestCases[] = {
|
||||
{Token::Value::ADD, smi_one, smi_max, number, str},
|
||||
{Token::Value::SUB, smi_one, smi_min, number, str}};
|
||||
for (TestCase const& test_case : kTestCases) {
|
||||
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 4, 0, 0);
|
||||
|
||||
i::FeedbackVectorSpec feedback_spec(&zone);
|
||||
i::FeedbackVectorSlot slot0 = feedback_spec.AddGeneralSlot();
|
||||
i::FeedbackVectorSlot slot1 = feedback_spec.AddGeneralSlot();
|
||||
i::FeedbackVectorSlot slot2 = feedback_spec.AddGeneralSlot();
|
||||
i::FeedbackVectorSlot slot3 = feedback_spec.AddGeneralSlot();
|
||||
|
||||
Handle<i::TypeFeedbackVector> vector =
|
||||
i::NewTypeFeedbackVector(isolate, &feedback_spec);
|
||||
|
||||
builder.LoadAccumulatorWithRegister(builder.Parameter(0))
|
||||
.CountOperation(test_case.op, vector->GetIndex(slot0))
|
||||
.LoadAccumulatorWithRegister(builder.Parameter(1))
|
||||
.CountOperation(test_case.op, vector->GetIndex(slot1))
|
||||
.LoadAccumulatorWithRegister(builder.Parameter(2))
|
||||
.CountOperation(test_case.op, vector->GetIndex(slot2))
|
||||
.LoadAccumulatorWithRegister(builder.Parameter(3))
|
||||
.CountOperation(test_case.op, vector->GetIndex(slot3))
|
||||
.Return();
|
||||
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
|
||||
|
||||
InterpreterTester tester(isolate, bytecode_array, vector);
|
||||
typedef Handle<Object> H;
|
||||
auto callable = tester.GetCallable<H, H, H, H>();
|
||||
|
||||
Handle<Object> return_val =
|
||||
callable(test_case.smi_feedback_value,
|
||||
test_case.smi_to_number_feedback_value,
|
||||
test_case.number_feedback_value, test_case.any_feedback_value)
|
||||
.ToHandleChecked();
|
||||
USE(return_val);
|
||||
Object* feedback0 = vector->Get(slot0);
|
||||
CHECK(feedback0->IsSmi());
|
||||
CHECK_EQ(BinaryOperationFeedback::kSignedSmall,
|
||||
static_cast<Smi*>(feedback0)->value());
|
||||
|
||||
Object* feedback1 = vector->Get(slot1);
|
||||
CHECK(feedback1->IsSmi());
|
||||
CHECK_EQ(BinaryOperationFeedback::kNumber,
|
||||
static_cast<Smi*>(feedback1)->value());
|
||||
|
||||
Object* feedback2 = vector->Get(slot2);
|
||||
CHECK(feedback2->IsSmi());
|
||||
CHECK_EQ(BinaryOperationFeedback::kNumber,
|
||||
static_cast<Smi*>(feedback2)->value());
|
||||
|
||||
Object* feedback3 = vector->Get(slot3);
|
||||
CHECK(feedback3->IsSmi());
|
||||
CHECK_EQ(BinaryOperationFeedback::kAny,
|
||||
static_cast<Smi*>(feedback3)->value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InterpreterBitwiseTypeFeedback) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
|
Loading…
Reference in New Issue
Block a user