openjdk-17/Implement-JBooster-RPC-byte-alignment.patch

700 lines
27 KiB
Diff
Raw Permalink Normal View History

2025-02-21 11:29:09 +08:00
From bcc1964f3ac7ffe6995f6734bc14cbbe07a09363 Mon Sep 17 00:00:00 2001
Date: Fri, 29 Nov 2024 15:38:42 +0800
Subject: Implement JBooster RPC byte alignment
---
.../share/jbooster/jClientArguments.cpp | 21 +++
.../share/jbooster/jClientArguments.hpp | 5 +
.../share/jbooster/net/messageBuffer.cpp | 34 ++++-
.../share/jbooster/net/messageBuffer.hpp | 19 ++-
.../jbooster/net/messageBuffer.inline.hpp | 44 +++++-
.../share/jbooster/net/rpcCompatibility.cpp | 43 ++++--
.../share/jbooster/net/serialization.hpp | 13 +-
.../jbooster/server/serverDataManager.cpp | 22 +--
.../jbooster/server/serverDataManager.hpp | 4 +-
.../jbooster/server/serverMessageHandler.cpp | 6 +-
test/hotspot/gtest/jbooster/test_net.cpp | 129 ++++++++++++++----
11 files changed, 272 insertions(+), 68 deletions(-)
diff --git a/src/hotspot/share/jbooster/jClientArguments.cpp b/src/hotspot/share/jbooster/jClientArguments.cpp
index 37093d031..b215913ea 100644
--- a/src/hotspot/share/jbooster/jClientArguments.cpp
+++ b/src/hotspot/share/jbooster/jClientArguments.cpp
@@ -34,6 +34,27 @@
#include "runtime/arguments.hpp"
#include "utilities/stringUtils.hpp"
+int JClientBoostLevel::serialize(MessageBuffer& buf) const {
+ uint8_t v = (_allow_clr ? (1 << 0) : 0)
+ | (_allow_cds ? (1 << 1) : 0)
+ | (_allow_aot ? (1 << 2) : 0)
+ | (_enable_aot_pgo ? (1 << 3) : 0)
+ | (_enable_cds_agg ? (1 << 4) : 0);
+ return buf.serialize_no_meta(v);
+}
+
+int JClientBoostLevel::deserialize(MessageBuffer& buf) {
+ uint8_t v = 0b10000000;
+ JB_RETURN(buf.deserialize_ref_no_meta(v));
+ assert((v & 0b10000000) == 0, "sanity");
+ _allow_clr = (v & (1 << 0));
+ _allow_cds = (v & (1 << 1));
+ _allow_aot = (v & (1 << 2));
+ _enable_aot_pgo = (v & (1 << 3));
+ _enable_cds_agg = (v & (1 << 4));
+ return 0;
+}
+
static JClientArguments::CpuArch calc_cpu() {
#ifdef X86
return JClientArguments::CpuArch::CPU_X86;
diff --git a/src/hotspot/share/jbooster/jClientArguments.hpp b/src/hotspot/share/jbooster/jClientArguments.hpp
index be057a07d..09c5dfdc0 100644
--- a/src/hotspot/share/jbooster/jClientArguments.hpp
+++ b/src/hotspot/share/jbooster/jClientArguments.hpp
@@ -49,8 +49,13 @@ public:
void set_allow_aot(bool allow_aot) { _allow_aot = allow_aot; }
void set_enable_aot_pgo(bool enable_aot_pgo) { _enable_aot_pgo = enable_aot_pgo; }
void set_enable_cds_agg(bool enable_cds_agg) { _enable_cds_agg = enable_cds_agg; }
+
+ int serialize(MessageBuffer& buf) const;
+ int deserialize(MessageBuffer& buf);
};
+DECLARE_SERIALIZER_INTRUSIVE(JClientBoostLevel);
+
/**
* Arguments that identify a program.
*/
diff --git a/src/hotspot/share/jbooster/net/messageBuffer.cpp b/src/hotspot/share/jbooster/net/messageBuffer.cpp
index 4673bb784..980cfbfed 100644
--- a/src/hotspot/share/jbooster/net/messageBuffer.cpp
+++ b/src/hotspot/share/jbooster/net/messageBuffer.cpp
@@ -23,15 +23,34 @@
#include "jbooster/net/messageBuffer.inline.hpp"
+/**
+ * Allocate an extra eight bytes in case the array object is not 8-byte aligned.
+ */
+char* MessageBuffer::alloc_buf_obj(uint32_t new_buf_size) {
+ return NEW_C_HEAP_ARRAY(char, new_buf_size + sizeof(int64_t), mtJBooster);
+}
+
+void MessageBuffer::del_buf_obj(char* buf_obj) {
+ FREE_C_HEAP_ARRAY(char, buf_obj);
+}
+
+/**
+ * Make the beginning of buf be 8-byte aligned.
+ */
+char* MessageBuffer::calc_buf_start(char* buf_obj) {
+ return buf_obj + calc_padding<int64_t>((uint32_t) reinterpret_cast<uintptr_t>(buf_obj));
+}
+
MessageBuffer::MessageBuffer(SerializationMode smode, CommunicationStream* stream):
_smode(smode),
_buf_size(_default_buf_size),
- _buf(NEW_C_HEAP_ARRAY(char, _buf_size, mtJBooster)),
+ _buf_obj(alloc_buf_obj(_buf_size)),
+ _buf(calc_buf_start(_buf_obj)),
_cur_offset(0),
_stream(stream) {}
MessageBuffer::~MessageBuffer() {
- FREE_C_HEAP_ARRAY(char, _buf);
+ del_buf_obj(_buf_obj);
}
/**
@@ -50,12 +69,19 @@ uint32_t MessageBuffer::calc_new_buf_size(uint32_t required_size) {
}
void MessageBuffer::expand_buf(uint32_t required_size, uint32_t copy_size) {
+ char* old_buf_obj = _buf_obj;
char* old_buf = _buf;
+
uint32_t new_buf_size = calc_new_buf_size(required_size);
- char* new_buf = NEW_C_HEAP_ARRAY(char, new_buf_size, mtJBooster);
+ char* new_buf_obj = alloc_buf_obj(new_buf_size);
+ char* new_buf = calc_buf_start(new_buf_obj);
+ guarantee((new_buf_obj + new_buf_size + sizeof(int64_t)) >= (new_buf + copy_size), "sanity");
memcpy(new_buf, old_buf, copy_size);
+ _buf_obj = new_buf_obj;
_buf = new_buf;
_buf_size = new_buf_size;
- FREE_C_HEAP_ARRAY(char, old_buf);
+ del_buf_obj(old_buf_obj);
+
+ assert(((int) (reinterpret_cast<uintptr_t>(_buf)) & 7) == 0, "8-byte aligned");
}
diff --git a/src/hotspot/share/jbooster/net/messageBuffer.hpp b/src/hotspot/share/jbooster/net/messageBuffer.hpp
index aaa8e7c3b..04e41e9d6 100644
--- a/src/hotspot/share/jbooster/net/messageBuffer.hpp
+++ b/src/hotspot/share/jbooster/net/messageBuffer.hpp
@@ -56,7 +56,7 @@ public:
void assert_can_deserialize() const NOT_DEBUG_RETURN;
};
-class MessageBuffer final: public StackObj {
+class MessageBuffer: public StackObj {
friend class Message;
private:
@@ -64,14 +64,23 @@ private:
SerializationMode _smode;
uint32_t _buf_size;
- char* _buf;
+ char* _buf_obj; // malloced buf object
+ char* _buf; // 8-byte aligned buf start
uint32_t _cur_offset;
CommunicationStream* const _stream;
private:
- static uint32_t calc_new_buf_size(uint32_t required_size);
+ static char* alloc_buf_obj(uint32_t new_buf_size);
+ static void del_buf_obj(char* buf_obj);
+
void expand_buf(uint32_t required_size, uint32_t copy_size);
+protected: // for gtest
+ template <typename Arg>
+ static uint32_t calc_padding(uint32_t offset);
+ static char* calc_buf_start(char* buf_obj);
+ static uint32_t calc_new_buf_size(uint32_t required_size);
+
public:
MessageBuffer(SerializationMode smode, CommunicationStream* stream = nullptr);
~MessageBuffer();
@@ -95,6 +104,8 @@ public:
}
// serializers
+ template <typename Arg>
+ int serialize_base(Arg v);
int serialize_memcpy(const void* from, uint32_t arg_size);
template <typename Arg>
int serialize_no_meta(const Arg& arg);
@@ -102,6 +113,8 @@ public:
int serialize_with_meta(const Arg* arg_ptr);
// deserializers
+ template <typename Arg>
+ int deserialize_base(Arg& to);
int deserialize_memcpy(void* to, uint32_t arg_size);
template <typename Arg>
int deserialize_ref_no_meta(Arg& arg);
diff --git a/src/hotspot/share/jbooster/net/messageBuffer.inline.hpp b/src/hotspot/share/jbooster/net/messageBuffer.inline.hpp
index c7dc0986f..9500c1aaa 100644
--- a/src/hotspot/share/jbooster/net/messageBuffer.inline.hpp
+++ b/src/hotspot/share/jbooster/net/messageBuffer.inline.hpp
@@ -38,6 +38,26 @@ inline void SerializationMode::assert_can_deserialize() const {
}
#endif
+template <typename Arg>
+inline uint32_t MessageBuffer::calc_padding(uint32_t offset) {
+ static_assert((sizeof(Arg) & (sizeof(Arg) - 1)) == 0, "Should be 1, 2, 4, 8!");
+ static_assert(sizeof(Arg) <= 8, "Should be 1, 2, 4, 8!");
+ return (-offset) & (sizeof(Arg) - 1);
+}
+
+template <typename Arg>
+inline int MessageBuffer::serialize_base(Arg v) {
+ static_assert(std::is_arithmetic<Arg>::value || std::is_enum<Arg>::value, "Base types or enums only!");
+ _smode.assert_can_serialize();
+ uint32_t arg_size = (uint32_t) sizeof(Arg);
+ uint32_t padding = calc_padding<Arg>(_cur_offset);
+ uint32_t nxt_offset = _cur_offset + padding + arg_size;
+ expand_if_needed(nxt_offset, _cur_offset);
+ *((Arg*) (_buf + _cur_offset + padding)) = v;
+ _cur_offset = nxt_offset;
+ return 0;
+}
+
inline int MessageBuffer::serialize_memcpy(const void* from, uint32_t arg_size) {
_smode.assert_can_serialize();
assert(from != nullptr, "sanity");
@@ -56,11 +76,13 @@ inline int MessageBuffer::serialize_no_meta(const Arg& arg) {
template <typename Arg>
inline int MessageBuffer::serialize_with_meta(const Arg* arg_ptr) {
+ static_assert(MessageConst::arg_meta_size == sizeof(uint32_t), "Meta changed?");
_smode.assert_can_serialize();
if (arg_ptr == nullptr) {
return serialize_no_meta(MessageConst::NULL_PTR);
}
const Arg& arg = *arg_ptr;
+ skip_cur_offset(calc_padding<uint32_t >(_cur_offset));
uint32_t meta_offset = _cur_offset;
skip_cur_offset(MessageConst::arg_meta_size);
expand_if_needed(_cur_offset, _cur_offset);
@@ -68,7 +90,25 @@ inline int MessageBuffer::serialize_with_meta(const Arg* arg_ptr) {
// fill arg meta at last
uint32_t arg_size = _cur_offset - meta_offset - MessageConst::arg_meta_size;
- memcpy((void*) (_buf + meta_offset), &arg_size, sizeof(arg_size));
+ *((uint32_t*) (_buf + meta_offset)) = arg_size;
+ return 0;
+}
+
+template <typename Arg>
+inline int MessageBuffer::deserialize_base(Arg& to) {
+ static_assert(std::is_arithmetic<Arg>::value || std::is_enum<Arg>::value, "Base types or enums only!");
+ _smode.assert_can_deserialize();
+ uint32_t arg_size = (uint32_t) sizeof(Arg);
+ uint32_t padding = calc_padding<Arg>(_cur_offset);
+ uint32_t nxt_offset = _cur_offset + padding + arg_size;
+ if (_buf_size < nxt_offset) {
+ log_warning(jbooster, rpc)("The size to parse is longer than the msg size: "
+ "arg_size=%u, cur_offset=%u, nxt_offset=%u, buf_size=%u",
+ arg_size, _cur_offset, nxt_offset, _buf_size);
+ return JBErr::BAD_MSG_DATA;
+ }
+ to = *((Arg*) (_buf + _cur_offset + padding));
+ _cur_offset = nxt_offset;
return 0;
}
@@ -125,7 +165,7 @@ inline int MessageBuffer::deserialize_with_meta(Arg* const& arg_ptr) {
return 0;
}
const char* type_name = DebugUtils::type_name<Arg>();
- log_warning(jbooster, rpc)("The arg size does match the parsed size: "
+ log_warning(jbooster, rpc)("The arg size does not match the parsed size: "
"arg=%s, arg_size=%u, (cur_size - arg_begin)=%u.",
type_name, arg_size, _cur_offset - arg_begin);
FREE_C_HEAP_ARRAY(char, type_name);
diff --git a/src/hotspot/share/jbooster/net/rpcCompatibility.cpp b/src/hotspot/share/jbooster/net/rpcCompatibility.cpp
index 7f849a6fe..a48d1c2d8 100644
--- a/src/hotspot/share/jbooster/net/rpcCompatibility.cpp
+++ b/src/hotspot/share/jbooster/net/rpcCompatibility.cpp
@@ -21,6 +21,7 @@
* questions.
*/
+#include "classfile/vmSymbols.hpp"
#include "jbooster/dataTransmissionUtils.hpp"
#include "jbooster/jBoosterManager.hpp"
#include "jbooster/jClientArguments.hpp"
@@ -33,9 +34,18 @@
#include "jbooster/net/rpcCompatibility.hpp"
#include "jbooster/net/serializationWrappers.hpp"
#include "jbooster/net/serverStream.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/method.hpp"
+#include "oops/methodData.hpp"
-static constexpr uint32_t calc_new_hash(uint32_t old_hash, uint32_t ele_hash) {
- return 31 * old_hash + ele_hash;
+static constexpr uint32_t calc_new_hash(uint32_t old_hash) {
+ return old_hash;
+}
+
+template <typename... Rest>
+static constexpr uint32_t calc_new_hash(uint32_t old_hash, uint32_t ele_hash, Rest... rest_hashes) {
+ uint32_t new_hash = old_hash * 31u + ele_hash;
+ return calc_new_hash(new_hash, rest_hashes...);
}
template <typename T>
@@ -54,20 +64,35 @@ static constexpr uint32_t calc_classes_hash() {
return calc_new_hash(calc_classes_hash<Second, Rest...>(), calc_class_hash<First>());
}
-/**
- * Returns a magic number computed at compile time based on the sizes of some classes.
- * It is just an crude way to check compatibility for now. More policies can be added later.
- */
-static constexpr uint32_t calc_magic_num() {
+static constexpr uint32_t classes_hash() {
return calc_classes_hash<
JBoosterManager, JClientVMFlags, JClientArguments,
JBErr, Message, MessageBuffer,
CommunicationStream, ClientStream, ServerStream,
ArrayWrapper<int>, MemoryWrapper, StringWrapper, FileWrapper,
- ClassLoaderKey, ClassLoaderChain, ClassLoaderLocator, KlassLocator, MethodLocator, ProfileDataCollector
+ ClassLoaderKey, ClassLoaderChain, ClassLoaderLocator, KlassLocator, MethodLocator, ProfileDataCollector,
+ InstanceKlass, Method, MethodData
>();
}
+static constexpr uint32_t little_or_big_endian() {
+ return (uint32_t) LITTLE_ENDIAN_ONLY('L') BIG_ENDIAN_ONLY('B');
+}
+
+/**
+ * Returns a magic number computed at compile time based on the sizes of some classes.
+ * It is just an crude way to check compatibility for now. More policies can be added later.
+ */
+static constexpr uint32_t calc_magic_num() {
+ return calc_new_hash(
+ classes_hash(),
+ little_or_big_endian(),
+ static_cast<uint32_t>(vmSymbolID::SID_LIMIT)
+ );
+}
+
+static constexpr uint32_t _magic_num = calc_magic_num();
+
uint32_t RpcCompatibility::magic_num() {
- return calc_magic_num();
+ return _magic_num;
}
diff --git a/src/hotspot/share/jbooster/net/serialization.hpp b/src/hotspot/share/jbooster/net/serialization.hpp
index f9a2996c5..ed8387eb6 100644
--- a/src/hotspot/share/jbooster/net/serialization.hpp
+++ b/src/hotspot/share/jbooster/net/serialization.hpp
@@ -72,21 +72,20 @@
// ------------------------------ Default Serializer -------------------------------
// The types it support for serialization/deserialization:
// - Base types: bool, int, long long, size_t, uint64_t, and so on.
-// - POD classes without pointers.
//
-// memcpy() is good enough in most cases. Even for base types such as char and size_t,
-// memcpy() has the similar performance as assignment (`=`) according to our tests.
-// It's also a choice to use assignment here. But if a class overloads the operator `=`
-// and allocates something on the heap, it can cause a memory leak.
+// No default serializer for classes! Implement them manually.
+//
+// Use uintptr_t instead of address (aka unsigned char*) if you want to serialize a
+// pointer.
template <typename Arg>
struct SerializationImpl {
static int serialize(MessageBuffer& buf, const Arg& arg) {
- return buf.serialize_memcpy(&arg, sizeof(Arg));
+ return buf.serialize_base(arg);
}
static int deserialize_ref(MessageBuffer& buf, Arg& arg) {
- return buf.deserialize_memcpy(&arg, sizeof(Arg));
+ return buf.deserialize_base(arg);
}
CANNOT_DESERIALIZE_POINTER(Arg);
diff --git a/src/hotspot/share/jbooster/server/serverDataManager.cpp b/src/hotspot/share/jbooster/server/serverDataManager.cpp
index b2f36c4e5..c3d5f290e 100644
--- a/src/hotspot/share/jbooster/server/serverDataManager.cpp
+++ b/src/hotspot/share/jbooster/server/serverDataManager.cpp
@@ -340,18 +340,18 @@ ClassLoaderData* JClientProgramData::add_class_loader_if_absent(const ClassLoade
// ------------------------------ JClientSessionData -------------------------------
class AddressMapKVArray: public StackObj {
- GrowableArray<address>* _key_array;
- GrowableArray<address>* _value_array;
+ GrowableArray<uintptr_t>* _key_array;
+ GrowableArray<uintptr_t>* _value_array;
public:
- AddressMapKVArray(GrowableArray<address>* key_array,
- GrowableArray<address>* value_array) :
+ AddressMapKVArray(GrowableArray<uintptr_t>* key_array,
+ GrowableArray<uintptr_t>* value_array) :
_key_array(key_array),
_value_array(value_array) {}
bool operator () (JClientSessionData::AddressMap::KVNode* kv_node) {
assert(kv_node->key() != nullptr && kv_node->value() != nullptr, "sanity");
- _key_array->append(kv_node->key());
- _value_array->append(kv_node->value());
+ _key_array->append(reinterpret_cast<uintptr_t>(kv_node->key()));
+ _value_array->append(reinterpret_cast<uintptr_t>(kv_node->value()));
return true;
}
};
@@ -422,17 +422,17 @@ void JClientSessionData::add_klass_address(address client_klass_addr,
put_address(_k_c2s, client_klass_addr, server_cld_addr, thread);
}
-void JClientSessionData::klass_array(GrowableArray<address>* key_array,
- GrowableArray<address>* value_array,
+void JClientSessionData::klass_array(GrowableArray<uintptr_t>* key_array,
+ GrowableArray<uintptr_t>* value_array,
Thread* thread) {
AddressMapKVArray array(key_array, value_array);
_k_c2s.for_each(array, thread);
}
-void JClientSessionData::klass_pointer_map_to_server(GrowableArray<address>* klass_array, Thread* thread) {
- for (GrowableArrayIterator<address> iter = klass_array->begin();
+void JClientSessionData::klass_pointer_map_to_server(GrowableArray<uintptr_t>* klass_array, Thread* thread) {
+ for (GrowableArrayIterator<uintptr_t> iter = klass_array->begin();
iter != klass_array->end(); ++iter) {
- InstanceKlass* klass = (InstanceKlass*) (*iter);
+ InstanceKlass* klass = reinterpret_cast<InstanceKlass*>(*iter);
Array<Method*>* methods = klass->methods();
for (int method_index = 0; method_index < methods->length(); method_index++) {
MethodData* method_data = method_data_address((address)(methods->at(method_index)), thread);
diff --git a/src/hotspot/share/jbooster/server/serverDataManager.hpp b/src/hotspot/share/jbooster/server/serverDataManager.hpp
index 2cb7d2de0..c6ef4c99a 100644
--- a/src/hotspot/share/jbooster/server/serverDataManager.hpp
+++ b/src/hotspot/share/jbooster/server/serverDataManager.hpp
@@ -291,9 +291,9 @@ public:
Klass* server_klass_address(address client_klass_addr, Thread* thread);
void add_klass_address(address client_klass_addr, address server_cld_addr, Thread* thread);
- void klass_array(GrowableArray<address>* key_array, GrowableArray<address>* value_array, Thread* thread);
+ void klass_array(GrowableArray<uintptr_t>* key_array, GrowableArray<uintptr_t>* value_array, Thread* thread);
- void klass_pointer_map_to_server(GrowableArray<address>* klass_array, Thread* thread);
+ void klass_pointer_map_to_server(GrowableArray<uintptr_t>* klass_array, Thread* thread);
void add_method_data(address method, address method_data, Thread* thread);
bool remove_method_data(address method, Thread* thread);
diff --git a/src/hotspot/share/jbooster/server/serverMessageHandler.cpp b/src/hotspot/share/jbooster/server/serverMessageHandler.cpp
index 49c25efb1..f46b839bb 100644
--- a/src/hotspot/share/jbooster/server/serverMessageHandler.cpp
+++ b/src/hotspot/share/jbooster/server/serverMessageHandler.cpp
@@ -196,14 +196,14 @@ int ServerMessageHandler::request_missing_klasses(TRAPS) {
int ServerMessageHandler::request_method_data(TRAPS) {
ResourceMark rm(THREAD);
- GrowableArray<address> client_klass_array;
- GrowableArray<address> server_klass_array;
+ GrowableArray<uintptr_t> client_klass_array;
+ GrowableArray<uintptr_t> server_klass_array;
ss().session_data()->klass_array(&client_klass_array,
&server_klass_array,
THREAD);
{
- ArrayWrapper<address> aw(&client_klass_array);
+ ArrayWrapper<uintptr_t> aw(&client_klass_array);
JB_RETURN(ss().send_request(MessageType::Profilinginfo, &aw));
InstanceKlass** klass_array_base = NULL;
if (server_klass_array.length() > 0) {
diff --git a/test/hotspot/gtest/jbooster/test_net.cpp b/test/hotspot/gtest/jbooster/test_net.cpp
index 9eb29fc3a..bf20b0aa3 100644
--- a/test/hotspot/gtest/jbooster/test_net.cpp
+++ b/test/hotspot/gtest/jbooster/test_net.cpp
@@ -26,10 +26,12 @@
#if INCLUDE_JBOOSTER
+#include "jbooster/jClientArguments.hpp"
#include "jbooster/net/message.inline.hpp"
#include "jbooster/net/messageBuffer.inline.hpp"
#include "jbooster/net/serializationWrappers.inline.hpp"
#include "jbooster/utilities/fileUtils.hpp"
+#include "memory/resourceArea.hpp"
#include "runtime/os.inline.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
@@ -105,6 +107,47 @@ static void copy_message_buffer(MessageBuffer& to, MessageBuffer& from) {
memcpy(to.buf(), from.buf(), from.cur_offset());
}
+class MockMessageBuffer: public MessageBuffer {
+public:
+ static bool test() {
+ // calc_padding<char[6]>(0); // should not pass the compilation
+ EXPECT_EQ(calc_padding<char>(123), 0u);
+ EXPECT_EQ(calc_padding<char>(124), 0u);
+ EXPECT_EQ(calc_padding<short>(123), 1u);
+ EXPECT_EQ(calc_padding<short>(120), 0u);
+ EXPECT_EQ(calc_padding<int>(0), 0u);
+ EXPECT_EQ(calc_padding<int>(1), 3u);
+ EXPECT_EQ(calc_padding<int>(2), 2u);
+ EXPECT_EQ(calc_padding<int>(3), 1u);
+ EXPECT_EQ(calc_padding<int>(4), 0u);
+ EXPECT_EQ(calc_padding<int>(400), 0u);
+ EXPECT_EQ(calc_padding<uint64_t>(1), 7u);
+ EXPECT_EQ(calc_padding<uint64_t>(3), 5u);
+ EXPECT_EQ(calc_padding<uint64_t>(12), 4u);
+ EXPECT_EQ(calc_padding<uint64_t>(7), 1u);
+
+ EXPECT_EQ(calc_buf_start(reinterpret_cast<char*>(7)), reinterpret_cast<char*>(8));
+ EXPECT_EQ(calc_buf_start(reinterpret_cast<char*>(9)), reinterpret_cast<char*>(16));
+ EXPECT_EQ(calc_buf_start(reinterpret_cast<char*>(12)), reinterpret_cast<char*>(16));
+ EXPECT_EQ(calc_buf_start(reinterpret_cast<char*>(65535)), reinterpret_cast<char*>(65536));
+ EXPECT_EQ(calc_buf_start(reinterpret_cast<char*>(65536)), reinterpret_cast<char*>(65536));
+
+ EXPECT_EQ(calc_new_buf_size(0), 0u);
+ EXPECT_EQ(calc_new_buf_size(1), 1u);
+ EXPECT_EQ(calc_new_buf_size(2), 2u);
+ EXPECT_EQ(calc_new_buf_size(3), 4u);
+ EXPECT_EQ(calc_new_buf_size(65535), 65536u);
+ EXPECT_EQ(calc_new_buf_size(65536), 65536u);
+ EXPECT_EQ(calc_new_buf_size(65537), 131072u);
+
+ return true;
+ }
+};
+
+TEST(JBoosterNet, padding) {
+ ASSERT_TRUE(MockMessageBuffer::test());
+}
+
TEST(JBoosterNet, try_catch) {
int i;
for (i = 0; i < 9; ++i) {
@@ -145,24 +188,25 @@ TEST(JBoosterNet, serializationn_basics) {
int i1 = 1234;
int64_t l1 = 900000000000000ll;
EXPECT_EQ(buf.serialize_no_meta(c1), 0);
- EXPECT_EQ(buf.cur_offset(), 1u);
+ EXPECT_EQ(buf.cur_offset(), 1u); // 1 (char)
EXPECT_EQ(buf.serialize_no_meta(i1), 0);
- EXPECT_EQ(buf.cur_offset(), 5u);
+ EXPECT_EQ(buf.cur_offset(), 8u); // 1 (last) + 3 (padding) + 4 (int32)
EXPECT_EQ(buf.serialize_no_meta(l1), 0);
- EXPECT_EQ(buf.cur_offset(), 13u);
+ EXPECT_EQ(buf.cur_offset(), 16u); // 8 (last) + 8 (int64)
uint32_t u1 = 2468;
const char* s1 = nullptr;
const char* s2 = "hello";
const char* s3 = "world!";
EXPECT_EQ(buf.serialize_with_meta(&u1), 0);
- EXPECT_EQ(buf.cur_offset(), 21u);
+ EXPECT_EQ(buf.cur_offset(), 24u); // 16 (last) + 4 (int32) + 4 (int32)
EXPECT_EQ(buf.serialize_with_meta(&s1), 0);
- EXPECT_EQ(buf.cur_offset(), 29u);
+ EXPECT_EQ(buf.cur_offset(), 32u); // 24 (last) + 4 (int32) + 4 (int32)
EXPECT_EQ(buf.serialize_with_meta(&s2), 0);
- EXPECT_EQ(buf.cur_offset(), 42u);
+ EXPECT_EQ(buf.cur_offset(), 45u); // 32 (last) + 4 (int32) + 4 (int32) + 5 (strlen)
EXPECT_EQ(buf.serialize_with_meta(&s3), 0);
- EXPECT_EQ(buf.cur_offset(), 56u);
+ EXPECT_EQ(buf.cur_offset(), 62u); // 45 (last) + 3 (padding) + 4 (int32) + 4 (int32) + 6 (strlen)
+ EXPECT_EQ((int) (reinterpret_cast<uintptr_t>(buf.buf())) & 7, 0); // 8-byte aligned
cache_size = buf.cur_offset();
memcpy(cache, buf.buf(), cache_size);
@@ -177,9 +221,9 @@ TEST(JBoosterNet, serializationn_basics) {
EXPECT_EQ(buf.deserialize_ref_no_meta(c1), 0);
EXPECT_EQ(buf.cur_offset(), 1u);
EXPECT_EQ(buf.deserialize_ref_no_meta(i1), 0);
- EXPECT_EQ(buf.cur_offset(), 5u);
+ EXPECT_EQ(buf.cur_offset(), 8u);
EXPECT_EQ(buf.deserialize_ref_no_meta(l1), 0);
- EXPECT_EQ(buf.cur_offset(), 13u);
+ EXPECT_EQ(buf.cur_offset(), 16u);
EXPECT_EQ(c1, '6');
EXPECT_EQ(i1, 1234);
EXPECT_EQ(l1, 900000000000000ll);
@@ -189,13 +233,15 @@ TEST(JBoosterNet, serializationn_basics) {
char s2[6];
StringWrapper s3;
EXPECT_EQ(buf.deserialize_with_meta(&u1), 0);
- EXPECT_EQ(buf.cur_offset(), 21u);
+ EXPECT_EQ(buf.cur_offset(), 24u);
EXPECT_EQ(buf.deserialize_with_meta(&s1), 0);
- EXPECT_EQ(buf.cur_offset(), 29u);
+ EXPECT_EQ(buf.cur_offset(), 32u);
EXPECT_EQ(buf.deserialize_with_meta(&s2), 0);
- EXPECT_EQ(buf.cur_offset(), 42u);
+ EXPECT_EQ(buf.cur_offset(), 45u);
EXPECT_EQ(buf.deserialize_with_meta(&s3), 0);
- EXPECT_EQ(buf.cur_offset(), 56u);
+ EXPECT_EQ(buf.cur_offset(), 62u);
+ EXPECT_EQ(((int) reinterpret_cast<uintptr_t>(buf.buf())) & 7, 0);
+
EXPECT_EQ(u1, 2468u);
EXPECT_STREQ(s1, nullptr);
EXPECT_STREQ(s2, "hello");
@@ -227,18 +273,11 @@ TEST_VM(JBoosterNet, serializationn_string) {
EXPECT_STREQ(ss3, s3);
}
- { MessageBuffer buf(SerializationMode::DESERIALIZE);
- copy_message_buffer(buf, buf0);
- char s1[1];
- ASSERT_DEATH(buf.deserialize_with_meta(&s1), "");
- }
-
{ MessageBuffer buf(SerializationMode::DESERIALIZE);
copy_message_buffer(buf, buf0);
char s1[64];
EXPECT_EQ(buf.deserialize_with_meta(&s1), 0);
EXPECT_STREQ(ss1, s1);
- ASSERT_DEATH(buf.deserialize_with_meta(&s1), "");
}
{ MessageBuffer buf(SerializationMode::DESERIALIZE);
@@ -269,8 +308,20 @@ TEST_VM(JBoosterNet, serializationn_string) {
}
}
-TEST(JBoosterNet, serializationn_crash) {
- int err;
+#ifdef ASSERT
+
+TEST_VM_ASSERT_MSG(JBoosterNet, serializationn_string_crash_null, ".*cannot set array to null") {
+ MessageBuffer buf(SerializationMode::BOTH);
+ const char* s = nullptr;
+ EXPECT_EQ(buf.serialize_with_meta(&s), 0);
+
+ char s1[8];
+ buf.reset_cur_offset();
+ buf.deserialize_with_meta(&s1); // should crash here
+ ASSERT_TRUE(false);
+}
+
+TEST_VM_ASSERT_MSG(JBoosterNet, serializationn_string_crash_arr_too_small, ".*array index out of bounds") {
MessageBuffer buf(SerializationMode::BOTH);
const char* s = "hello";
EXPECT_EQ(buf.serialize_with_meta(&s), 0);
@@ -282,12 +333,12 @@ TEST(JBoosterNet, serializationn_crash) {
char s2[5];
buf.reset_cur_offset();
- bool old = SuppressFatalErrorMessage;
- SuppressFatalErrorMessage = true;
- ASSERT_DEATH(buf.deserialize_with_meta(&s2), "");
- SuppressFatalErrorMessage = old;
+ buf.deserialize_with_meta(&s2); // should crash here
+ ASSERT_TRUE(false);
}
+#endif // ASSERT
+
TEST(JBoosterNet, serializationn_wrappers) {
MessageBuffer buf(SerializationMode::BOTH);
uint32_t mem_size = 16u * 1024;
@@ -303,7 +354,7 @@ TEST(JBoosterNet, serializationn_wrappers) {
ga.append(&s4);
ArrayWrapper<StringWrapper> aw(&ga);
EXPECT_EQ(buf.serialize_with_meta(&aw), 0);
- EXPECT_EQ(buf.cur_offset(), 0u + (4 + 4) + (1 + 2 + 3 + 4 + 4 * (4 + 4)));
+ EXPECT_EQ(buf.cur_offset(), 0u + (4 + 4) + ((1 + 3) + (2 + 2) + (3 + 1) + 4 + 4 * (4 + 4)));
char* mem = NEW_C_HEAP_ARRAY(char, mem_size, mtJBooster);
memset(mem, 0x68, mem_size);
@@ -385,6 +436,30 @@ TEST(JBoosterNet, serializationn_file_wrapper) {
FileUtils::remove(file_name2);
}
+TEST(JBoosterNet, serializationn_others) {
+ MessageBuffer buf(SerializationMode::BOTH);
+
+ {
+ JClientBoostLevel lvl;
+ lvl.set_allow_clr(true);
+ lvl.set_allow_aot(true);
+ lvl.set_enable_cds_agg(true);
+ EXPECT_EQ(buf.serialize_with_meta(&lvl), 0);
+ }
+
+ buf.reset_cur_offset();
+
+ {
+ JClientBoostLevel lvl;
+ EXPECT_EQ(buf.deserialize_with_meta(&lvl), 0);
+ EXPECT_EQ(lvl.is_clr_allowed(), true);
+ EXPECT_EQ(lvl.is_cds_allowed(), false);
+ EXPECT_EQ(lvl.is_aot_allowed(), true);
+ EXPECT_EQ(lvl.is_aot_pgo_enabled(), false);
+ EXPECT_EQ(lvl.is_cds_agg_enabled(), true);
+ }
+}
+
TEST(JBoosterNet, expansion_of_message_buffer) {
MessageBuffer buf(SerializationMode::SERIALIZE);
ASSERT_EQ(buf.buf_size(), 4096u);
--
2.22.0