Commit cd6631ad authored by mlippautz's avatar mlippautz Committed by Commit bot

Add template parameter and unittests to atomic utils.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#30589}
parent df966cd2
......@@ -13,22 +13,76 @@
namespace v8 {
namespace internal {
template <class T>
class AtomicNumber {
public:
AtomicNumber() : value_(0) {}
explicit AtomicNumber(T initial) : value_(initial) {}
V8_INLINE void Increment(T increment) {
base::NoBarrier_AtomicIncrement(&value_,
static_cast<base::AtomicWord>(increment));
}
V8_INLINE T Value() { return static_cast<T>(base::NoBarrier_Load(&value_)); }
V8_INLINE void SetValue(T new_value) {
base::NoBarrier_Store(&value_, static_cast<base::AtomicWord>(new_value));
}
private:
STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
base::AtomicWord value_;
};
// Flag using T atomically. Also accepts void* as T.
template <typename T>
class AtomicValue {
public:
AtomicValue() : value_(0) {}
explicit AtomicValue(base::AtomicWord initial) : value_(initial) {}
explicit AtomicValue(T initial)
: value_(cast_helper<T>::to_storage_type(initial)) {}
V8_INLINE void Increment(base::AtomicWord increment) {
base::NoBarrier_AtomicIncrement(&value_, increment);
V8_INLINE T Value() {
return cast_helper<T>::to_return_type(base::NoBarrier_Load(&value_));
}
V8_INLINE base::AtomicWord Value() { return base::NoBarrier_Load(&value_); }
V8_INLINE bool TrySetValue(T old_value, T new_value) {
return base::NoBarrier_CompareAndSwap(
&value_, cast_helper<T>::to_storage_type(old_value),
cast_helper<T>::to_storage_type(new_value)) ==
cast_helper<T>::to_storage_type(old_value);
}
V8_INLINE void SetValue(base::AtomicWord new_value) {
base::NoBarrier_Store(&value_, new_value);
V8_INLINE T /*old_value*/ SetValue(T new_value) {
return cast_helper<T>::to_return_type(base::NoBarrier_AtomicExchange(
&value_, cast_helper<T>::to_storage_type(new_value)));
}
private:
STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
template <typename S>
struct cast_helper {
static base::AtomicWord to_storage_type(S value) {
return static_cast<base::AtomicWord>(value);
}
static S to_return_type(base::AtomicWord value) {
return static_cast<S>(value);
}
};
template <typename S>
struct cast_helper<S*> {
static base::AtomicWord to_storage_type(S* value) {
return reinterpret_cast<base::AtomicWord>(value);
}
static S* to_return_type(base::AtomicWord value) {
return reinterpret_cast<S*>(value);
}
};
base::AtomicWord value_;
};
......@@ -82,7 +136,7 @@ class AtomicEnumSet {
void Add(const AtomicEnumSet& set) { ATOMIC_SET_WRITE(|, set.ToIntegral()); }
void Remove(E element) { ATOMIC_SET_WRITE(&, Mask(element)); }
void Remove(E element) { ATOMIC_SET_WRITE(&, ~Mask(element)); }
void Remove(const AtomicEnumSet& set) {
ATOMIC_SET_WRITE(&, ~set.ToIntegral());
......@@ -109,26 +163,6 @@ class AtomicEnumSet {
base::AtomicWord bits_;
};
// Flag using enums atomically.
template <class E>
class AtomicEnumFlag {
public:
explicit AtomicEnumFlag(E initial) : value_(initial) {}
V8_INLINE E Value() { return static_cast<E>(base::NoBarrier_Load(&value_)); }
V8_INLINE bool TrySetValue(E old_value, E new_value) {
return base::NoBarrier_CompareAndSwap(
&value_, static_cast<base::AtomicWord>(old_value),
static_cast<base::AtomicWord>(new_value)) ==
static_cast<base::AtomicWord>(old_value);
}
private:
base::AtomicWord value_;
};
} // namespace internal
} // namespace v8
......
......@@ -2138,7 +2138,7 @@ class Heap {
// This is not the depth of nested AlwaysAllocateScope's but rather a single
// count, as scopes can be acquired from multiple tasks (read: threads).
AtomicValue always_allocate_scope_count_;
AtomicNumber<size_t> always_allocate_scope_count_;
// For keeping track of context disposals.
int contexts_disposed_;
......
// 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 <limits.h>
#include "src/atomic-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
TEST(AtomicNumber, Constructor) {
// Test some common types.
AtomicNumber<int> zero_int;
AtomicNumber<size_t> zero_size_t;
AtomicNumber<intptr_t> zero_intptr_t;
EXPECT_EQ(0, zero_int.Value());
EXPECT_EQ(0, zero_size_t.Value());
EXPECT_EQ(0, zero_intptr_t.Value());
}
TEST(AtomicNumber, Value) {
AtomicNumber<int> a(1);
EXPECT_EQ(1, a.Value());
AtomicNumber<int> b(-1);
EXPECT_EQ(-1, b.Value());
AtomicNumber<size_t> c(1);
EXPECT_EQ(1, c.Value());
AtomicNumber<size_t> d(static_cast<size_t>(-1));
EXPECT_EQ(std::numeric_limits<size_t>::max(), d.Value());
}
TEST(AtomicNumber, SetValue) {
AtomicNumber<int> a(1);
a.SetValue(-1);
EXPECT_EQ(-1, a.Value());
}
TEST(AtomicNumber, Increment) {
AtomicNumber<int> a(std::numeric_limits<int>::max());
a.Increment(1);
EXPECT_EQ(std::numeric_limits<int>::min(), a.Value());
// Check that potential signed-ness of the underlying storage has no impact
// on unsigned types.
AtomicNumber<size_t> b(std::numeric_limits<intptr_t>::max());
b.Increment(1);
EXPECT_EQ(static_cast<size_t>(std::numeric_limits<intptr_t>::max()) + 1,
b.Value());
// Should work as decrement as well.
AtomicNumber<size_t> c(1);
c.Increment(-1);
EXPECT_EQ(0, c.Value());
c.Increment(-1);
EXPECT_EQ(std::numeric_limits<size_t>::max(), c.Value());
}
namespace {
enum TestFlag {
kA,
kB,
kC,
};
} // namespace
TEST(AtomicValue, Initial) {
AtomicValue<TestFlag> a(kA);
EXPECT_EQ(TestFlag::kA, a.Value());
}
TEST(AtomicValue, TrySetValue) {
AtomicValue<TestFlag> a(kA);
EXPECT_FALSE(a.TrySetValue(kB, kC));
EXPECT_TRUE(a.TrySetValue(kA, kC));
EXPECT_EQ(TestFlag::kC, a.Value());
}
TEST(AtomicValue, SetValue) {
AtomicValue<TestFlag> a(kB);
EXPECT_EQ(kB, a.SetValue(kC));
EXPECT_EQ(TestFlag::kC, a.Value());
}
TEST(AtomicValue, WithVoidStar) {
AtomicValue<void*> a(nullptr);
AtomicValue<void*> dummy(nullptr);
EXPECT_EQ(nullptr, a.Value());
EXPECT_EQ(nullptr, a.SetValue(&a));
EXPECT_EQ(&a, a.Value());
EXPECT_FALSE(a.TrySetValue(nullptr, &dummy));
EXPECT_TRUE(a.TrySetValue(&a, &dummy));
EXPECT_EQ(&dummy, a.Value());
}
namespace {
enum TestSetValue { kAA, kBB, kCC, kLastValue = kCC };
} // namespace
TEST(AtomicEnumSet, Constructor) {
AtomicEnumSet<TestSetValue> a;
EXPECT_TRUE(a.IsEmpty());
EXPECT_FALSE(a.Contains(kAA));
}
TEST(AtomicEnumSet, AddSingle) {
AtomicEnumSet<TestSetValue> a;
a.Add(kAA);
EXPECT_FALSE(a.IsEmpty());
EXPECT_TRUE(a.Contains(kAA));
EXPECT_FALSE(a.Contains(kBB));
EXPECT_FALSE(a.Contains(kCC));
}
TEST(AtomicEnumSet, AddOtherSet) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
EXPECT_FALSE(a.IsEmpty());
EXPECT_TRUE(b.IsEmpty());
b.Add(a);
EXPECT_FALSE(b.IsEmpty());
EXPECT_TRUE(a.Contains(kAA));
EXPECT_TRUE(b.Contains(kAA));
}
TEST(AtomicEnumSet, RemoveSingle) {
AtomicEnumSet<TestSetValue> a;
a.Add(kAA);
a.Add(kBB);
EXPECT_TRUE(a.Contains(kAA));
EXPECT_TRUE(a.Contains(kBB));
a.Remove(kAA);
EXPECT_FALSE(a.Contains(kAA));
EXPECT_TRUE(a.Contains(kBB));
}
TEST(AtomicEnumSet, RemoveOtherSet) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
a.Add(kBB);
b.Add(kBB);
a.Remove(b);
EXPECT_TRUE(a.Contains(kAA));
EXPECT_FALSE(a.Contains(kBB));
EXPECT_FALSE(a.Contains(kCC));
}
TEST(AtomicEnumSet, RemoveEmptySet) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
a.Add(kBB);
EXPECT_TRUE(a.Contains(kAA));
EXPECT_TRUE(a.Contains(kBB));
EXPECT_FALSE(a.Contains(kCC));
EXPECT_TRUE(b.IsEmpty());
a.Remove(b);
EXPECT_TRUE(a.Contains(kAA));
EXPECT_TRUE(a.Contains(kBB));
EXPECT_FALSE(a.Contains(kCC));
}
TEST(AtomicEnumSet, Intersect) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
b.Add(kCC);
a.Intersect(b);
EXPECT_TRUE(a.IsEmpty());
}
TEST(AtomicEnumSet, ContainsAnyOf) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
b.Add(kCC);
EXPECT_FALSE(a.ContainsAnyOf(b));
b.Add(kAA);
EXPECT_TRUE(a.ContainsAnyOf(b));
}
TEST(AtomicEnumSet, Equality) {
AtomicEnumSet<TestSetValue> a;
AtomicEnumSet<TestSetValue> b;
a.Add(kAA);
EXPECT_FALSE(a == b);
EXPECT_TRUE(a != b);
b.Add(kAA);
EXPECT_TRUE(a == b);
EXPECT_FALSE(a != b);
}
} // namespace internal
} // namespace v8
......@@ -27,6 +27,7 @@
'V8_IMMINENT_DEPRECATION_WARNINGS',
],
'sources': [ ### gcmole(all) ###
'atomic-utils-unittest.cc',
'base/bits-unittest.cc',
'base/cpu-unittest.cc',
'base/division-by-constant-unittest.cc',
......
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