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((uint32_t) reinterpret_cast(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(_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 + 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 + int serialize_base(Arg v); int serialize_memcpy(const void* from, uint32_t arg_size); template int serialize_no_meta(const Arg& arg); @@ -102,6 +113,8 @@ public: int serialize_with_meta(const Arg* arg_ptr); // deserializers + template + int deserialize_base(Arg& to); int deserialize_memcpy(void* to, uint32_t arg_size); template 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 +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 +inline int MessageBuffer::serialize_base(Arg v) { + static_assert(std::is_arithmetic::value || std::is_enum::value, "Base types or enums only!"); + _smode.assert_can_serialize(); + uint32_t arg_size = (uint32_t) sizeof(Arg); + uint32_t padding = calc_padding(_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 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(_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 +inline int MessageBuffer::deserialize_base(Arg& to) { + static_assert(std::is_arithmetic::value || std::is_enum::value, "Base types or enums only!"); + _smode.assert_can_deserialize(); + uint32_t arg_size = (uint32_t) sizeof(Arg); + uint32_t padding = calc_padding(_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(); - 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 +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 @@ -54,20 +64,35 @@ static constexpr uint32_t calc_classes_hash() { return calc_new_hash(calc_classes_hash(), calc_class_hash()); } -/** - * 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, 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(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 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
* _key_array; - GrowableArray
* _value_array; + GrowableArray* _key_array; + GrowableArray* _value_array; public: - AddressMapKVArray(GrowableArray
* key_array, - GrowableArray
* value_array) : + AddressMapKVArray(GrowableArray* key_array, + GrowableArray* 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(kv_node->key())); + _value_array->append(reinterpret_cast(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
* key_array, - GrowableArray
* value_array, +void JClientSessionData::klass_array(GrowableArray* key_array, + GrowableArray* value_array, Thread* thread) { AddressMapKVArray array(key_array, value_array); _k_c2s.for_each(array, thread); } -void JClientSessionData::klass_pointer_map_to_server(GrowableArray
* klass_array, Thread* thread) { - for (GrowableArrayIterator
iter = klass_array->begin(); +void JClientSessionData::klass_pointer_map_to_server(GrowableArray* klass_array, Thread* thread) { + for (GrowableArrayIterator iter = klass_array->begin(); iter != klass_array->end(); ++iter) { - InstanceKlass* klass = (InstanceKlass*) (*iter); + InstanceKlass* klass = reinterpret_cast(*iter); Array* 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
* key_array, GrowableArray
* value_array, Thread* thread); + void klass_array(GrowableArray* key_array, GrowableArray* value_array, Thread* thread); - void klass_pointer_map_to_server(GrowableArray
* klass_array, Thread* thread); + void klass_pointer_map_to_server(GrowableArray* 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
client_klass_array; - GrowableArray
server_klass_array; + GrowableArray client_klass_array; + GrowableArray server_klass_array; ss().session_data()->klass_array(&client_klass_array, &server_klass_array, THREAD); { - ArrayWrapper
aw(&client_klass_array); + ArrayWrapper 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(0); // should not pass the compilation + EXPECT_EQ(calc_padding(123), 0u); + EXPECT_EQ(calc_padding(124), 0u); + EXPECT_EQ(calc_padding(123), 1u); + EXPECT_EQ(calc_padding(120), 0u); + EXPECT_EQ(calc_padding(0), 0u); + EXPECT_EQ(calc_padding(1), 3u); + EXPECT_EQ(calc_padding(2), 2u); + EXPECT_EQ(calc_padding(3), 1u); + EXPECT_EQ(calc_padding(4), 0u); + EXPECT_EQ(calc_padding(400), 0u); + EXPECT_EQ(calc_padding(1), 7u); + EXPECT_EQ(calc_padding(3), 5u); + EXPECT_EQ(calc_padding(12), 4u); + EXPECT_EQ(calc_padding(7), 1u); + + EXPECT_EQ(calc_buf_start(reinterpret_cast(7)), reinterpret_cast(8)); + EXPECT_EQ(calc_buf_start(reinterpret_cast(9)), reinterpret_cast(16)); + EXPECT_EQ(calc_buf_start(reinterpret_cast(12)), reinterpret_cast(16)); + EXPECT_EQ(calc_buf_start(reinterpret_cast(65535)), reinterpret_cast(65536)); + EXPECT_EQ(calc_buf_start(reinterpret_cast(65536)), reinterpret_cast(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(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(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 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