Use CommonNodeCache for heap constants in ChangeLowering.

TEST=compiler-unittests
R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23077 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-08-12 12:37:50 +00:00
parent d5f0ecfbd3
commit dae1e1ea01
10 changed files with 309 additions and 207 deletions

View File

@ -34,8 +34,11 @@ Node* ChangeLoweringBase::ExternalConstant(ExternalReference reference) {
Node* ChangeLoweringBase::HeapConstant(PrintableUnique<HeapObject> value) {
// TODO(bmeurer): Use common node cache.
return graph()->NewNode(common()->HeapConstant(value));
Node** loc = cache()->FindHeapConstant(value);
if (*loc == NULL) {
*loc = graph()->NewNode(common()->HeapConstant(value));
}
return *loc;
}

View File

@ -7,6 +7,7 @@
#include "src/assembler.h"
#include "src/compiler/node-cache.h"
#include "src/unique.h"
namespace v8 {
namespace internal {
@ -27,7 +28,8 @@ class CommonNodeCache V8_FINAL : public ZoneObject {
}
Node** FindExternalConstant(ExternalReference reference) {
return external_constants_.Find(zone_, reference.address());
return external_constants_.Find(
zone_, reinterpret_cast<intptr_t>(reference.address()));
}
Node** FindNumberConstant(double value) {
@ -35,17 +37,23 @@ class CommonNodeCache V8_FINAL : public ZoneObject {
return number_constants_.Find(zone_, BitCast<int64_t>(value));
}
Zone* zone() const { return zone_; }
Node** FindHeapConstant(PrintableUnique<HeapObject> object) {
return heap_constants_.Find(zone_, object.Hashcode());
}
private:
Int32NodeCache int32_constants_;
Int64NodeCache float64_constants_;
PtrNodeCache external_constants_;
IntPtrNodeCache external_constants_;
Int64NodeCache number_constants_;
IntPtrNodeCache heap_constants_;
Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(CommonNodeCache);
};
}
}
} // namespace v8::internal::compiler
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_COMMON_NODE_CACHE_H_

View File

@ -4,6 +4,8 @@
#include "src/compiler/node-cache.h"
#include "src/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
@ -12,35 +14,21 @@ namespace compiler {
#define LINEAR_PROBE 5
template <typename Key>
int32_t NodeCacheHash(Key key) {
UNIMPLEMENTED();
return 0;
}
inline int NodeCacheHash(Key key);
template <>
inline int32_t NodeCacheHash(int32_t key) {
inline int NodeCacheHash(int32_t key) {
return ComputeIntegerHash(key, 0);
}
template <>
inline int32_t NodeCacheHash(int64_t key) {
inline int NodeCacheHash(int64_t key) {
return ComputeLongHash(key);
}
template <>
inline int32_t NodeCacheHash(double key) {
return ComputeLongHash(BitCast<int64_t>(key));
}
template <>
inline int32_t NodeCacheHash(void* key) {
return ComputePointerHash(key);
}
template <typename Key>
bool NodeCache<Key>::Resize(Zone* zone) {
if (size_ >= max_) return false; // Don't grow past the maximum size.
@ -76,7 +64,7 @@ bool NodeCache<Key>::Resize(Zone* zone) {
template <typename Key>
Node** NodeCache<Key>::Find(Zone* zone, Key key) {
int32_t hash = NodeCacheHash(key);
int hash = NodeCacheHash(key);
if (entries_ == NULL) {
// Allocate the initial entries and insert the first entry.
int num_entries = INITIAL_SIZE + LINEAR_PROBE;
@ -112,9 +100,9 @@ Node** NodeCache<Key>::Find(Zone* zone, Key key) {
}
template class NodeCache<int64_t>;
template class NodeCache<int32_t>;
template class NodeCache<void*>;
}
}
} // namespace v8::internal::compiler
template class NodeCache<int64_t>;
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -5,14 +5,19 @@
#ifndef V8_COMPILER_NODE_CACHE_H_
#define V8_COMPILER_NODE_CACHE_H_
#include "src/v8.h"
#include "src/compiler/node.h"
#include "src/base/macros.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>
@ -36,18 +41,21 @@ class NodeCache {
};
Entry* entries_; // lazily-allocated hash entries.
int32_t size_;
int32_t max_;
int size_;
int max_;
bool Resize(Zone* zone);
DISALLOW_COPY_AND_ASSIGN(NodeCache);
};
// Various default cache types.
typedef NodeCache<int64_t> Int64NodeCache;
typedef NodeCache<int32_t> Int32NodeCache;
typedef NodeCache<void*> PtrNodeCache;
}
}
} // namespace v8::internal::compiler
typedef NodeCache<int64_t> Int64NodeCache;
typedef NodeCache<intptr_t> IntPtrNodeCache;
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_NODE_CACHE_H_

