Add JSGraph::GetCachedNodes and NodeCache::GetCachedNodes. These routines are necessary in the dead code elimination phase to trim away uses from unreachable nodes.

R=bmeurer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/656103002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24632 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
titzer@chromium.org 2014-10-15 12:29:39 +00:00
parent 23868b419c
commit 754abff699
7 changed files with 272 additions and 9 deletions

View File

@ -41,6 +41,14 @@ class CommonNodeCache FINAL : public ZoneObject {
Zone* zone() const { return zone_; }
void GetCachedNodes(NodeVector* nodes) {
int32_constants_.GetCachedNodes(nodes);
int64_constants_.GetCachedNodes(nodes);
float64_constants_.GetCachedNodes(nodes);
external_constants_.GetCachedNodes(nodes);
number_constants_.GetCachedNodes(nodes);
}
private:
Int32NodeCache int32_constants_;
Int64NodeCache int64_constants_;

View File

@ -191,6 +191,18 @@ Node* JSGraph::ExternalConstant(ExternalReference reference) {
return *loc;
}
void JSGraph::GetCachedNodes(NodeVector* nodes) {
cache_.GetCachedNodes(nodes);
SetOncePointer<Node>* ptrs[] = {
&c_entry_stub_constant_, &undefined_constant_, &the_hole_constant_,
&true_constant_, &false_constant_, &null_constant_,
&zero_constant_, &one_constant_, &nan_constant_};
for (size_t i = 0; i < arraysize(ptrs); i++) {
if (ptrs[i]->is_set()) nodes->push_back(ptrs[i]->get());
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -103,12 +103,15 @@ class JSGraph : public ZoneObject {
Zone* zone() { return graph()->zone(); }
Isolate* isolate() { return zone()->isolate(); }
void GetCachedNodes(NodeVector* nodes);
private:
Graph* graph_;
CommonOperatorBuilder* common_;
JSOperatorBuilder* javascript_;
MachineOperatorBuilder* machine_;
// TODO(titzer): make this into a simple array.
SetOncePointer<Node> c_entry_stub_constant_;
SetOncePointer<Node> undefined_constant_;
SetOncePointer<Node> the_hole_constant_;

View File

@ -7,6 +7,7 @@
#include <cstring>
#include "src/zone.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
@ -90,6 +91,15 @@ Node** NodeCache<Key, Hash, Pred>::Find(Zone* zone, Key key) {
}
template <typename Key, typename Hash, typename Pred>
void NodeCache<Key, Hash, Pred>::GetCachedNodes(NodeVector* nodes) {
if (entries_) {
for (size_t i = 0; i < size_; i++) {
if (entries_[i].value_ != NULL) nodes->push_back(entries_[i].value_);
}
}
}
template class NodeCache<int64_t>;
template class NodeCache<int32_t>;
template class NodeCache<void*>;

View File

@ -7,20 +7,12 @@
#include "src/base/functional.h"
#include "src/base/macros.h"
#include "src/compiler/node.h"
namespace v8 {
namespace internal {
// Forward declarations.
class Zone;
namespace compiler {
// Forward declarations.
class Node;
// A cache for nodes based on a key. Useful for implementing canonicalization of
// nodes such as constants, parameters, etc.
template <typename Key, typename Hash = base::hash<Key>,
@ -39,6 +31,8 @@ class NodeCache FINAL {
// too full or encounters too many hash collisions.
Node** Find(Zone* zone, Key key);
void GetCachedNodes(NodeVector* nodes);
private:
enum { kInitialSize = 16u, kLinearProbe = 5u };

View File

@ -4,6 +4,7 @@
#include "src/v8.h"
#include "src/assembler.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties-inl.h"
#include "src/compiler/typer.h"
@ -30,6 +31,7 @@ class JSCacheTesterHelper {
};
// TODO(dcarney): JSConstantCacheTester inherits from JSGraph???
class JSConstantCacheTester : public HandleAndZoneScope,
public JSCacheTesterHelper,
public JSGraph {
@ -293,3 +295,177 @@ TEST(OddballTypes) {
TEST(ExternalReferences) {
// TODO(titzer): test canonicalization of external references.
}
static bool Contains(NodeVector* nodes, Node* n) {
for (size_t i = 0; i < nodes->size(); i++) {
if (nodes->at(i) == n) return true;
}
return false;
}
static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) {
NodeVector nodes(T->main_zone());
T->GetCachedNodes(&nodes);
CHECK(Contains(&nodes, n));
}
TEST(JSGraph_GetCachedNodes1) {
JSConstantCacheTester T;
CheckGetCachedNodesContains(&T, T.TrueConstant());
CheckGetCachedNodesContains(&T, T.UndefinedConstant());
CheckGetCachedNodesContains(&T, T.TheHoleConstant());
CheckGetCachedNodesContains(&T, T.TrueConstant());
CheckGetCachedNodesContains(&T, T.FalseConstant());
CheckGetCachedNodesContains(&T, T.NullConstant());
CheckGetCachedNodesContains(&T, T.ZeroConstant());
CheckGetCachedNodesContains(&T, T.OneConstant());
CheckGetCachedNodesContains(&T, T.NaNConstant());
}
TEST(JSGraph_GetCachedNodes_int32) {
JSConstantCacheTester T;
int32_t constants[] = {0, 11, 12, 13, 14, 55, -55, -44, -33, -22, -11,
0, 11, 11, 12, 12, 11, 11, -33, -33, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int count_before = T.graph()->NodeCount();
NodeVector nodes_before(T.main_zone());
T.GetCachedNodes(&nodes_before);
Node* n = T.Int32Constant(constants[i]);
if (n->id() < count_before) {
// An old ID indicates a cached node. It should have been in the set.
CHECK(Contains(&nodes_before, n));
}
// Old or new, it should be in the cached set afterwards.
CheckGetCachedNodesContains(&T, n);
}
}
TEST(JSGraph_GetCachedNodes_float64) {
JSConstantCacheTester T;
double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4,
-33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3,
11, 11, -33.3, -33.3, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int count_before = T.graph()->NodeCount();
NodeVector nodes_before(T.main_zone());
T.GetCachedNodes(&nodes_before);
Node* n = T.Float64Constant(constants[i]);
if (n->id() < count_before) {
// An old ID indicates a cached node. It should have been in the set.
CHECK(Contains(&nodes_before, n));
}
// Old or new, it should be in the cached set afterwards.
CheckGetCachedNodesContains(&T, n);
}
}
TEST(JSGraph_GetCachedNodes_int64) {
JSConstantCacheTester T;
int32_t constants[] = {0, 11, 12, 13, 14, 55, -55, -44, -33, -22, -11,
0, 11, 11, 12, 12, 11, 11, -33, -33, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int count_before = T.graph()->NodeCount();
NodeVector nodes_before(T.main_zone());
T.GetCachedNodes(&nodes_before);
Node* n = T.Int64Constant(constants[i]);
if (n->id() < count_before) {
// An old ID indicates a cached node. It should have been in the set.
CHECK(Contains(&nodes_before, n));
}
// Old or new, it should be in the cached set afterwards.
CheckGetCachedNodesContains(&T, n);
}
}
TEST(JSGraph_GetCachedNodes_number) {
JSConstantCacheTester T;
double constants[] = {0, 11.1, 12.2, 13, 14, 55.5, -55.5, -44.4,
-33, -22, -11, 0, 11.1, 11.1, 12.3, 12.3,
11, 11, -33.3, -33.3, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int count_before = T.graph()->NodeCount();
NodeVector nodes_before(T.main_zone());
T.GetCachedNodes(&nodes_before);
Node* n = T.Constant(constants[i]);
if (n->id() < count_before) {
// An old ID indicates a cached node. It should have been in the set.
CHECK(Contains(&nodes_before, n));
}
// Old or new, it should be in the cached set afterwards.
CheckGetCachedNodesContains(&T, n);
}
}
TEST(JSGraph_GetCachedNodes_external) {
JSConstantCacheTester T;
ExternalReference constants[] = {ExternalReference::address_of_min_int(),
ExternalReference::address_of_min_int(),
ExternalReference::address_of_min_int(),
ExternalReference::address_of_one_half(),
ExternalReference::address_of_one_half(),
ExternalReference::address_of_min_int(),
ExternalReference::address_of_the_hole_nan(),
ExternalReference::address_of_one_half()};
for (size_t i = 0; i < arraysize(constants); i++) {
int count_before = T.graph()->NodeCount();
NodeVector nodes_before(T.main_zone());
T.GetCachedNodes(&nodes_before);
Node* n = T.ExternalConstant(constants[i]);
if (n->id() < count_before) {
// An old ID indicates a cached node. It should have been in the set.
CHECK(Contains(&nodes_before, n));
}
// Old or new, it should be in the cached set afterwards.
CheckGetCachedNodesContains(&T, n);
}
}
TEST(JSGraph_GetCachedNodes_together) {
JSConstantCacheTester T;
Node* constants[] = {
T.TrueConstant(),
T.UndefinedConstant(),
T.TheHoleConstant(),
T.TrueConstant(),
T.FalseConstant(),
T.NullConstant(),
T.ZeroConstant(),
T.OneConstant(),
T.NaNConstant(),
T.Int32Constant(0),
T.Int32Constant(1),
T.Int64Constant(-2),
T.Int64Constant(-4),
T.Float64Constant(0.9),
T.Float64Constant(V8_INFINITY),
T.Constant(0.99),
T.Constant(1.11),
T.ExternalConstant(ExternalReference::address_of_one_half())};
NodeVector nodes(T.main_zone());
T.GetCachedNodes(&nodes);
for (size_t i = 0; i < arraysize(constants); i++) {
CHECK(Contains(&nodes, constants[i]));
}
}

View File

@ -158,3 +158,63 @@ TEST(PtrConstant_hits) {
}
CHECK_LT(4, hits);
}
static bool Contains(NodeVector* nodes, Node* n) {
for (size_t i = 0; i < nodes->size(); i++) {
if (nodes->at(i) == n) return true;
}
return false;
}
TEST(NodeCache_GetCachedNodes_int32) {
GraphTester graph;
Int32NodeCache cache;
CommonOperatorBuilder common(graph.zone());
int32_t constants[] = {0, 311, 12, 13, 14, 555, -555, -44, -33, -22, -11,
0, 311, 311, 412, 412, 11, 11, -33, -33, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int32_t k = constants[i];
Node** pos = cache.Find(graph.zone(), k);
if (*pos != NULL) {
NodeVector nodes(graph.zone());
cache.GetCachedNodes(&nodes);
CHECK(Contains(&nodes, *pos));
} else {
NodeVector nodes(graph.zone());
Node* n = graph.NewNode(common.Int32Constant(k));
*pos = n;
cache.GetCachedNodes(&nodes);
CHECK(Contains(&nodes, n));
}
}
}
TEST(NodeCache_GetCachedNodes_int64) {
GraphTester graph;
Int64NodeCache cache;
CommonOperatorBuilder common(graph.zone());
int64_t constants[] = {0, 311, 12, 13, 14, 555, -555, -44, -33, -22, -11,
0, 311, 311, 412, 412, 11, 11, -33, -33, -22, -11};
for (size_t i = 0; i < arraysize(constants); i++) {
int64_t k = constants[i];
Node** pos = cache.Find(graph.zone(), k);
if (*pos != NULL) {
NodeVector nodes(graph.zone());
cache.GetCachedNodes(&nodes);
CHECK(Contains(&nodes, *pos));
} else {
NodeVector nodes(graph.zone());
Node* n = graph.NewNode(common.Int64Constant(k));
*pos = n;
cache.GetCachedNodes(&nodes);
CHECK(Contains(&nodes, n));
}
}
}