Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/net/Message.hpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2020, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#ifndef MESSAGE_H
24
#define MESSAGE_H
25
26
#include <vector>
27
#include <stdlib.h>
28
#include "net/MessageBuffer.hpp"
29
#include "net/MessageTypes.hpp"
30
#include "OMR/Bytes.hpp" // for alignNoCheck
31
32
namespace JITServer
33
{
34
/**
35
@class Message
36
@brief Representation of a JITServer remote message.
37
38
All of the actual data and metadata is stored inside MessageBuffer,
39
this class just provides an interface to access/add it.
40
This is done to minimize the amount of copying when sending/receiving
41
messages over the network.
42
43
Each message contains an offset to metadata and a vector of offsets to data descriptors,
44
where each descriptor describes a single value sent inside the message.
45
*/
46
class Message
47
{
48
public:
49
/**
50
@class MetaData
51
@brief Describes general parameters of a message: number of datapoints, message type, and version.
52
53
It is assumed that the MetaData immediately follows the messages size
54
which is encoded as a uint32_t
55
*/
56
struct MetaData
57
{
58
MetaData() :
59
_version(0), _config(0), _type(MessageType_MAXTYPE), _numDataPoints(0)
60
{}
61
uint32_t _version;
62
uint32_t _config; // includes JITServerCompatibilityFlags which must match
63
MessageType _type;
64
uint16_t _numDataPoints;
65
66
void init()
67
{
68
_version = 0;
69
_config = 0;
70
_type = MessageType_MAXTYPE;
71
_numDataPoints = 0;
72
}
73
};
74
75
/**
76
@brief Utility function that builds the "full version" of client/server as
77
a composition of the version number and compatibility flags.
78
*/
79
static uint64_t buildFullVersion(uint32_t version, uint32_t config)
80
{
81
return (((uint64_t)config) << 32) | version;
82
}
83
84
/**
85
@class DataDescriptor
86
@brief Metadata containing the type and size of a single value in a message
87
88
A DataDescriptor needs to be aligned on a 32-bit boundary. Because of this
89
requirement, the data following the descriptor needs to be padded to a
90
32-bit boundary
91
*/
92
struct DataDescriptor
93
{
94
// Data types that can be sent in a message
95
// Adding new types is possible, as long as
96
// serialization/deserialization functions
97
// are added to RawTypeConvert
98
enum DataType : uint8_t
99
{
100
INT32,
101
INT64,
102
UINT32,
103
UINT64,
104
BOOL,
105
STRING,
106
OBJECT, // only trivially-copyable; pointers fall into this category
107
ENUM,
108
VECTOR,
109
SIMPLE_VECTOR, // vector whose elements are trivially-copyable and less than 256 bytes
110
EMPTY_VECTOR,
111
TUPLE,
112
LAST_TYPE
113
};
114
static const char* const _descriptorNames[];
115
/**
116
@brief Constructor
117
118
@param type The type of the data described by the descriptor
119
@param payloadSize Size of the real data (excluding any required padding)
120
121
*/
122
DataDescriptor(DataType type, uint32_t payloadSize) : _type(type), _dataOffset(0), _vectorElementSize(0)
123
{
124
// Round the _size up to a 4-byte multiple to ensure that the
125
// descriptor coming after this data point is 4-byte aligned
126
_size = OMR::alignNoCheck(payloadSize, sizeof(uint32_t));
127
_paddingSize = static_cast<uint8_t>(_size - payloadSize);
128
}
129
DataType getDataType() const { return _type; }
130
uint32_t getPayloadSize() const { return _size - _paddingSize - _dataOffset; }
131
uint32_t getTotalSize() const { return _size; }
132
uint8_t getPaddingSize() const { return _paddingSize; }
133
uint8_t getDataOffset() const { return _dataOffset; }
134
uint8_t getVectorElementSize() const { return _vectorElementSize; }
135
void setVectorElementSize(uint8_t sz) { _vectorElementSize = sz; }
136
137
/**
138
@brief Initialize descriptor with values give as parameters.
139
140
@param type The type of data described by descriptor
141
@param totalSize Total size of data following the descriptor
142
@param paddingSize Size of padding added after the real payload (included in totalSize)
143
@param dataOffset Distance from end of descriptor to start of real payload (included in totalSize)
144
*/
145
void init(DataType type, uint32_t totalSize, uint8_t paddingSize, uint8_t dataOffset)
146
{
147
_type = type;
148
_paddingSize = paddingSize;
149
_dataOffset = dataOffset;
150
_vectorElementSize = 0;
151
_size = totalSize;
152
}
153
154
/**
155
@brief Adjust an existing descriptor by adding some offset to real payload
156
157
@param initialPadding Distance from end of descriptor to start of real payload (included in totalSize)
158
*/
159
void addInitialPadding(uint8_t initialPadding)
160
{
161
TR_ASSERT(_dataOffset == 0, "Initial padding added twice");
162
TR_ASSERT(initialPadding == 4, "Current implementation assumes only 4 bytes of padding"); // because we add 4 bytes to align on a 8-byte boundary
163
_dataOffset = initialPadding;
164
_size += initialPadding; // Total size increases as well
165
}
166
167
/**
168
@brief Tells if data attached to this descriptor is a type that
169
can be directly copied from its address into the contiguous buffer.
170
171
Currently, vectors and tuples are the only non-primitive supported types.
172
Note: while vectors of primitive types could be copied directly if you copy
173
from &v[0], it will not work if it's a vector of vectors, or a vector of tuples.
174
175
@return Whether the data descriptor is primitive
176
*/
177
bool isPrimitive() const { return _type != VECTOR && _type != TUPLE; }
178
179
/**
180
@brief Get the pointer to the beginning of data attached to this descriptor.
181
182
This assumes that the data is located after the descriptor at some
183
some offset, no more than 255 bytes away (typically such offset is 0).
184
This allows us to align data on a natural boundary.
185
186
@return A pointer to the beginning of the data
187
*/
188
void *getDataStart()
189
{
190
return static_cast<void *>(static_cast<char*>(static_cast<void*>(this + 1)) + _dataOffset);
191
}
192
193
/**
194
@brief Get a pointer to the beginning of the next descriptor in the MessageBuffer.
195
196
@return Returns a pointer to the following descriptor in the MessageBuffer
197
*/
198
DataDescriptor* getNextDescriptor()
199
{
200
return static_cast<DataDescriptor*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(this + 1)) + _size));
201
}
202
203
uint32_t print(uint32_t nestingLevel);
204
private:
205
DataType _type; // Message type on 8 bits
206
uint8_t _paddingSize; // How many bytes are actually used for padding (0-3)
207
uint8_t _dataOffset; // Offset from DataDescriptor to actual data
208
uint8_t _vectorElementSize; // Size of an element for SIMPLE_VECTORs
209
uint32_t _size; // Size of the data segment, which can include nested data
210
}; // struct DataDescriptor
211
212
Message()
213
{
214
// Reserve space for encoding the size and MetaData.
215
// These will be populated at a later time
216
_buffer.reserveValue<uint32_t>(); // Reserve space for encoding the size
217
_buffer.reserveValue<Message::MetaData>();
218
219
getMetaData()->init();
220
}
221
222
MetaData *getMetaData() const
223
{
224
return _buffer.getValueAtOffset<MetaData>(sizeof(uint32_t)); // sizeof(uint32_t) represents the space for message size
225
}
226
227
/**
228
@brief Add a new data point to the message.
229
230
Writes the descriptor and attached data to the MessageBuffer
231
and updates the message structure. If the attached data is not
232
aligned on a 32-bit boundary, some padding will be written as well.
233
234
@param desc Descriptor for the new data
235
@param dataStart Pointer to the new data
236
@param needs64BitAlignment Whether data following the descriptor needs to be 64-bit aligned
237
238
@return The total amount of data written (including padding, but not including the descriptor)
239
*/
240
uint32_t addData(const DataDescriptor &desc, const void *dataStart, bool needs64BitAlignment = false);
241
242
/**
243
@brief Allocate space for a descriptor in the MessageBuffer
244
and update the message structure without writing any actual data.
245
246
This method is needed for some specific cases, mainly for writing
247
non-primitive data points.
248
249
@return The offset to the descriptor reserved
250
*/
251
uint32_t reserveDescriptor()
252
{
253
uint32_t descOffset = _buffer.reserveValue<DataDescriptor>();
254
_descriptorOffsets.push_back(descOffset);
255
return descOffset;
256
}
257
258
/**
259
@brief Get a pointer to the descriptor at given index
260
261
@param idx Index of the descriptor
262
263
@return A pointer to the descriptor
264
*/
265
DataDescriptor *getDescriptor(size_t idx) const
266
{
267
TR_ASSERT(idx < _descriptorOffsets.size(), "Out-of-bounds access for _descriptorOffsets");
268
uint32_t offset = _descriptorOffsets[idx];
269
return _buffer.getValueAtOffset<DataDescriptor>(offset);
270
}
271
272
/**
273
@brief Get a pointer to the last descriptor added to the message.
274
*/
275
DataDescriptor *getLastDescriptor() const
276
{
277
return _buffer.getValueAtOffset<DataDescriptor>(_descriptorOffsets.back());
278
}
279
280
/**
281
@brief Get the total number of descriptors in the message.
282
*/
283
uint32_t getNumDescriptors() const { return _descriptorOffsets.size(); }
284
285
/**
286
@brief Set message type
287
288
@param type The new message type
289
*/
290
void setType(MessageType type) { getMetaData()->_type = type; }
291
292
/**
293
@brief Get message type
294
*/
295
MessageType type() const { return getMetaData()->_type; }
296
297
/**
298
@brief Serialize the message
299
300
Write total message size to the beginning of message buffer and return pointer to it.
301
302
@return A pointer to the beginning of the serialized message
303
*/
304
char *serialize()
305
{
306
*_buffer.getValueAtOffset<uint32_t>(0) = _buffer.size();
307
return _buffer.getBufferStart();
308
}
309
310
/**
311
@brief Return the size of the serialized message.
312
*/
313
uint32_t serializedSize() { return _buffer.size(); }
314
315
/**
316
@brief Rebuild the message from the MessageBuffer
317
318
Assuming that the MessageBuffer contains data for a valid
319
message, rebuilds the message structure, i.e. sets offsets
320
for metadata and data descriptors.
321
*/
322
void deserialize();
323
324
/**
325
@brief Set serialized size of the message
326
*/
327
void setSerializedSize(uint32_t serializedSize)
328
{
329
_buffer.writeValue(serializedSize);
330
}
331
332
/**
333
@brief Expand the internal buffer when requiredSize is greater than the capacity
334
335
If expansion occurred, this method copies the number of bytes from the beginning
336
of the buffer to _curPtr from the old buffer to the new buffer.
337
*/
338
void expandBufferIfNeeded(uint32_t requiredSize)
339
{
340
_buffer.expandIfNeeded(requiredSize);
341
}
342
343
/**
344
@brief Expand the internal buffer to requiredSize and copy numBytesToCopy
345
from the old buffer into the new one
346
*/
347
void expandBuffer(uint32_t requiredSize, uint32_t numBytesToCopy)
348
{
349
_buffer.expand(requiredSize, numBytesToCopy);
350
}
351
352
uint32_t getBufferCapacity() const { return _buffer.getCapacity(); }
353
354
/**
355
@brief Get the pointer to the start of the buffer.
356
357
This method should be used only to read an incoming message.
358
359
@return A pointer to the beginning of the MessageBuffer
360
*/
361
char *getBufferStartForRead() { return _buffer.getBufferStart(); }
362
363
void clearForRead()
364
{
365
_descriptorOffsets.clear();
366
_buffer.clear();
367
}
368
369
void clearForWrite()
370
{
371
_descriptorOffsets.clear();
372
_buffer.clear();
373
_buffer.reserveValue<uint32_t>(); // For writing the size
374
_buffer.reserveValue<MetaData>(); // For writing the metadata
375
}
376
377
void print();
378
protected:
379
std::vector<uint32_t> _descriptorOffsets;
380
MessageBuffer _buffer; // Buffer used for send/receive operations
381
};
382
383
384
class ServerMessage : public Message
385
{
386
};
387
388
class ClientMessage : public Message
389
{
390
public:
391
uint64_t fullVersion()
392
{
393
const MetaData* metaData = getMetaData();
394
return buildFullVersion(metaData->_version, metaData->_config);
395
}
396
void setFullVersion(uint32_t version, uint32_t config)
397
{
398
MetaData *metaData = getMetaData();
399
metaData->_version = version;
400
metaData->_config = config;
401
}
402
void clearFullVersion()
403
{
404
MetaData *metaData = getMetaData();
405
metaData->_version = 0;
406
metaData->_config = 0;
407
}
408
};
409
};
410
#endif
411
412