View File

@ -65,7 +65,6 @@
'compiler/test-linkage.cc',
'compiler/test-machine-operator-reducer.cc',
'compiler/test-node-algorithm.cc',
'compiler/test-node-cache.cc',
'compiler/test-node.cc',
'compiler/test-operator.cc',
'compiler/test-phi-reducer.cc',

View File

@ -1,160 +0,0 @@
// 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/v8.h"
#include "graph-tester.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/node-cache.h"
using namespace v8::internal;
using namespace v8::internal::compiler;
TEST(Int32Constant_back_to_back) {
GraphTester graph;
Int32NodeCache cache;
for (int i = -2000000000; i < 2000000000; i += 3315177) {
Node** pos = cache.Find(graph.zone(), i);
CHECK_NE(NULL, pos);
for (int j = 0; j < 3; j++) {
Node** npos = cache.Find(graph.zone(), i);
CHECK_EQ(pos, npos);
}
}
}
TEST(Int32Constant_five) {
GraphTester graph;
Int32NodeCache cache;
CommonOperatorBuilder common(graph.zone());
int32_t constants[] = {static_cast<int32_t>(0x80000000), -77, 0, 1, -1};
Node* nodes[ARRAY_SIZE(constants)];
for (size_t i = 0; i < ARRAY_SIZE(constants); i++) {
int32_t k = constants[i];
Node* node = graph.NewNode(common.Int32Constant(k));
*cache.Find(graph.zone(), k) = nodes[i] = node;
}
for (size_t i = 0; i < ARRAY_SIZE(constants); i++) {
int32_t k = constants[i];
CHECK_EQ(nodes[i], *cache.Find(graph.zone(), k));
}
}
TEST(Int32Constant_hits) {
GraphTester graph;
Int32NodeCache cache;
const int32_t kSize = 1500;
Node** nodes = graph.zone()->NewArray<Node*>(kSize);
CommonOperatorBuilder common(graph.zone());
for (int i = 0; i < kSize; i++) {
int32_t v = i * -55;
nodes[i] = graph.NewNode(common.Int32Constant(v));
*cache.Find(graph.zone(), v) = nodes[i];
}
int hits = 0;
for (int i = 0; i < kSize; i++) {
int32_t v = i * -55;
Node** pos = cache.Find(graph.zone(), v);
if (*pos != NULL) {
CHECK_EQ(nodes[i], *pos);
hits++;
}
}
CHECK_LT(4, hits);
}
TEST(Int64Constant_back_to_back) {
GraphTester graph;
Int64NodeCache cache;
for (int64_t i = -2000000000; i < 2000000000; i += 3315177) {
Node** pos = cache.Find(graph.zone(), i);
CHECK_NE(NULL, pos);
for (int j = 0; j < 3; j++) {
Node** npos = cache.Find(graph.zone(), i);
CHECK_EQ(pos, npos);
}
}
}
TEST(Int64Constant_hits) {
GraphTester graph;
Int64NodeCache cache;
const int32_t kSize = 1500;
Node** nodes = graph.zone()->NewArray<Node*>(kSize);
CommonOperatorBuilder common(graph.zone());
for (int i = 0; i < kSize; i++) {
int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001);
nodes[i] = graph.NewNode(common.Int32Constant(i));
*cache.Find(graph.zone(), v) = nodes[i];
}
int hits = 0;
for (int i = 0; i < kSize; i++) {
int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001);
Node** pos = cache.Find(graph.zone(), v);
if (*pos != NULL) {
CHECK_EQ(nodes[i], *pos);
hits++;
}
}
CHECK_LT(4, hits);
}
TEST(PtrConstant_back_to_back) {
GraphTester graph;
PtrNodeCache cache;
int32_t buffer[50];
for (int32_t* p = buffer;
(p - buffer) < static_cast<ptrdiff_t>(ARRAY_SIZE(buffer)); p++) {
Node** pos = cache.Find(graph.zone(), p);
CHECK_NE(NULL, pos);
for (int j = 0; j < 3; j++) {
Node** npos = cache.Find(graph.zone(), p);
CHECK_EQ(pos, npos);
}
}
}
TEST(PtrConstant_hits) {
GraphTester graph;
PtrNodeCache cache;
const int32_t kSize = 50;
int32_t buffer[kSize];
Node* nodes[kSize];
CommonOperatorBuilder common(graph.zone());
for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) {
int k = static_cast<int>(i);
int32_t* p = &buffer[i];
nodes[i] = graph.NewNode(common.Int32Constant(k));
*cache.Find(graph.zone(), p) = nodes[i];
}
int hits = 0;
for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) {
int32_t* p = &buffer[i];
Node** pos = cache.Find(graph.zone(), p);
if (*pos != NULL) {
CHECK_EQ(nodes[i], *pos);
hits++;
}
}
CHECK_LT(4, hits);
}

