Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8247910: Improve alignment and power-of-2 utilities using C++14
8238956: Replace powerOfTwo::max_value with std::numeric_limits

Reviewed-by: tschatzl, stefank
  • Loading branch information
Kim Barrett committed Sep 15, 2020
1 parent 70cc7fc commit af8c678
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 162 deletions.
4 changes: 2 additions & 2 deletions src/hotspot/cpu/zero/interpreterFrame_zero.hpp
Expand Up @@ -57,8 +57,8 @@ class InterpreterFrame : public ZeroFrame {
protected:
enum Layout {
istate_off = jf_header_words +
(align_up_(sizeof(BytecodeInterpreter),
wordSize) >> LogBytesPerWord) - 1,
(align_up(sizeof(BytecodeInterpreter),
wordSize) >> LogBytesPerWord) - 1,
header_words
};

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/gc/shared/taskqueue.hpp
Expand Up @@ -113,8 +113,8 @@ class TaskQueueSuper: public CHeapObj<F> {

// N must be a power of 2 for computing modulo via masking.
// N must be >= 2 for the algorithm to work at all, though larger is better.
// C++11: is_power_of_2 is not (yet) constexpr.
STATIC_ASSERT((N >= 2) && ((N & (N - 1)) == 0));
STATIC_ASSERT(N >= 2);
STATIC_ASSERT(is_power_of_2(N));
static const uint MOD_N_MASK = N - 1;

class Age {
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/memory/padded.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, 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
Expand Down Expand Up @@ -34,7 +34,7 @@
// when the start address is not a multiple of alignment; the second maintains
// alignment of starting addresses that happen to be a multiple.
#define PADDING_SIZE(type, alignment) \
((alignment) + align_up_(sizeof(type), (alignment)))
((alignment) + align_up(sizeof(type), (alignment)))

// Templates to create a subclass padded to avoid cache line sharing. These are
// effective only when applied to derived-most (leaf) classes.
Expand Down Expand Up @@ -69,7 +69,7 @@ class PaddedEndImpl<T, /*pad_size*/ 0> : public T {
// No padding.
};

#define PADDED_END_SIZE(type, alignment) (align_up_(sizeof(type), (alignment)) - sizeof(type))
#define PADDED_END_SIZE(type, alignment) (align_up(sizeof(type), (alignment)) - sizeof(type))

// More memory conservative implementation of Padded. The subclass adds the
// minimal amount of padding needed to make the size of the objects be aligned.
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/memory/padded.inline.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, 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
Expand Down Expand Up @@ -36,7 +36,7 @@
template <class T, MEMFLAGS flags, size_t alignment>
PaddedEnd<T>* PaddedArray<T, flags, alignment>::create_unfreeable(uint length) {
// Check that the PaddedEnd class works as intended.
STATIC_ASSERT(is_aligned_(sizeof(PaddedEnd<T>), alignment));
STATIC_ASSERT(is_aligned(sizeof(PaddedEnd<T>), alignment));

// Allocate a chunk of memory large enough to allow for some alignment.
void* chunk = AllocateHeap(length * sizeof(PaddedEnd<T, alignment>) + alignment, flags);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/globals_shared.hpp
Expand Up @@ -37,7 +37,7 @@
// parts of the memory system may require additional alignment
// and are responsible for those alignments.
#ifdef _LP64
#define ScaleForWordSize(x) align_down_((x) * 13 / 10, HeapWordSize)
#define ScaleForWordSize(x) align_down((x) * 13 / 10, HeapWordSize)
#else
#define ScaleForWordSize(x) (x)
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/services/nmtCommon.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
Expand Down Expand Up @@ -29,7 +29,7 @@
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"

#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_up_(sizeof(obj), sizeof(type))/sizeof(type))
#define CALC_OBJ_SIZE_IN_TYPE(obj, type) (align_up(sizeof(obj), sizeof(type))/sizeof(type))

// Native memory tracking level
enum NMT_TrackingLevel {
Expand Down
91 changes: 45 additions & 46 deletions src/hotspot/share/utilities/align.hpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
Expand All @@ -25,65 +25,64 @@
#ifndef SHARE_UTILITIES_ALIGN_HPP
#define SHARE_UTILITIES_ALIGN_HPP

#include "metaprogramming/enableIf.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/powerOfTwo.hpp"

// Signed variants of alignment helpers. There are two versions of each, a macro
// for use in places like enum definitions that require compile-time constant
// expressions and a function for all other places so as to get type checking.

// Using '(what) & ~align_mask(alignment)' to align 'what' down is broken when
// 'alignment' is an unsigned int and 'what' is a wider type. The & operation
// will widen the inverted mask, and not sign extend it, leading to a mask with
// zeros in the most significant bits. The use of align_mask_widened() solves
// this problem.
#define align_mask(alignment) ((alignment) - 1)
#define widen_to_type_of(what, type_carrier) (true ? (what) : (type_carrier))
#define align_mask_widened(alignment, type_carrier) widen_to_type_of(align_mask(alignment), (type_carrier))

#define align_down_(size, alignment) ((size) & ~align_mask_widened((alignment), (size)))

#define align_up_(size, alignment) (align_down_((size) + align_mask(alignment), (alignment)))

#define is_aligned_(size, alignment) (((size) & align_mask(alignment)) == 0)

// Helpers to align sizes and check for alignment

template <typename T, typename A>
inline T align_up(T size, A alignment) {
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);

T ret = align_up_(size, alignment);
assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret);

return ret;
#include <type_traits>

// Compute mask to use for aligning to or testing alignment.
// The alignment must be a power of 2. Returns alignment - 1, which is
// a mask with all bits set below alignment's single bit.
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
static constexpr T alignment_mask(T alignment) {
assert(is_power_of_2(alignment),
"must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
return alignment - 1;
}

template <typename T, typename A>
inline T align_down(T size, A alignment) {
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
// Some "integral" constant alignments are defined via enum.
template<typename T, ENABLE_IF(std::is_enum<T>::value)>
static constexpr auto alignment_mask(T alignment) {
return alignment_mask(static_cast<std::underlying_type_t<T>>(alignment));
}

T ret = align_down_(size, alignment);
assert(is_aligned_(ret, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)ret);
// Align integers and check for alignment.
// The is_integral filtering here is not for disambiguation with the T*
// overloads; if those match then they are a better match. Rather, the
// is_integral filtering is to prevent back-sliding on the use of enums
// as "integral" constants that need aligning.

return ret;
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
constexpr bool is_aligned(T size, A alignment) {
return (size & alignment_mask(alignment)) == 0;
}

template <typename T, typename A>
inline bool is_aligned(T size, A alignment) {
assert(is_power_of_2(alignment), "must be a power of 2: " UINT64_FORMAT, (uint64_t)alignment);
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
constexpr T align_down(T size, A alignment) {
// Convert mask to T before lognot. Otherwise, if alignment is unsigned
// and smaller than T, the result of the lognot will be zero-extended
// by integral promotion, and upper bits of size will be discarded.
T result = size & ~T(alignment_mask(alignment));
assert(is_aligned(result, alignment),
"must be aligned: " UINT64_FORMAT, (uint64_t)result);
return result;
}

return is_aligned_(size, alignment);
template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
constexpr T align_up(T size, A alignment) {
T adjusted = size + alignment_mask(alignment);
return align_down(adjusted, alignment);
}

// Align down with a lower bound. If the aligning results in 0, return 'alignment'.
template <typename T, typename A>
inline T align_down_bounded(T size, A alignment) {
A aligned_size = align_down(size, alignment);
return aligned_size > 0 ? aligned_size : alignment;
constexpr T align_down_bounded(T size, A alignment) {
T aligned_size = align_down(size, alignment);
return (aligned_size > 0) ? aligned_size : T(alignment);
}

// Helpers to align pointers and check for alignment.
// Align pointers and check for alignment.

template <typename T, typename A>
inline T* align_up(T* ptr, A alignment) {
Expand Down Expand Up @@ -122,7 +121,7 @@ inline bool is_object_aligned(const void* addr) {

// Pad out certain offsets to jlong alignment, in HeapWord units.
template <typename T>
inline T align_object_offset(T offset) {
constexpr T align_object_offset(T offset) {
return align_up(offset, HeapWordsPerLong);
}

Expand Down
97 changes: 20 additions & 77 deletions src/hotspot/share/utilities/powerOfTwo.hpp
Expand Up @@ -26,16 +26,17 @@
#define SHARE_UTILITIES_POWEROFTWO_HPP

#include "metaprogramming/enableIf.hpp"
#include "metaprogramming/isIntegral.hpp"
#include "metaprogramming/isSigned.hpp"
#include "utilities/count_leading_zeros.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include <limits>
#include <type_traits>

// Power of two convenience library.

template <typename T>
bool is_power_of_2(T x) {
// Returns true iff there exists integer i such that (T(1) << i) == x.
template <typename T, ENABLE_IF(std::is_integral<T>::value)>
constexpr bool is_power_of_2(T x) {
return (x > T(0)) && ((x & (x - 1)) == T(0));
}

Expand All @@ -55,94 +56,36 @@ inline int exact_log2_long(jlong x) {
return bits - count_leading_zeros(x) - 1;
}

// Round down to the closest power of two greater to or equal to the given
// value.

// Signed version: 0 is an invalid input, negative values are invalid
template <typename T>
inline typename EnableIf<IsSigned<T>::value, T>::type round_down_power_of_2(T value) {
STATIC_ASSERT(IsIntegral<T>::value);
// Round down to the closest power of two less than or equal to the given value.
// precondition: value > 0.
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
inline T round_down_power_of_2(T value) {
assert(value > 0, "Invalid value");
uint32_t lz = count_leading_zeros(value);
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
return T(1) << (sizeof(T) * BitsPerByte - 1 - lz);
}

// Unsigned version: 0 is an invalid input
template <typename T>
inline typename EnableIf<!IsSigned<T>::value, T>::type round_down_power_of_2(T value) {
STATIC_ASSERT(IsIntegral<T>::value);
assert(value != 0, "Invalid value");
uint32_t lz = count_leading_zeros(value);
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
return T(1) << (sizeof(T) * BitsPerByte - 1 - lz);
}

// Round up to the closest power of two greater to or equal to
// the given value.

// Signed version: 0 is an invalid input, negative values are invalid,
// overflows with assert if value is larger than 2^30 or 2^62 for 32- and
// 64-bit integers, respectively
template <typename T>
inline typename EnableIf<IsSigned<T>::value, T>::type round_up_power_of_2(T value) {
STATIC_ASSERT(IsIntegral<T>::value);
STATIC_ASSERT(IsSigned<T>::value);
// Round up to the closest power of two greater to or equal to the given value.
// precondition: value > 0.
// precondition: value <= maximum power of two representable by T.
template<typename T, ENABLE_IF(std::is_integral<T>::value)>
inline T round_up_power_of_2(T value) {
assert(value > 0, "Invalid value");
const T max_value = std::numeric_limits<T>::max();
assert(value <= (max_value - (max_value >> 1)), "Overflow");
if (is_power_of_2(value)) {
return value;
}
uint32_t lz = count_leading_zeros(value);
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
assert(lz > 1, "Will overflow");
return T(1) << (sizeof(T) * BitsPerByte - lz);
}

// Unsigned version: 0 is an invalid input, overflows with assert if value
// is larger than 2^31 or 2^63 for 32- and 64-bit integers, respectively
template <typename T>
inline typename EnableIf<!IsSigned<T>::value, T>::type round_up_power_of_2(T value) {
STATIC_ASSERT(IsIntegral<T>::value);
STATIC_ASSERT(!IsSigned<T>::value);
assert(value != 0, "Invalid value");
if (is_power_of_2(value)) {
return value;
}
uint32_t lz = count_leading_zeros(value);
assert(lz < sizeof(T) * BitsPerByte, "Sanity");
assert(lz > 0, "Will overflow");
return T(1) << (sizeof(T) * BitsPerByte - lz);
}

// Helper function to get the maximum positive value. Implemented here
// since using std::numeric_limits<T>::max() seems problematic on some
// platforms.

template <typename T> T max_value() {
if (IsSigned<T>::value) {
// Highest positive power of two expressible in the type
uint64_t val = static_cast<T>(1) << (sizeof(T) * BitsPerByte - 2);
// Fill lower bits with ones
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
if (sizeof(T) >= 2) val |= val >> 8;
if (sizeof(T) >= 4) val |= val >> 16;
if (sizeof(T) == 8) val |= val >> 32;
return (T)val;
} else {
return ~(static_cast<T>(0));
}
}

// Calculate the next power of two greater than the given value.

// Accepts 0 (returns 1), overflows with assert if value is larger than
// or equal to 2^31 (signed: 2^30) or 2^63 (signed: 2^62), for 32-
// and 64-bit integers, respectively
template <typename T>
// precondition: if signed, value >= 0.
// precondition: value < maximum power of two representable by T.
template <typename T, ENABLE_IF(std::is_integral<T>::value)>
inline T next_power_of_2(T value) {
assert(value != max_value<T>(), "Overflow");
assert(value < std::numeric_limits<T>::max(), "Overflow");
return round_up_power_of_2(value + 1);
}

Expand Down
4 changes: 2 additions & 2 deletions test/hotspot/gtest/runtime/test_arguments.cpp
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
Expand Down Expand Up @@ -153,7 +153,7 @@ static intx calc_expected(julong small_xss_input) {
assert(small_xss_input <= max_julong / 2, "Sanity");

// Match code in arguments.cpp
julong julong_ret = align_up_(small_xss_input, K) / K;
julong julong_ret = align_up(small_xss_input, K) / K;
assert(julong_ret <= (julong)max_intx, "Overflow: " JULONG_FORMAT, julong_ret);
return (intx)julong_ret;
}
Expand Down

2 comments on commit af8c678

@bridgekeeper
Copy link

@bridgekeeper bridgekeeper bot commented on af8c678 Sep 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bridgekeeper
Copy link

@bridgekeeper bridgekeeper bot commented on af8c678 Sep 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.