In openjdk/mmtkUpcalls.cpp, there is a struct MaybeUninit<T> which is used to prevent the constructor to be called on a global variable. It is implemented with char _data[sizeof(T)] as its member.
However, char[sizeof(T)] does not necessarily have the same alignment requirement as T.
I added a static assertion and a run-time assertion:
diff --git a/openjdk/mmtkUpcalls.cpp b/openjdk/mmtkUpcalls.cpp
index a11e186..aaebfb1 100644
--- a/openjdk/mmtkUpcalls.cpp
+++ b/openjdk/mmtkUpcalls.cpp
@@ -118,7 +118,18 @@ private:
static MaybeUninit<JavaThreadIteratorWithHandle> jtiwh;
static bool mutator_iteration_start = true;
+static_assert(alignof(jtiwh) == alignof(JavaThreadIteratorWithHandle),
+ "jtiwh and JavaThreadIteratorWithHandle does not have the same alignment");
+
static void* mmtk_get_next_mutator() {
+ if ((uintptr_t)&jtiwh % alignof(JavaThreadIteratorWithHandle) != 0) {
+ fprintf(stderr, "[mmtk_get_next_mutator] error: jtiwh is not aligned. jtiwh: %p, align: %zd\n",
+ &jtiwh, alignof(JavaThreadIteratorWithHandle));
+ exit(1);
+ } else {
+ fprintf(stderr, "[mmtk_get_next_mutator] OK: jtiwh is aligned. jtiwh: %p, align: %zd\n",
+ &jtiwh, alignof(JavaThreadIteratorWithHandle));
+ }
if (mutator_iteration_start) {
*jtiwh = JavaThreadIteratorWithHandle();
mutator_iteration_start = false;
The static assertion fails. But if I comment out the static_assert, the run-time assertion always succeeds on my x86_64 machine running Linux. I did not find any ABI documentation that requires static variables (jtiwh) to have any particular alignment (such as word-aligned, 8-byte aligned, 16-byte aligned, ...). So there is a chance that jtiwh may be mis-aligned on some platform-compiler combinations, but not manifested yet. The proper way to avoid initializing a global variable is to use std::opitonal<T>, or manually implement it using a union if OpenJDK does not support C++17.
However, from a higher level, it is almost always bad to use global variables. mmtk_get_next_mutator and mmtk_reset_mutator_iterator depends on the global jtiwh variable to maintain the iterator between successive calls. In a reentrant API, they should take a parameter which points to an allocated JavaThreadIteratorWithHandle instance. It shouldn't be a problem to just new JavaThreadIteratorWithHandle and allocate it on the heap, I think. See opendir and readdir_r for example.
In
openjdk/mmtkUpcalls.cpp, there is a structMaybeUninit<T>which is used to prevent the constructor to be called on a global variable. It is implemented withchar _data[sizeof(T)]as its member.However,
char[sizeof(T)]does not necessarily have the same alignment requirement asT.I added a static assertion and a run-time assertion:
The static assertion fails. But if I comment out the
static_assert, the run-time assertion always succeeds on my x86_64 machine running Linux. I did not find any ABI documentation that requires static variables (jtiwh) to have any particular alignment (such as word-aligned, 8-byte aligned, 16-byte aligned, ...). So there is a chance thatjtiwhmay be mis-aligned on some platform-compiler combinations, but not manifested yet. The proper way to avoid initializing a global variable is to usestd::opitonal<T>, or manually implement it using aunionif OpenJDK does not support C++17.However, from a higher level, it is almost always bad to use global variables.
mmtk_get_next_mutatorandmmtk_reset_mutator_iteratordepends on the globaljtiwhvariable to maintain the iterator between successive calls. In a reentrant API, they should take a parameter which points to an allocatedJavaThreadIteratorWithHandleinstance. It shouldn't be a problem to justnew JavaThreadIteratorWithHandleand allocate it on the heap, I think. See opendir and readdir_r for example.