Realm
A distributed, event-based tasking library
Loading...
Searching...
No Matches
codedesc.h
Go to the documentation of this file.
1/*
2 * Copyright 2025 Stanford University, NVIDIA Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18// constructs for describing code blobs to Realm
19
20#ifndef REALM_CODEDESC_H
21#define REALM_CODEDESC_H
22
23#include "realm/realm_config.h"
24
25#include "realm/serialize.h"
26
27#include <stddef.h>
28#include <vector>
29#include <iostream>
30
31namespace Realm {
32
33 // we need a way to describe types of functions and arguments - every JIT framework
34 // (e.g. llvm) has their own way of doing this, so this is intended to be a generic
35 // version that knows how to convert to/from implementation-specific versions
36
37 // Types have value semantics and are implemented as a tagged union
38 class Type {
39 public:
40 // default constructor creates an invalid type
41 Type(void);
42
43 // copy and assignment do what you want
44 Type(const Type &rhs);
45 Type &operator=(const Type &rhs);
46
47 ~Type(void);
48
49 // construction of useful types is usually done via template-fu
50 template <typename T>
51 static Type from_cpp_type(void);
52
53 template <typename T>
54 static Type from_cpp_value(const T &value);
55
56 // exact equality
57 bool operator==(const Type &rhs) const;
58 bool operator!=(const Type &rhs) const;
59
60 // testing for the kind
61 bool is_valid(void) const;
62
63 template <typename T>
64 bool is(void) const;
65
66 template <typename T>
67 T &as(void);
68
69 template <typename T>
70 const T &as(void) const;
71
72 // accessors/mutators for common fields
73 size_t &size_bits(void);
74 const size_t &size_bits(void) const;
75
76 size_t &alignment_bits(void);
77 const size_t &alignment_bits(void) const;
78
79 // pretty-printing
80 friend std::ostream &operator<<(std::ostream &os, const Type &t);
81
82 // serializer/deserializer functions
83 template <typename S>
84 friend bool serialize(S &os, const Type &t);
85
86 template <typename S>
87 friend bool deserialize(S &os, Type &t);
88
89#define REALM_TYPE_KINDS(__func__) \
90 __func__(OpaqueKind, OpaqueFields, f_opaque) __func__( \
91 IntegerKind, IntegerFields, \
92 f_integer) __func__(FloatingPointKind, FloatingPointFields, \
93 f_float) __func__(PointerKind, PointerFields, \
94 f_pointer) __func__(FunctionPointerKind, \
95 FunctionPointerFields, \
96 f_funcptr)
97
98 enum Kind
99 {
101#define KINDS_ENUM(k, f, n) k,
103#undef KINDS_ENUM
104 };
105
106 protected:
107#define FIELDOBJ_METHODS(classname) \
108 void destroy(void); \
109 void copy_from(const classname &rhs); \
110 bool is_equal(const classname &rhs) const; \
111 template <typename S> \
112 bool serialize(S &s) const; \
113 template <typename S> \
114 bool deserialize(S &s)
122 struct OpaqueFields : public CommonFields {
123 // nothing
124
126 };
133 // nothing
134
136 };
149#undef FIELDOBJ_METHODS
150
151 union {
153#define FIELDS_ENTRY(k, f, n) f n;
155#undef FIELDS_ENTRY
156 };
157
158 void destroy(void);
159 void copy_from(const Type &rhs);
160
161 // only used by subclass constructors
162 Type(Kind _kind, size_t _size_bits, size_t _alignment_bits);
163 };
164
165 class OpaqueType : public Type {
166 public:
167 static const Type::Kind KIND = OpaqueKind;
168
169 OpaqueType(size_t _size_bits, size_t _alignment_bits = 0);
170 };
171
172 class IntegerType : public Type {
173 public:
174 static const Type::Kind KIND = IntegerKind;
175
176 IntegerType(size_t _size_bits, bool _signed, size_t _alignment_bits = 0);
177
178 bool &is_signed(void);
179 const bool &is_signed(void) const;
180 };
181
182 class PointerType : public Type {
183 public:
184 static const Type::Kind KIND = PointerKind;
185
186 PointerType(const Type &_base_type, bool _const = false, size_t _size_bits = 0,
187 size_t _alignment_bits = 0);
188
190 const Type &base_type(void) const;
191
192 bool &is_const(void);
193 const bool &is_const(void) const;
194 };
195
196 class FunctionPointerType : public Type {
197 public:
198 static const Type::Kind KIND = FunctionPointerKind;
199
200 // different constructors for each number of parameters...
201 FunctionPointerType(const Type &_return_type, size_t _size_bits = 0,
202 size_t _alignment_bits = 0);
203 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
204 size_t _size_bits = 0, size_t _alignment_bits = 0);
205 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
206 const Type &_param2_type, size_t _size_bits = 0,
207 size_t _alignment_bits = 0);
208 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
209 const Type &_param2_type, const Type &_param3_type,
210 size_t _size_bits = 0, size_t _alignment_bits = 0);
211 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
212 const Type &_param2_type, const Type &_param3_type,
213 const Type &_param4_type, size_t _size_bits = 0,
214 size_t _alignment_bits = 0);
215 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
216 const Type &_param2_type, const Type &_param3_type,
217 const Type &_param4_type, const Type &_param5_type,
218 size_t _size_bits = 0, size_t _alignment_bits = 0);
219 FunctionPointerType(const Type &_return_type, const Type &_param1_type,
220 const Type &_param2_type, const Type &_param3_type,
221 const Type &_param4_type, const Type &_param5_type,
222 const Type &_param6_type, size_t _size_bits = 0,
223 size_t _alignment_bits = 0);
224
226 const Type &return_type(void) const;
227
228 std::vector<Type> &param_types(void);
229 const std::vector<Type> &param_types(void) const;
230 };
231
232 namespace TypeConv {
233 // these generate a Type object from a C++ type or value
234 template <typename T>
236 template <typename T>
237 Type from_cpp_value(const T &value);
238 }; // namespace TypeConv
239
240 // a CodeDescriptor is an object that describes a blob of code as a callable function
241 // it includes:
242 // a) its type, as a Type object
243 // b) zero or more "implementations" (e.g. function pointer, or LLVM IR, or DSO
244 // reference) c) zero or more "properties" (e.g. "this function is pure")
245
246 class CodeImplementation;
247 class CodeProperty;
248
250 public:
252 explicit CodeDescriptor(const Type &_t);
253
254 // a common pattern is to make a code descriptor from a function pointer - we
255 // can use template magic to do this all at once
256 // TODO: use some SFINAE trick to make this only work if T is a function pointer?
257 template <typename T>
258 explicit CodeDescriptor(T fnptr);
259
260 // copy and assignment
263
265
266 // erase contents
267 void clear(void);
268
270
271 // add an implementation - becomes owned by the descriptor
273
274 // add a property - becomes owned by the descriptor
276
277 const Type &type(void) const;
278 const std::vector<CodeImplementation *> &implementations(void) const;
279 const std::vector<CodeProperty *> &properties(void) const;
280
281 // are any of the code implementations marked as "portable" (i.e.
282 // usable in another process/address space)?
284
285 // attempt to make a portable implementation from what we have
287
288 template <typename T>
289 const T *find_impl(void) const;
290
291 // pretty-printing
292 friend std::ostream &operator<<(std::ostream &os, const CodeDescriptor &cd);
293
294 // serialization/deserialization - note that the standard << serializer will
295 // not serialize non-portable implementations
296 template <typename S>
297 bool serialize(S &serializer, bool portable) const;
298
299 template <typename S>
300 bool deserialize(S &deserializer);
301
302 protected:
303 void copy_from(const CodeDescriptor &rhs);
304
306 std::vector<CodeImplementation *> m_impls;
307 std::vector<CodeProperty *> m_props;
308 };
309
310 template <typename S>
311 bool serialize(S &serializer, const CodeDescriptor &cd);
312
313 template <typename S>
314 bool deserialize(S &deserializer, CodeDescriptor &cd);
315
316 // this is the interface that actual CodeImplementations must follow
318 protected:
319 // not directly constructed
321
322 public:
323 virtual ~CodeImplementation(void);
324
325 virtual CodeImplementation *clone(void) const = 0;
326
327 // is this implementation meaningful in another address space?
328 virtual bool is_portable(void) const = 0;
329
330 // template <typename S>
331 // bool serialize(S& serializer) const;
332
333 template <typename S>
334 static CodeImplementation *deserialize_new(S &deserializer);
335
336 // pretty-printing
337 friend std::ostream &operator<<(std::ostream &os, const CodeImplementation &ci);
338
339 protected:
340 virtual void print(std::ostream &os) const = 0;
341 };
342
343 template <typename S>
344 bool serialize(S &serializer, const CodeImplementation &ci);
345
346 // this is the interface that actual CodePropertys must follow
348 protected:
349 // not directly constructed
351
352 public:
353 virtual ~CodeProperty(void);
354
355 virtual CodeProperty *clone(void) const = 0;
356
357 // is this implementation meaningful in another address space?
358 virtual bool is_portable(void) const = 0;
359
360 // TODO: serialization/deserialization stuff
361 };
362
363 // abstract class that describes a code translator that can convert a code
364 // implementation
365 // of one type into one of another type - in order to be extensible by add-on modules,
366 // it uses c++ dynamic type info support
368 protected:
369 CodeTranslator(const std::string &_name);
370
371 public:
372 virtual ~CodeTranslator(void);
373
374 virtual bool can_translate(const std::type_info &source_impl_type,
375 const std::type_info &target_impl_type) = 0;
376
377 // default version just iterates over all the implementations in the source
378 virtual bool can_translate(const CodeDescriptor &source_codedesc,
379 const std::type_info &target_impl_type);
380
382 const std::type_info &target_impl_type) = 0;
383
384 // default version just iterates over all the implementations in the source
385 virtual CodeImplementation *translate(const CodeDescriptor &source_codedesc,
386 const std::type_info &target_impl_type);
387
388 // template versions when target type is statically known
389 template <typename TARGET_TYPE>
390 bool can_translate(const std::type_info &source_impl_type);
391
392 template <typename TARGET_TYPE>
393 bool can_translate(const CodeDescriptor &source_codedesc);
394
395 template <typename TARGET_TYPE>
396 TARGET_TYPE *translate(const CodeImplementation *source);
397
398 template <typename TARGET_TYPE>
399 TARGET_TYPE *translate(const CodeDescriptor &source_codedesc);
400
401 std::string name;
402 };
403
404 // two simple implementations:
405 // 1) raw function pointers - non-portable
406 // 2) DSO references (i.e. name of shared object, name of symbol) - portable
407
409 public:
410 // note that this implementation forgets the actual function prototype - it's
411 // up to the surrounding CodeDescriptor object to remember that
413
415
416 virtual CodeImplementation *clone(void) const;
417
418 virtual bool is_portable(void) const;
419
420 template <typename T>
421 inline T get_impl(void) const
422 {
423 return reinterpret_cast<T>(fnptr);
424 }
425
426 template <typename S>
427 bool serialize(S &serializer) const;
428
429 template <typename S>
430 static CodeImplementation *deserialize_new(S &deserializer);
431
432 protected:
435
439
440 virtual void print(std::ostream &os) const;
441
442 public:
443 void (*fnptr)();
444 };
445
446#ifdef REALM_USE_DLFCN
447 class REALM_PUBLIC_API DSOReferenceImplementation : public CodeImplementation {
448 public:
449 DSOReferenceImplementation(const std::string &_dso_name,
450 const std::string &_symbol_name);
451
452 virtual ~DSOReferenceImplementation(void);
453
454 virtual CodeImplementation *clone(void) const;
455
456 virtual bool is_portable(void) const;
457
458 template <typename S>
459 bool serialize(S &serializer) const;
460
461 template <typename S>
462 static CodeImplementation *deserialize_new(S &deserializer);
463
464 protected:
465 DSOReferenceImplementation(void);
466
468 DSOReferenceImplementation>
469 serdez_subclass;
470
471 virtual void print(std::ostream &os) const;
472
473#ifdef REALM_USE_DLADDR
474 friend class CodeDescriptor;
475 static DSOReferenceImplementation *
476 cvt_fnptr_to_dsoref(const FunctionPointerImplementation *fpi, bool quiet = false);
477#endif
478 public:
479 std::string dso_name, symbol_name;
480 };
481
482 // converts DSOReferenceImplementation -> FunctionPointerImplementation and
483 // (if dladdr is available) the reverse
484 // NOTE: this is exported for now due to issue #818
485 class REALM_INTERNAL_API_EXTERNAL_LINKAGE DSOCodeTranslator : public CodeTranslator {
486 public:
487 DSOCodeTranslator(void);
488
489 virtual ~DSOCodeTranslator(void);
490
491 virtual bool can_translate(const std::type_info &source_impl_type,
492 const std::type_info &target_impl_type);
493
494 virtual CodeImplementation *translate(const CodeImplementation *source,
495 const std::type_info &target_impl_type);
496
497 // C++ considers the above a "partial override" and wants these defined too
498 virtual bool can_translate(const CodeDescriptor &source_codedesc,
499 const std::type_info &target_impl_type);
500
501 virtual CodeImplementation *translate(const CodeDescriptor &source_codedesc,
502 const std::type_info &target_impl_type);
503
504 protected:
505 std::map<std::string, void *> modules_loaded;
506 };
507#endif
508
509}; // namespace Realm
510
511#include "realm/codedesc.inl"
512
513#undef REALM_TYPE_KINDS
514
515#endif
Definition codedesc.h:249
CodeDescriptor & operator=(const CodeDescriptor &rhs)
const T * find_impl(void) const
void copy_from(const CodeDescriptor &rhs)
bool has_portable_implementations(void) const
CodeDescriptor & set_type(const Type &_t)
friend std::ostream & operator<<(std::ostream &os, const CodeDescriptor &cd)
CodeDescriptor(const Type &_t)
std::vector< CodeProperty * > m_props
Definition codedesc.h:307
bool serialize(S &serializer, bool portable) const
CodeDescriptor & add_implementation(CodeImplementation *impl)
std::vector< CodeImplementation * > m_impls
Definition codedesc.h:306
bool create_portable_implementation(void)
Type m_type
Definition codedesc.h:305
const std::vector< CodeImplementation * > & implementations(void) const
const std::vector< CodeProperty * > & properties(void) const
CodeDescriptor(const CodeDescriptor &rhs)
CodeDescriptor & add_property(CodeProperty *prop)
bool deserialize(S &deserializer)
const Type & type(void) const
Definition codedesc.h:317
virtual bool is_portable(void) const =0
static CodeImplementation * deserialize_new(S &deserializer)
virtual CodeImplementation * clone(void) const =0
friend std::ostream & operator<<(std::ostream &os, const CodeImplementation &ci)
virtual ~CodeImplementation(void)
virtual void print(std::ostream &os) const =0
Definition codedesc.h:347
virtual ~CodeProperty(void)
virtual bool is_portable(void) const =0
virtual CodeProperty * clone(void) const =0
Definition codedesc.h:367
CodeTranslator(const std::string &_name)
bool can_translate(const std::type_info &source_impl_type)
TARGET_TYPE * translate(const CodeDescriptor &source_codedesc)
virtual CodeImplementation * translate(const CodeDescriptor &source_codedesc, const std::type_info &target_impl_type)
virtual CodeImplementation * translate(const CodeImplementation *source, const std::type_info &target_impl_type)=0
virtual bool can_translate(const std::type_info &source_impl_type, const std::type_info &target_impl_type)=0
std::string name
Definition codedesc.h:401
virtual bool can_translate(const CodeDescriptor &source_codedesc, const std::type_info &target_impl_type)
bool can_translate(const CodeDescriptor &source_codedesc)
virtual ~CodeTranslator(void)
TARGET_TYPE * translate(const CodeImplementation *source)
Definition codedesc.h:408
static Serialization::PolymorphicSerdezSubclass< CodeImplementation, FunctionPointerImplementation > serdez_subclass
Definition codedesc.h:438
static CodeImplementation * deserialize_new(S &deserializer)
virtual bool is_portable(void) const
virtual CodeImplementation * clone(void) const
T get_impl(void) const
Definition codedesc.h:421
virtual void print(std::ostream &os) const
FunctionPointerImplementation(void(*_fnptr)())
bool serialize(S &serializer) const
REALM_INTERNAL_API_EXTERNAL_LINKAGE FunctionPointerImplementation(void)
Definition codedesc.h:196
static const Type::Kind KIND
Definition codedesc.h:198
FunctionPointerType(const Type &_return_type, const Type &_param1_type, const Type &_param2_type, const Type &_param3_type, const Type &_param4_type, const Type &_param5_type, size_t _size_bits=0, size_t _alignment_bits=0)
const Type & return_type(void) const
std::vector< Type > & param_types(void)
FunctionPointerType(const Type &_return_type, const Type &_param1_type, const Type &_param2_type, const Type &_param3_type, const Type &_param4_type, const Type &_param5_type, const Type &_param6_type, size_t _size_bits=0, size_t _alignment_bits=0)
FunctionPointerType(const Type &_return_type, const Type &_param1_type, const Type &_param2_type, const Type &_param3_type, size_t _size_bits=0, size_t _alignment_bits=0)
const std::vector< Type > & param_types(void) const
FunctionPointerType(const Type &_return_type, const Type &_param1_type, const Type &_param2_type, size_t _size_bits=0, size_t _alignment_bits=0)
FunctionPointerType(const Type &_return_type, const Type &_param1_type, const Type &_param2_type, const Type &_param3_type, const Type &_param4_type, size_t _size_bits=0, size_t _alignment_bits=0)
FunctionPointerType(const Type &_return_type, const Type &_param1_type, size_t _size_bits=0, size_t _alignment_bits=0)
FunctionPointerType(const Type &_return_type, size_t _size_bits=0, size_t _alignment_bits=0)
Definition codedesc.h:172
const bool & is_signed(void) const
static const Type::Kind KIND
Definition codedesc.h:174
bool & is_signed(void)
IntegerType(size_t _size_bits, bool _signed, size_t _alignment_bits=0)
Definition codedesc.h:165
static const Type::Kind KIND
Definition codedesc.h:167
OpaqueType(size_t _size_bits, size_t _alignment_bits=0)
Definition codedesc.h:182
const bool & is_const(void) const
PointerType(const Type &_base_type, bool _const=false, size_t _size_bits=0, size_t _alignment_bits=0)
bool & is_const(void)
Type & base_type(void)
const Type & base_type(void) const
static const Type::Kind KIND
Definition codedesc.h:184
Definition codedesc.h:38
const size_t & size_bits(void) const
friend bool deserialize(S &os, Type &t)
bool is(void) const
void copy_from(const Type &rhs)
Type & operator=(const Type &rhs)
Kind
Definition codedesc.h:99
@ InvalidKind
Definition codedesc.h:100
friend std::ostream & operator<<(std::ostream &os, const Type &t)
size_t & alignment_bits(void)
size_t & size_bits(void)
void destroy(void)
CommonFields f_common
Definition codedesc.h:152
T & as(void)
bool operator==(const Type &rhs) const
Type(const Type &rhs)
const size_t & alignment_bits(void) const
const T & as(void) const
static Type from_cpp_value(const T &value)
friend bool serialize(S &os, const Type &t)
bool operator!=(const Type &rhs) const
Type(Kind _kind, size_t _size_bits, size_t _alignment_bits)
bool is_valid(void) const
static Type from_cpp_type(void)
#define FIELDS_ENTRY(k, f, n)
Definition codedesc.h:153
#define KINDS_ENUM(k, f, n)
Definition codedesc.h:101
#define REALM_TYPE_KINDS(__func__)
Definition codedesc.h:89
#define REALM_INTERNAL_API_EXTERNAL_LINKAGE
Definition compiler_support.h:218
#define REALM_PUBLIC_API
Definition compiler_support.h:217
Type from_cpp_type(void)
Type from_cpp_value(const T &value)
Definition activemsg.h:38
bool serialize(S &serdez, const ByteArrayRef &a)
bool deserialize(S &serdez, ByteArray &a)
Definition codedesc.h:115
FIELDOBJ_METHODS(CommonFields)
Kind kind
Definition codedesc.h:116
size_t alignment_bits
Definition codedesc.h:118
size_t size_bits
Definition codedesc.h:117
Definition codedesc.h:132
FIELDOBJ_METHODS(FloatingPointFields)
Definition codedesc.h:143
std::vector< Type > * param_types
Definition codedesc.h:145
FIELDOBJ_METHODS(FunctionPointerFields)
Type * return_type
Definition codedesc.h:144
Definition codedesc.h:127
bool is_signed
Definition codedesc.h:128
FIELDOBJ_METHODS(IntegerFields)
Definition codedesc.h:122
FIELDOBJ_METHODS(OpaqueFields)
Definition codedesc.h:137
FIELDOBJ_METHODS(PointerFields)
bool is_const
Definition codedesc.h:139
Type * base_type
Definition codedesc.h:138