fb54e570e1
The motivation is to avoid bugs such as the one fixed in https://chromium-review.googlesource.com/c/v8/v8/+/800270. Bug: v8:7109 Change-Id: I82a55f4a78d289d00ae7bafe78b45d92bab07a6b Reviewed-on: https://chromium-review.googlesource.com/800291 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Michael Achenbach <machenbach@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#49829}
234 lines
6.9 KiB
C++
234 lines
6.9 KiB
C++
// Copyright 2014 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.
|
|
|
|
#include "src/compiler/state-values-utils.h"
|
|
#include "src/bit-vector.h"
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class StateValuesIteratorTest : public GraphTest {
|
|
public:
|
|
StateValuesIteratorTest() : GraphTest(3) {}
|
|
|
|
Node* StateValuesFromVector(NodeVector* nodes) {
|
|
int count = static_cast<int>(nodes->size());
|
|
return graph()->NewNode(
|
|
common()->StateValues(count, SparseInputMask::Dense()), count,
|
|
count == 0 ? nullptr : &(nodes->front()));
|
|
}
|
|
};
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, SimpleIteration) {
|
|
NodeVector inputs(zone());
|
|
const int count = 10;
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(count, i);
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, EmptyIteration) {
|
|
NodeVector inputs(zone());
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
bool empty = true;
|
|
for (auto node : StateValuesAccess(state_values)) {
|
|
USE(node);
|
|
empty = false;
|
|
}
|
|
EXPECT_TRUE(empty);
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, NestedIteration) {
|
|
NodeVector inputs(zone());
|
|
int count = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
if (i == 2) {
|
|
// Single nested in index 2.
|
|
NodeVector nested_inputs(zone());
|
|
for (int j = 0; j < 8; j++) {
|
|
nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
inputs.push_back(StateValuesFromVector(&nested_inputs));
|
|
} else if (i == 5) {
|
|
// Double nested at index 5.
|
|
NodeVector nested_inputs(zone());
|
|
for (int j = 0; j < 8; j++) {
|
|
if (j == 7) {
|
|
NodeVector doubly_nested_inputs(zone());
|
|
for (int k = 0; k < 2; k++) {
|
|
doubly_nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
nested_inputs.push_back(StateValuesFromVector(&doubly_nested_inputs));
|
|
} else {
|
|
nested_inputs.push_back(Int32Constant(count++));
|
|
}
|
|
}
|
|
inputs.push_back(StateValuesFromVector(&nested_inputs));
|
|
} else {
|
|
inputs.push_back(Int32Constant(count++));
|
|
}
|
|
}
|
|
Node* state_values = StateValuesFromVector(&inputs);
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(count, i);
|
|
}
|
|
|
|
|
|
TEST_F(StateValuesIteratorTest, TreeFromVector) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
|
|
// Build the tree.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* values_node = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
|
|
// Check the tree contents with vector.
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
i++;
|
|
}
|
|
EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, TreeFromVectorWithLiveness) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
// Generate the input liveness.
|
|
BitVector liveness(count, zone());
|
|
for (int i = 0; i < count; i++) {
|
|
if (i % 3 == 0) {
|
|
liveness.Add(i);
|
|
}
|
|
}
|
|
|
|
// Build the tree.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* values_node = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
|
|
// Check the tree contents with vector.
|
|
int i = 0;
|
|
for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) {
|
|
if (liveness.Contains(i)) {
|
|
EXPECT_THAT(node.node, IsInt32Constant(i));
|
|
} else {
|
|
EXPECT_EQ(node.node, nullptr);
|
|
}
|
|
i++;
|
|
}
|
|
EXPECT_EQ(inputs.size(), static_cast<size_t>(i));
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, BuildTreeIdentical) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
|
|
// Build two trees from the same data.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* node1 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
Node* node2 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
nullptr);
|
|
|
|
// The trees should be equal since the data was the same.
|
|
EXPECT_EQ(node1, node2);
|
|
}
|
|
}
|
|
|
|
TEST_F(StateValuesIteratorTest, BuildTreeWithLivenessIdentical) {
|
|
int sizes[] = {0, 1, 2, 100, 5000, 30000};
|
|
TRACED_FOREACH(int, count, sizes) {
|
|
JSOperatorBuilder javascript(zone());
|
|
MachineOperatorBuilder machine(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
|
|
&machine);
|
|
|
|
// Generate the input vector.
|
|
NodeVector inputs(zone());
|
|
for (int i = 0; i < count; i++) {
|
|
inputs.push_back(Int32Constant(i));
|
|
}
|
|
// Generate the input liveness.
|
|
BitVector liveness(count, zone());
|
|
for (int i = 0; i < count; i++) {
|
|
if (i % 3 == 0) {
|
|
liveness.Add(i);
|
|
}
|
|
}
|
|
|
|
// Build two trees from the same data.
|
|
StateValuesCache builder(&jsgraph);
|
|
Node* node1 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
Node* node2 = builder.GetNodeForValues(
|
|
inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size(),
|
|
&liveness);
|
|
|
|
// The trees should be equal since the data was the same.
|
|
EXPECT_EQ(node1, node2);
|
|
}
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|