--- /dev/null 2017-03-07 11:44:12.271151064 +0100 +++ new/test/native/runtime/test_atomic.cpp 2017-07-17 10:39:53.418135418 +0200 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/atomic.hpp" +#include "utilities/macros.hpp" +#include "unittest.hpp" + +#include + +struct AtomicShortAddTest: public testing::Test { + ATOMIC_SHORT_PAIR( + volatile int16_t _atomic, + int16_t _not_atomic + ); + + void add_max() { + Atomic::add(std::numeric_limits::max(), &_atomic); + } + + void sub_max() { + Atomic::add(std::numeric_limits::min(), &_atomic); + } + + AtomicShortAddTest() : _atomic(0), _not_atomic(0) {} +}; + +// This test tests whether the neighbouring short will be +// touched by an overflow. +TEST_VM_F(AtomicShortAddTest, test_short_add_overflow) { + EXPECT_EQ(_atomic, 0); + EXPECT_EQ(_not_atomic, 0); + add_max(); + EXPECT_EQ(_atomic, std::numeric_limits::max()); + EXPECT_EQ(_not_atomic, 0); + add_max(); + EXPECT_EQ(_not_atomic, 0); +} + +// This test tests whether the neighbouring short will be +// touched by an underflow. +TEST_VM_F(AtomicShortAddTest, test_short_add_underflow) { + EXPECT_EQ(0, _atomic); + EXPECT_EQ(_not_atomic, 0); + sub_max(); + EXPECT_EQ(_atomic, std::numeric_limits::min()); + EXPECT_EQ(_not_atomic, 0); + sub_max(); + EXPECT_EQ(_not_atomic, 0); +} + +class AtomicIntegerTest: public testing::Test { +public: + template + void test_add() { + volatile T value = 0; + T result; + const T zero = 0; + const T one = 1; + const T max = std::numeric_limits::max(); + const T min = std::numeric_limits::min(); + + EXPECT_EQ(zero, value); + result = Atomic::add(1, &value); + EXPECT_EQ(one, value); + EXPECT_EQ(result, value); + result = Atomic::add(-1, &value); + EXPECT_EQ(zero, value); + EXPECT_EQ(result, value); + result = Atomic::add(max, &value); + EXPECT_EQ(max, value); + EXPECT_EQ(result, value); + } + + template + void test_inc_dec() { + volatile T value = 0; + const T zero = 0; + const T one = 1; + const T max = std::numeric_limits::max(); + const T min = std::numeric_limits::min(); + + EXPECT_EQ(zero, value); + Atomic::inc(&value); + EXPECT_EQ(one, value); + Atomic::dec(&value); + EXPECT_EQ(zero, value); + Atomic::add(max - 1, &value); + EXPECT_EQ(max - 1, value); + Atomic::inc(&value); + EXPECT_EQ(max, value); + } + + template + void test_cas() { + const T max = std::numeric_limits::max(); + const T min = std::numeric_limits::min(); + + volatile T value = min; + + // Successful cas + T result = Atomic::cmpxchg(max, &value, min); + EXPECT_EQ(max, value); + EXPECT_EQ(min, result); + + // Unsuccessful cas + result = Atomic::cmpxchg(max, &value, min); + EXPECT_EQ(max, value); + EXPECT_EQ(max, result); + + // Another successful cas + result = Atomic::cmpxchg(min, &value, max); + EXPECT_EQ(min, value); + EXPECT_EQ(max, result); + } + + template + void test_swap() { + const T zero = 0; + const T one = 1; + const T max = std::numeric_limits::max(); + const T min = std::numeric_limits::min(); + + volatile T value = zero; + + T result = Atomic::xchg(one, &value); + EXPECT_EQ(one, value); + EXPECT_EQ(zero, result); + + value = min; + result = Atomic::xchg(max, &value); + EXPECT_EQ(max, value); + EXPECT_EQ(min, result); + + result = Atomic::xchg(min, &value); + EXPECT_EQ(min, value); + EXPECT_EQ(max, result); + } +}; + +#define GENERATE_ATOMIC_INTEGER_TEST(T) \ +TEST_VM_F(AtomicIntegerTest, atomic_add_##T) { \ + test_add(); \ + test_inc_dec(); \ + test_cas(); \ + test_swap(); \ +} + +GENERATE_ATOMIC_INTEGER_TEST(int32) +GENERATE_ATOMIC_INTEGER_TEST(intptr) +GENERATE_ATOMIC_INTEGER_TEST(uint32) +GENERATE_ATOMIC_INTEGER_TEST(uintptr) + +#undef GENERATE_ATOMIC_INTEGER_TEST + +TEST(AtomicTest, pointer_arithmetic_byte) { + const intptr_t max = std::numeric_limits::max(); + const intptr_t min = std::numeric_limits::min(); + + int8_t *volatile byte_array = NULL; + + Atomic::inc(&byte_array); + EXPECT_EQ(1, IntegerTypes::cast_to_signed(byte_array)); + int8_t* result = Atomic::add(5, &byte_array); + EXPECT_EQ(6, IntegerTypes::cast_to_signed(byte_array)); + EXPECT_EQ(6, IntegerTypes::cast_to_signed(result)); + byte_array = NULL; + result = Atomic::add(max, &byte_array); + EXPECT_EQ(max, IntegerTypes::cast_to_signed(byte_array)); + EXPECT_EQ(max, IntegerTypes::cast_to_signed(result)); + Atomic::dec(&byte_array); + EXPECT_EQ(max - 1, IntegerTypes::cast_to_signed(byte_array)); +} + +TEST(AtomicTest, pointer_arithmetic_pointer) { + const intptr_t max = std::numeric_limits::max() / sizeof(void*); + const intptr_t min = std::numeric_limits::min() / sizeof(void*); + + void **volatile pointer_array = NULL; + + Atomic::inc(&pointer_array); + EXPECT_EQ(IntegerTypes::cast_to_signed(1 * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array)); + void** result = Atomic::add(5, &pointer_array); + EXPECT_EQ(IntegerTypes::cast_to_signed(6 * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array)); + EXPECT_EQ(IntegerTypes::cast_to_signed(6 * sizeof(void*)), IntegerTypes::cast_to_signed(result)); + pointer_array = NULL; + result = Atomic::add(max, &pointer_array); + EXPECT_EQ(IntegerTypes::cast_to_signed(max * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array)); + EXPECT_EQ(IntegerTypes::cast_to_signed(max * sizeof(void*)), IntegerTypes::cast_to_signed(result)); + Atomic::dec(&pointer_array); + EXPECT_EQ(IntegerTypes::cast_to_signed((max - 1) * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array)); +}