Path: blob/master/runtime/compiler/net/MessageBuffer.hpp
6000 views
/*******************************************************************************1* Copyright (c) 2020, 2021 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_BUFFER_H23#define MESSAGE_BUFFER_H2425#include "env/jittypes.h"26#include "env/TRMemory.hpp"27#include "OMR/Bytes.hpp" // for alignNoCheck28#include "env/CompilerEnv.hpp"2930namespace JITServer31{32/**33@class MessageBuffer34@brief A wrapper around a contiguous, persistent memory allocated buffer35for storing a JITServer message.3637The buffer is extensible, i.e. when the current capacity is reached, a new,38larger buffer can be allocated and data copied there.39Since reallocation causes addresses of values inside the buffer to change, read/write operations40return an offset into the buffer to indicate the location of data, instead of pointers.4142Method getValueAtOffset returns a pointer to data at a given offset, but be mindful that43the pointer might become invalid if more data is added to the buffer.4445Variable _curPtr defines the boundary of the current data. Reading/writing to/from buffer46will always advance the pointer.47*/48class MessageBuffer49{50public:51MessageBuffer();5253~MessageBuffer()54{55freeMemory(_storage);56}575859/**60@brief Get the current active size of the buffer.6162Note: this returns the number of bytes written to the buffer so far,63NOT the overall capacity of the buffer. Capacity is the number of64bytes allocated, but not necessarily used.6566@return the size of the buffer67*/68uint32_t size() const { return _curPtr - _storage; }6970char *getBufferStart() const { return _storage; }7172/**73@brief Return a pointer to the value at given offset inside the buffer.7475Given a type and offset, returns the pointer of that type.76Behavior is only defined if offset does not exceed populated buffer size.7778@return ponter of the specified type at given offset79*/80template <typename T>81T *getValueAtOffset(uint32_t offset) const82{83TR_ASSERT_FATAL(offset < size(), "Offset is outside of buffer bounds");84return reinterpret_cast<T *>(_storage + offset);85}8687/**88@brief Write value of type T to the buffer.8990Copies the value into buffer, expanding it if needed,91and advances _curPtr by sizeof(T) bytes plus some padding92so that the data inside the buffer is always 32-bit aligned93Behavior is undefined if T is not trivially copyable (i.e. not contiguous in memory).9495@param val value to be written9697@return offset to the beginning of written value inside the buffer98*/99template <typename T>100uint32_t writeValue(const T &val)101{102static_assert(std::is_trivially_copyable<T>::value == true, "T must be trivially copyable.");103uint8_t paddingSize = static_cast<uint8_t>(OMR::alignNoCheck(sizeof(T), sizeof(uint32_t)) - sizeof(T));104return writeData(&val, sizeof(T), paddingSize);105}106107/**108@brief Write a given number of bytes into the buffer.109110Copies dataSize bytes from dataStart into the buffer, expanding it if needed,111and advances _curPtr by (dataSize + paddingSize) bytes.112113@param dataStart pointer to the beginning of the data to be written114@param dataSize number of bytes of real data to be written115@param paddingSize number of bytes of padding116117@return offset to the beginning of written data inside the buffer118*/119uint32_t writeData(const void *dataStart, uint32_t dataSize, uint8_t paddingSize);120121/**122@brief Reserve memory for a value of type T.123124Advances _curPtr by sizeof(T) bytes, expanding the125buffer if needed.126Behavior is undefined if T is not trivially copyable (i.e. not contiguous in memory).127128@return offset to the beginning of the reserved memory block129*/130template <typename T>131uint32_t reserveValue()132{133expandIfNeeded(size() + sizeof(T));134char *valStart = _curPtr;135_curPtr += sizeof(T);136return offset(valStart);137}138139/**140@brief Read next value of type T from the buffer.141142Assumes that the next unread value in the buffer is of type T.143Advances _curPtr by sizeof(T) bytes.144145@return offset to the beginning of value146*/147template <typename T>148uint32_t readValue()149{150return readData(sizeof(T));151}152153/**154@brief "Read" next dataSize bytes from the buffer.155156Assumes that the buffer contains at least dataSize unread bytes.157Advances _curPtr by dataSize bytes ( this is considered a "read")158159@return offset to the beginning of data160*/161uint32_t readData(uint32_t dataSize)162{163char* data = _curPtr;164_curPtr += dataSize; // Advance cursor165return offset(data); // Return offset before the advance166}167168void clear() { _curPtr = _storage; }169170/**171@brief Check to see if the current pointer in the MessageBuffer is 64-bit aligned.172*/173bool is64BitAligned() { return ((uintptr_t)_curPtr & ((uintptr_t)0x7)) == 0; }174175/**176@brief Moves the current pointer in the MessageBuffer to achieve 64-bit alignment177178@return returns the number of padding bytes required for alignment (0-7)179*/180uint8_t alignCurrentPositionOn64Bit();181182/**183@brief Expand the underlying buffer if more than allocated memory is needed.184185@param requiredSize the number of bytes the buffer needs to fit.186*/187void expandIfNeeded(uint32_t requiredSize);188189/**190@brief Expand the underlying buffer to fit requiredSize and copy numBytesToCopy191from the old buffer to the new buffer when requiredSize is greater than192the capacity, and free the old buffer.193194If requiredSize is greater than _capacity, allocates a new buffer that can fit requiredSize195bytes rounded up to the nearest power of 2,196copies all existing data based on _curPtr location to the new buffer,197and frees the old buffer.198199@param requiredSize the number of bytes the buffer needs to fit.200@param numBytesToCopy the number of bytes that need to be copied over from the old buffer201*/202void expand(uint32_t requiredSize, uint32_t numBytesToCopy);203204uint32_t getCapacity() const { return _capacity; }205206207private:208static const size_t INITIAL_BUFFER_SIZE = 32768; // Initial buffer size is 32K209uint32_t offset(char *addr) const { return addr - _storage; }210char *allocateMemory(uint32_t capacity) { return static_cast<char *>(_allocator.allocate(capacity)); }211void freeMemory(char *storage) { _allocator.deallocate(storage); }212uint32_t computeRequiredCapacity(uint32_t requiredSize);213214uint32_t _capacity;215char *_storage;216char *_curPtr;217TR::PersistentAllocator &_allocator;218};219};220#endif221222223