Path: blob/master/runtime/compiler/net/Message.hpp
6000 views
/*******************************************************************************1* Copyright (c) 2020, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#ifndef MESSAGE_H23#define MESSAGE_H2425#include <vector>26#include <stdlib.h>27#include "net/MessageBuffer.hpp"28#include "net/MessageTypes.hpp"29#include "OMR/Bytes.hpp" // for alignNoCheck3031namespace JITServer32{33/**34@class Message35@brief Representation of a JITServer remote message.3637All of the actual data and metadata is stored inside MessageBuffer,38this class just provides an interface to access/add it.39This is done to minimize the amount of copying when sending/receiving40messages over the network.4142Each message contains an offset to metadata and a vector of offsets to data descriptors,43where each descriptor describes a single value sent inside the message.44*/45class Message46{47public:48/**49@class MetaData50@brief Describes general parameters of a message: number of datapoints, message type, and version.5152It is assumed that the MetaData immediately follows the messages size53which is encoded as a uint32_t54*/55struct MetaData56{57MetaData() :58_version(0), _config(0), _type(MessageType_MAXTYPE), _numDataPoints(0)59{}60uint32_t _version;61uint32_t _config; // includes JITServerCompatibilityFlags which must match62MessageType _type;63uint16_t _numDataPoints;6465void init()66{67_version = 0;68_config = 0;69_type = MessageType_MAXTYPE;70_numDataPoints = 0;71}72};7374/**75@brief Utility function that builds the "full version" of client/server as76a composition of the version number and compatibility flags.77*/78static uint64_t buildFullVersion(uint32_t version, uint32_t config)79{80return (((uint64_t)config) << 32) | version;81}8283/**84@class DataDescriptor85@brief Metadata containing the type and size of a single value in a message8687A DataDescriptor needs to be aligned on a 32-bit boundary. Because of this88requirement, the data following the descriptor needs to be padded to a8932-bit boundary90*/91struct DataDescriptor92{93// Data types that can be sent in a message94// Adding new types is possible, as long as95// serialization/deserialization functions96// are added to RawTypeConvert97enum DataType : uint8_t98{99INT32,100INT64,101UINT32,102UINT64,103BOOL,104STRING,105OBJECT, // only trivially-copyable; pointers fall into this category106ENUM,107VECTOR,108SIMPLE_VECTOR, // vector whose elements are trivially-copyable and less than 256 bytes109EMPTY_VECTOR,110TUPLE,111LAST_TYPE112};113static const char* const _descriptorNames[];114/**115@brief Constructor116117@param type The type of the data described by the descriptor118@param payloadSize Size of the real data (excluding any required padding)119120*/121DataDescriptor(DataType type, uint32_t payloadSize) : _type(type), _dataOffset(0), _vectorElementSize(0)122{123// Round the _size up to a 4-byte multiple to ensure that the124// descriptor coming after this data point is 4-byte aligned125_size = OMR::alignNoCheck(payloadSize, sizeof(uint32_t));126_paddingSize = static_cast<uint8_t>(_size - payloadSize);127}128DataType getDataType() const { return _type; }129uint32_t getPayloadSize() const { return _size - _paddingSize - _dataOffset; }130uint32_t getTotalSize() const { return _size; }131uint8_t getPaddingSize() const { return _paddingSize; }132uint8_t getDataOffset() const { return _dataOffset; }133uint8_t getVectorElementSize() const { return _vectorElementSize; }134void setVectorElementSize(uint8_t sz) { _vectorElementSize = sz; }135136/**137@brief Initialize descriptor with values give as parameters.138139@param type The type of data described by descriptor140@param totalSize Total size of data following the descriptor141@param paddingSize Size of padding added after the real payload (included in totalSize)142@param dataOffset Distance from end of descriptor to start of real payload (included in totalSize)143*/144void init(DataType type, uint32_t totalSize, uint8_t paddingSize, uint8_t dataOffset)145{146_type = type;147_paddingSize = paddingSize;148_dataOffset = dataOffset;149_vectorElementSize = 0;150_size = totalSize;151}152153/**154@brief Adjust an existing descriptor by adding some offset to real payload155156@param initialPadding Distance from end of descriptor to start of real payload (included in totalSize)157*/158void addInitialPadding(uint8_t initialPadding)159{160TR_ASSERT(_dataOffset == 0, "Initial padding added twice");161TR_ASSERT(initialPadding == 4, "Current implementation assumes only 4 bytes of padding"); // because we add 4 bytes to align on a 8-byte boundary162_dataOffset = initialPadding;163_size += initialPadding; // Total size increases as well164}165166/**167@brief Tells if data attached to this descriptor is a type that168can be directly copied from its address into the contiguous buffer.169170Currently, vectors and tuples are the only non-primitive supported types.171Note: while vectors of primitive types could be copied directly if you copy172from &v[0], it will not work if it's a vector of vectors, or a vector of tuples.173174@return Whether the data descriptor is primitive175*/176bool isPrimitive() const { return _type != VECTOR && _type != TUPLE; }177178/**179@brief Get the pointer to the beginning of data attached to this descriptor.180181This assumes that the data is located after the descriptor at some182some offset, no more than 255 bytes away (typically such offset is 0).183This allows us to align data on a natural boundary.184185@return A pointer to the beginning of the data186*/187void *getDataStart()188{189return static_cast<void *>(static_cast<char*>(static_cast<void*>(this + 1)) + _dataOffset);190}191192/**193@brief Get a pointer to the beginning of the next descriptor in the MessageBuffer.194195@return Returns a pointer to the following descriptor in the MessageBuffer196*/197DataDescriptor* getNextDescriptor()198{199return static_cast<DataDescriptor*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(this + 1)) + _size));200}201202uint32_t print(uint32_t nestingLevel);203private:204DataType _type; // Message type on 8 bits205uint8_t _paddingSize; // How many bytes are actually used for padding (0-3)206uint8_t _dataOffset; // Offset from DataDescriptor to actual data207uint8_t _vectorElementSize; // Size of an element for SIMPLE_VECTORs208uint32_t _size; // Size of the data segment, which can include nested data209}; // struct DataDescriptor210211Message()212{213// Reserve space for encoding the size and MetaData.214// These will be populated at a later time215_buffer.reserveValue<uint32_t>(); // Reserve space for encoding the size216_buffer.reserveValue<Message::MetaData>();217218getMetaData()->init();219}220221MetaData *getMetaData() const222{223return _buffer.getValueAtOffset<MetaData>(sizeof(uint32_t)); // sizeof(uint32_t) represents the space for message size224}225226/**227@brief Add a new data point to the message.228229Writes the descriptor and attached data to the MessageBuffer230and updates the message structure. If the attached data is not231aligned on a 32-bit boundary, some padding will be written as well.232233@param desc Descriptor for the new data234@param dataStart Pointer to the new data235@param needs64BitAlignment Whether data following the descriptor needs to be 64-bit aligned236237@return The total amount of data written (including padding, but not including the descriptor)238*/239uint32_t addData(const DataDescriptor &desc, const void *dataStart, bool needs64BitAlignment = false);240241/**242@brief Allocate space for a descriptor in the MessageBuffer243and update the message structure without writing any actual data.244245This method is needed for some specific cases, mainly for writing246non-primitive data points.247248@return The offset to the descriptor reserved249*/250uint32_t reserveDescriptor()251{252uint32_t descOffset = _buffer.reserveValue<DataDescriptor>();253_descriptorOffsets.push_back(descOffset);254return descOffset;255}256257/**258@brief Get a pointer to the descriptor at given index259260@param idx Index of the descriptor261262@return A pointer to the descriptor263*/264DataDescriptor *getDescriptor(size_t idx) const265{266TR_ASSERT(idx < _descriptorOffsets.size(), "Out-of-bounds access for _descriptorOffsets");267uint32_t offset = _descriptorOffsets[idx];268return _buffer.getValueAtOffset<DataDescriptor>(offset);269}270271/**272@brief Get a pointer to the last descriptor added to the message.273*/274DataDescriptor *getLastDescriptor() const275{276return _buffer.getValueAtOffset<DataDescriptor>(_descriptorOffsets.back());277}278279/**280@brief Get the total number of descriptors in the message.281*/282uint32_t getNumDescriptors() const { return _descriptorOffsets.size(); }283284/**285@brief Set message type286287@param type The new message type288*/289void setType(MessageType type) { getMetaData()->_type = type; }290291/**292@brief Get message type293*/294MessageType type() const { return getMetaData()->_type; }295296/**297@brief Serialize the message298299Write total message size to the beginning of message buffer and return pointer to it.300301@return A pointer to the beginning of the serialized message302*/303char *serialize()304{305*_buffer.getValueAtOffset<uint32_t>(0) = _buffer.size();306return _buffer.getBufferStart();307}308309/**310@brief Return the size of the serialized message.311*/312uint32_t serializedSize() { return _buffer.size(); }313314/**315@brief Rebuild the message from the MessageBuffer316317Assuming that the MessageBuffer contains data for a valid318message, rebuilds the message structure, i.e. sets offsets319for metadata and data descriptors.320*/321void deserialize();322323/**324@brief Set serialized size of the message325*/326void setSerializedSize(uint32_t serializedSize)327{328_buffer.writeValue(serializedSize);329}330331/**332@brief Expand the internal buffer when requiredSize is greater than the capacity333334If expansion occurred, this method copies the number of bytes from the beginning335of the buffer to _curPtr from the old buffer to the new buffer.336*/337void expandBufferIfNeeded(uint32_t requiredSize)338{339_buffer.expandIfNeeded(requiredSize);340}341342/**343@brief Expand the internal buffer to requiredSize and copy numBytesToCopy344from the old buffer into the new one345*/346void expandBuffer(uint32_t requiredSize, uint32_t numBytesToCopy)347{348_buffer.expand(requiredSize, numBytesToCopy);349}350351uint32_t getBufferCapacity() const { return _buffer.getCapacity(); }352353/**354@brief Get the pointer to the start of the buffer.355356This method should be used only to read an incoming message.357358@return A pointer to the beginning of the MessageBuffer359*/360char *getBufferStartForRead() { return _buffer.getBufferStart(); }361362void clearForRead()363{364_descriptorOffsets.clear();365_buffer.clear();366}367368void clearForWrite()369{370_descriptorOffsets.clear();371_buffer.clear();372_buffer.reserveValue<uint32_t>(); // For writing the size373_buffer.reserveValue<MetaData>(); // For writing the metadata374}375376void print();377protected:378std::vector<uint32_t> _descriptorOffsets;379MessageBuffer _buffer; // Buffer used for send/receive operations380};381382383class ServerMessage : public Message384{385};386387class ClientMessage : public Message388{389public:390uint64_t fullVersion()391{392const MetaData* metaData = getMetaData();393return buildFullVersion(metaData->_version, metaData->_config);394}395void setFullVersion(uint32_t version, uint32_t config)396{397MetaData *metaData = getMetaData();398metaData->_version = version;399metaData->_config = config;400}401void clearFullVersion()402{403MetaData *metaData = getMetaData();404metaData->_version = 0;405metaData->_config = 0;406}407};408};409#endif410411412