View File

@ -0,0 +1,125 @@
// 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/common-node-cache.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "test/compiler-unittests/compiler-unittests.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::AllOf;
using testing::IsNull;
using testing::NotNull;
using testing::Pointee;
namespace v8 {
namespace internal {
namespace compiler {
class CommonNodeCacheTest : public CompilerTest {
public:
CommonNodeCacheTest() : cache_(zone()), common_(zone()), graph_(zone()) {}
virtual ~CommonNodeCacheTest() {}
protected:
Factory* factory() const { return isolate()->factory(); }
CommonNodeCache* cache() { return &cache_; }
CommonOperatorBuilder* common() { return &common_; }
Graph* graph() { return &graph_; }
private:
CommonNodeCache cache_;
CommonOperatorBuilder common_;
Graph graph_;
};
TEST_F(CommonNodeCacheTest, FindInt32Constant) {
Node** l42 = cache()->FindInt32Constant(42);
ASSERT_THAT(l42, AllOf(NotNull(), Pointee(IsNull())));
Node* n42 = *l42 = graph()->NewNode(common()->Int32Constant(42));
Node** l0 = cache()->FindInt32Constant(0);
ASSERT_THAT(l0, AllOf(NotNull(), Pointee(IsNull())));
Node* n0 = *l0 = graph()->NewNode(common()->Int32Constant(0));
EXPECT_THAT(cache()->FindInt32Constant(42), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindInt32Constant(0), AllOf(l0, Pointee(n0)));
EXPECT_THAT(cache()->FindInt32Constant(42), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindInt32Constant(0), AllOf(l0, Pointee(n0)));
}
TEST_F(CommonNodeCacheTest, FindFloat64Constant) {
Node** l42 = cache()->FindFloat64Constant(42.0);
ASSERT_THAT(l42, AllOf(NotNull(), Pointee(IsNull())));
Node* n42 = *l42 = graph()->NewNode(common()->Float64Constant(42.0));
Node** l0 = cache()->FindFloat64Constant(0.0);
ASSERT_THAT(l0, AllOf(NotNull(), Pointee(IsNull())));
Node* n0 = *l0 = graph()->NewNode(common()->Float64Constant(0.0));
EXPECT_THAT(cache()->FindFloat64Constant(42.0), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindFloat64Constant(0.0), AllOf(l0, Pointee(n0)));
EXPECT_THAT(cache()->FindFloat64Constant(42.0), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindFloat64Constant(0.0), AllOf(l0, Pointee(n0)));
}
TEST_F(CommonNodeCacheTest, FindExternalConstant) {
ExternalReference i = ExternalReference::isolate_address(isolate());
Node** li = cache()->FindExternalConstant(i);
ASSERT_THAT(li, AllOf(NotNull(), Pointee(IsNull())));
Node* ni = *li = graph()->NewNode(common()->ExternalConstant(i));
ExternalReference m = ExternalReference::address_of_min_int();
Node** lm = cache()->FindExternalConstant(m);
ASSERT_THAT(lm, AllOf(NotNull(), Pointee(IsNull())));
Node* nm = *lm = graph()->NewNode(common()->ExternalConstant(m));
EXPECT_THAT(cache()->FindExternalConstant(i), AllOf(li, Pointee(ni)));
EXPECT_THAT(cache()->FindExternalConstant(m), AllOf(lm, Pointee(nm)));
EXPECT_THAT(cache()->FindExternalConstant(i), AllOf(li, Pointee(ni)));
EXPECT_THAT(cache()->FindExternalConstant(m), AllOf(lm, Pointee(nm)));
}
TEST_F(CommonNodeCacheTest, FindNumberConstant) {
Node** l42 = cache()->FindNumberConstant(42.0);
ASSERT_THAT(l42, AllOf(NotNull(), Pointee(IsNull())));
Node* n42 = *l42 = graph()->NewNode(common()->NumberConstant(42.0));
Node** l0 = cache()->FindNumberConstant(0.0);
ASSERT_THAT(l0, AllOf(NotNull(), Pointee(IsNull())));
Node* n0 = *l0 = graph()->NewNode(common()->NumberConstant(0.0));
EXPECT_THAT(cache()->FindNumberConstant(42.0), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindNumberConstant(0.0), AllOf(l0, Pointee(n0)));
EXPECT_THAT(cache()->FindNumberConstant(42.0), AllOf(l42, Pointee(n42)));
EXPECT_THAT(cache()->FindNumberConstant(0.0), AllOf(l0, Pointee(n0)));
}
TEST_F(CommonNodeCacheTest, FindHeapConstant) {
PrintableUnique<HeapObject> n = PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->null_value());
Node** ln = cache()->FindHeapConstant(n);
ASSERT_THAT(ln, AllOf(NotNull(), Pointee(IsNull())));
Node* nn = *ln = graph()->NewNode(common()->HeapConstant(n));
PrintableUnique<HeapObject> t = PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->true_value());
Node** lt = cache()->FindHeapConstant(t);
ASSERT_THAT(lt, AllOf(NotNull(), Pointee(IsNull())));
Node* nt = *lt = graph()->NewNode(common()->HeapConstant(t));
EXPECT_THAT(cache()->FindHeapConstant(n), AllOf(ln, Pointee(nn)));
EXPECT_THAT(cache()->FindHeapConstant(t), AllOf(lt, Pointee(nt)));
EXPECT_THAT(cache()->FindHeapConstant(n), AllOf(ln, Pointee(nn)));
EXPECT_THAT(cache()->FindHeapConstant(t), AllOf(lt, Pointee(nt)));
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -21,8 +21,10 @@
],
'sources': [ ### gcmole(all) ###
'change-lowering-unittest.cc',
'common-node-cache-unittest.cc',
'compiler-unittests.cc',
'instruction-selector-unittest.cc',
'node-cache-unittest.cc',
'node-matchers.cc',
'node-matchers.h',
],

View File

@ -0,0 +1,129 @@
// 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 <algorithm>
#include "src/base/utils/random-number-generator.h"
#include "src/compiler/node.h"
#include "src/compiler/node-cache.h"
#include "src/flags.h"
#include "test/compiler-unittests/compiler-unittests.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest-type-names.h"
using testing::AllOf;
using testing::IsNull;
using testing::NotNull;
using testing::Pointee;
namespace v8 {
namespace internal {
namespace compiler {
template <typename T>
class NodeCacheTest : public CompilerTest {
public:
NodeCacheTest() : rng_(FLAG_random_seed) {}
virtual ~NodeCacheTest() {}
protected:
NodeCache<T>* cache() { return &cache_; }
base::RandomNumberGenerator* rng() { return &rng_; }
void GenerateRandom(T* first, T* last) {
for (T* i = first; i != last; ++i) {
do {
*i = GenerateRandom();
} while (std::find(first, i, *i) != i);
}
}
private:
T GenerateRandom();
NodeCache<T> cache_;
base::RandomNumberGenerator rng_;
};
template <>
int32_t NodeCacheTest<int32_t>::GenerateRandom() {
return rng()->NextInt();
}
template <>
int64_t NodeCacheTest<int64_t>::GenerateRandom() {
int64_t v;
rng()->NextBytes(&v, sizeof(v));
return v;
}
typedef ::testing::Types<int32_t, int64_t> NodeCacheTypes;
TYPED_TEST_CASE(NodeCacheTest, NodeCacheTypes);
TYPED_TEST(NodeCacheTest, BackToBack) {
static const size_t kSize = 100;
TypeParam values[kSize];
this->GenerateRandom(&values[0], &values[kSize]);
for (const TypeParam* i = &values[0]; i != &values[kSize]; ++i) {
TypeParam value = *i;
SCOPED_TRACE(::testing::Message() << "value " << value);
Node** location = this->cache()->Find(this->zone(), value);
ASSERT_THAT(location, AllOf(NotNull(), Pointee(IsNull())));
for (int attempt = 1; attempt < 4; ++attempt) {
SCOPED_TRACE(::testing::Message() << "attempt " << attempt);
EXPECT_EQ(location, this->cache()->Find(this->zone(), value));
}
}
}
TYPED_TEST(NodeCacheTest, MinimumSize) {
static const size_t kSize = 5;
TypeParam values[kSize];
this->GenerateRandom(&values[0], &values[kSize]);
Node** locations[kSize];
Node* nodes = this->zone()->template NewArray<Node>(kSize);
for (size_t i = 0; i < kSize; ++i) {
locations[i] = this->cache()->Find(this->zone(), values[i]);
ASSERT_THAT(locations[i], NotNull());
EXPECT_EQ(&locations[i],
std::find(&locations[0], &locations[i], locations[i]));
*locations[i] = &nodes[i];
}
for (size_t i = 0; i < kSize; ++i) {
EXPECT_EQ(locations[i], this->cache()->Find(this->zone(), values[i]));
}
}
TYPED_TEST(NodeCacheTest, MinimumHits) {
static const size_t kSize = 250;
static const size_t kMinHits = 10;
TypeParam* values = this->zone()->template NewArray<TypeParam>(kSize);
this->GenerateRandom(&values[0], &values[kSize]);
Node* nodes = this->zone()->template NewArray<Node>(kSize);
for (size_t i = 0; i < kSize; ++i) {
Node** location = this->cache()->Find(this->zone(), values[i]);
ASSERT_THAT(location, AllOf(NotNull(), Pointee(IsNull())));
*location = &nodes[i];
}
size_t hits = 0;
for (size_t i = 0; i < kSize; ++i) {
Node** location = this->cache()->Find(this->zone(), values[i]);
ASSERT_THAT(location, NotNull());
if (*location != NULL) {
EXPECT_EQ(&nodes[i], *location);
++hits;
}
}
EXPECT_GE(hits, kMinHits);
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -11,10 +11,10 @@
namespace testing {
namespace internal {
#define GET_TYPE_NAME(type) \
template <> \
std::string GetTypeName<type>() { \
return #type; \
#define GET_TYPE_NAME(type) \
template <> \
inline std::string GetTypeName<type>() { \
return #type; \
}
GET_TYPE_NAME(int8_t)
GET_TYPE_NAME(uint8_t)