Skip to content

Commit 3292edb

Browse files
authored
[orc-rt] Add C and C++ APIs for WrapperFunctionResult. (#154927)
orc_rt_WrapperFunctionResult is a byte-buffer with inline storage and a builtin error state. It is intended as a general purpose return type for functions that return a serialized result (e.g. for communication across ABIs or via IPC/RPC). orc_rt_WrapperFunctionResult contains a small amount of inline storage, allowing it to avoid heap-allocation for small return types (e.g. bools, chars, pointers).
1 parent d2b810e commit 3292edb

File tree

6 files changed

+389
-0
lines changed

6 files changed

+389
-0
lines changed

orc-rt/include/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
set(ORC_RT_HEADERS
2+
orc-rt-c/ExternC.h
3+
orc-rt-c/WrapperFunctionResult.h
24
orc-rt-c/orc-rt.h
35
orc-rt/BitmaskEnum.h
46
orc-rt/Compiler.h
57
orc-rt/Error.h
68
orc-rt/Math.h
79
orc-rt/RTTI.h
10+
orc-rt/WrapperFunctionResult.h
811
orc-rt/move_only_function.h
912
orc-rt/span.h
1013
)

orc-rt/include/orc-rt-c/ExternC.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*===- ExternC.h - C API for the ORC runtime ----------------------*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
|*===----------------------------------------------------------------------===*|
9+
|* *|
10+
|* This file defines the C API for the ORC runtime *|
11+
|* *|
12+
\*===----------------------------------------------------------------------===*/
13+
14+
#ifndef ORC_RT_C_EXTERNC_H
15+
#define ORC_RT_C_EXTERNC_H
16+
17+
/* Helper to suppress strict prototype warnings. */
18+
#ifdef __clang__
19+
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN \
20+
_Pragma("clang diagnostic push") \
21+
_Pragma("clang diagnostic error \"-Wstrict-prototypes\"")
22+
#define ORC_RT_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop")
23+
#else
24+
#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN
25+
#define ORC_RT_C_STRICT_PROTOTYPES_END
26+
#endif
27+
28+
/* Helper to wrap C code for C++ */
29+
#ifdef __cplusplus
30+
#define ORC_RT_C_EXTERN_C_BEGIN \
31+
extern "C" { \
32+
ORC_RT_C_STRICT_PROTOTYPES_BEGIN
33+
#define ORC_RT_C_EXTERN_C_END \
34+
ORC_RT_C_STRICT_PROTOTYPES_END \
35+
}
36+
#else
37+
#define ORC_RT_C_EXTERN_C_BEGIN ORC_RT_C_STRICT_PROTOTYPES_BEGIN
38+
#define ORC_RT_C_EXTERN_C_END ORC_RT_C_STRICT_PROTOTYPES_END
39+
#endif
40+
41+
#endif /* ORC_RT_C_EXTERNC_H */
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*===----- WrapperFunctionResult.h - blob-of-bytes container -----*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
|*===----------------------------------------------------------------------===*|
9+
|* *|
10+
|* Defines orc_rt_WrapperFunctionResult and related APIs. *|
11+
|* *|
12+
\*===----------------------------------------------------------------------===*/
13+
14+
#ifndef ORC_RT_C_WRAPPERFUNCTIONRESULT_H
15+
#define ORC_RT_C_WRAPPERFUNCTIONRESULT_H
16+
17+
#include "orc-rt-c/ExternC.h"
18+
19+
#include <assert.h>
20+
#include <stdlib.h>
21+
#include <string.h>
22+
23+
ORC_RT_C_EXTERN_C_BEGIN
24+
25+
typedef union {
26+
char *ValuePtr;
27+
char Value[sizeof(char *)];
28+
} orc_rt_WrapperFunctionResultDataUnion;
29+
30+
/**
31+
* orc_rt_WrapperFunctionResult is a kind of C-SmallVector with an
32+
* out-of-band error state.
33+
*
34+
* If Size == 0 and Data.ValuePtr is non-zero then the value is in the
35+
* 'out-of-band error' state, and Data.ValuePtr points at a malloc-allocated,
36+
* null-terminated string error message.
37+
*
38+
* If Size <= sizeof(orc_rt_WrapperFunctionResultData) then the value is in
39+
* the 'small' state and the content is held in the first Size bytes of
40+
* Data.Value.
41+
*
42+
* If Size > sizeof(orc_rt_WrapperFunctionResultData) then the value is in the
43+
* 'large' state and the content is held in the first Size bytes of the
44+
* memory pointed to by Data.ValuePtr. This memory must have been allocated by
45+
* malloc, and will be freed with free when this value is destroyed.
46+
*/
47+
typedef struct {
48+
orc_rt_WrapperFunctionResultDataUnion Data;
49+
size_t Size;
50+
} orc_rt_WrapperFunctionResult;
51+
52+
/**
53+
* Zero-initialize an orc_rt_WrapperFunctionResult.
54+
*/
55+
static inline void
56+
orc_rt_WrapperFunctionResultInit(orc_rt_WrapperFunctionResult *R) {
57+
R->Size = 0;
58+
R->Data.ValuePtr = 0;
59+
}
60+
61+
/**
62+
* Create an orc_rt_WrapperFunctionResult with an uninitialized buffer of
63+
* size Size. The buffer is returned via the DataPtr argument.
64+
*/
65+
static inline orc_rt_WrapperFunctionResult
66+
orc_rt_WrapperFunctionResultAllocate(size_t Size) {
67+
orc_rt_WrapperFunctionResult R;
68+
R.Size = Size;
69+
// If Size is 0 ValuePtr must be 0 or it is considered an out-of-band error.
70+
R.Data.ValuePtr = 0;
71+
if (Size > sizeof(R.Data.Value))
72+
R.Data.ValuePtr = (char *)malloc(Size);
73+
return R;
74+
}
75+
76+
/**
77+
* Create an orc_rt_WrapperFunctionResult from the given data range.
78+
*/
79+
static inline orc_rt_WrapperFunctionResult
80+
orc_rt_CreateWrapperFunctionResultFromRange(const char *Data, size_t Size) {
81+
orc_rt_WrapperFunctionResult R;
82+
R.Size = Size;
83+
if (R.Size > sizeof(R.Data.Value)) {
84+
char *Tmp = (char *)malloc(Size);
85+
memcpy(Tmp, Data, Size);
86+
R.Data.ValuePtr = Tmp;
87+
} else
88+
memcpy(R.Data.Value, Data, Size);
89+
return R;
90+
}
91+
92+
/**
93+
* Create an orc_rt_WrapperFunctionResult by copying the given string,
94+
* including the null-terminator.
95+
*
96+
* This function copies the input string. The client is responsible for freeing
97+
* the ErrMsg arg.
98+
*/
99+
static inline orc_rt_WrapperFunctionResult
100+
orc_rt_CreateWrapperFunctionResultFromString(const char *Source) {
101+
return orc_rt_CreateWrapperFunctionResultFromRange(Source,
102+
strlen(Source) + 1);
103+
}
104+
105+
/**
106+
* Create an orc_rt_WrapperFunctionResult representing an out-of-band
107+
* error.
108+
*
109+
* This function copies the input string. The client is responsible for freeing
110+
* the ErrMsg arg.
111+
*/
112+
static inline orc_rt_WrapperFunctionResult
113+
orc_rt_CreateWrapperFunctionResultFromOutOfBandError(const char *ErrMsg) {
114+
orc_rt_WrapperFunctionResult R;
115+
R.Size = 0;
116+
char *Tmp = (char *)malloc(strlen(ErrMsg) + 1);
117+
strcpy(Tmp, ErrMsg);
118+
R.Data.ValuePtr = Tmp;
119+
return R;
120+
}
121+
122+
/**
123+
* This should be called to destroy orc_rt_WrapperFunctionResult values
124+
* regardless of their state.
125+
*/
126+
static inline void
127+
orc_rt_DisposeWrapperFunctionResult(orc_rt_WrapperFunctionResult *R) {
128+
if (R->Size > sizeof(R->Data.Value) || (R->Size == 0 && R->Data.ValuePtr))
129+
free(R->Data.ValuePtr);
130+
}
131+
132+
/**
133+
* Get a pointer to the data contained in the given
134+
* orc_rt_WrapperFunctionResult.
135+
*/
136+
static inline char *
137+
orc_rt_WrapperFunctionResultData(orc_rt_WrapperFunctionResult *R) {
138+
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
139+
"Cannot get data for out-of-band error value");
140+
return R->Size > sizeof(R->Data.Value) ? R->Data.ValuePtr : R->Data.Value;
141+
}
142+
143+
/**
144+
* Safely get the size of the given orc_rt_WrapperFunctionResult.
145+
*
146+
* Asserts that we're not trying to access the size of an error value.
147+
*/
148+
static inline size_t
149+
orc_rt_WrapperFunctionResultSize(const orc_rt_WrapperFunctionResult *R) {
150+
assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
151+
"Cannot get size for out-of-band error value");
152+
return R->Size;
153+
}
154+
155+
/**
156+
* Returns 1 if this value is equivalent to a value just initialized by
157+
* orc_rt_WrapperFunctionResultInit, 0 otherwise.
158+
*/
159+
static inline size_t
160+
orc_rt_WrapperFunctionResultEmpty(const orc_rt_WrapperFunctionResult *R) {
161+
return R->Size == 0 && R->Data.ValuePtr == 0;
162+
}
163+
164+
/**
165+
* Returns a pointer to the out-of-band error string for this
166+
* orc_rt_WrapperFunctionResult, or null if there is no error.
167+
*
168+
* The orc_rt_WrapperFunctionResult retains ownership of the error
169+
* string, so it should be copied if the caller wishes to preserve it.
170+
*/
171+
static inline const char *orc_rt_WrapperFunctionResultGetOutOfBandError(
172+
const orc_rt_WrapperFunctionResult *R) {
173+
return R->Size == 0 ? R->Data.ValuePtr : 0;
174+
}
175+
176+
ORC_RT_C_EXTERN_C_END
177+
178+
#endif /* ORC_RT_WRAPPERFUNCTIONRESULT_H */
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===---- WrapperFunctionResult.h -- blob-of-bytes container ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Defines WrapperFunctionResult and related APIs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef ORC_RT_WRAPPERFUNCTIONRESULT_H
14+
#define ORC_RT_WRAPPERFUNCTIONRESULT_H
15+
16+
#include "orc-rt-c/WrapperFunctionResult.h"
17+
18+
#include <utility>
19+
20+
namespace orc_rt {
21+
22+
/// A C++ convenience wrapper for orc_rt_WrapperFunctionResult. Auto-disposes
23+
/// the contained result on destruction.
24+
class WrapperFunctionResult {
25+
public:
26+
/// Create a default WrapperFunctionResult.
27+
WrapperFunctionResult() { orc_rt_WrapperFunctionResultInit(&R); }
28+
29+
/// Create a WrapperFunctionResult from a WrapperFunctionResult. This
30+
/// instance takes ownership of the result object and will automatically
31+
/// call dispose on the result upon destruction.
32+
WrapperFunctionResult(orc_rt_WrapperFunctionResult R) : R(R) {}
33+
34+
WrapperFunctionResult(const WrapperFunctionResult &) = delete;
35+
WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
36+
37+
WrapperFunctionResult(WrapperFunctionResult &&Other) {
38+
orc_rt_WrapperFunctionResultInit(&R);
39+
std::swap(R, Other.R);
40+
}
41+
42+
WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
43+
orc_rt_WrapperFunctionResult Tmp;
44+
orc_rt_WrapperFunctionResultInit(&Tmp);
45+
std::swap(Tmp, Other.R);
46+
std::swap(R, Tmp);
47+
return *this;
48+
}
49+
50+
~WrapperFunctionResult() { orc_rt_DisposeWrapperFunctionResult(&R); }
51+
52+
/// Relinquish ownership of and return the
53+
/// orc_rt_WrapperFunctionResult.
54+
orc_rt_WrapperFunctionResult release() {
55+
orc_rt_WrapperFunctionResult Tmp;
56+
orc_rt_WrapperFunctionResultInit(&Tmp);
57+
std::swap(R, Tmp);
58+
return Tmp;
59+
}
60+
61+
/// Get a pointer to the data contained in this instance.
62+
char *data() { return orc_rt_WrapperFunctionResultData(&R); }
63+
64+
/// Returns the size of the data contained in this instance.
65+
size_t size() const { return orc_rt_WrapperFunctionResultSize(&R); }
66+
67+
/// Returns true if this value is equivalent to a default-constructed
68+
/// WrapperFunctionResult.
69+
bool empty() const { return orc_rt_WrapperFunctionResultEmpty(&R); }
70+
71+
/// Create a WrapperFunctionResult with the given size and return a pointer
72+
/// to the underlying memory.
73+
static WrapperFunctionResult allocate(size_t Size) {
74+
WrapperFunctionResult R;
75+
R.R = orc_rt_WrapperFunctionResultAllocate(Size);
76+
return R;
77+
}
78+
79+
/// Copy from the given char range.
80+
static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
81+
return orc_rt_CreateWrapperFunctionResultFromRange(Source, Size);
82+
}
83+
84+
/// Copy from the given null-terminated string (includes the null-terminator).
85+
static WrapperFunctionResult copyFrom(const char *Source) {
86+
return orc_rt_CreateWrapperFunctionResultFromString(Source);
87+
}
88+
89+
/// Create an out-of-band error by copying the given string.
90+
static WrapperFunctionResult createOutOfBandError(const char *Msg) {
91+
return orc_rt_CreateWrapperFunctionResultFromOutOfBandError(Msg);
92+
}
93+
94+
/// If this value is an out-of-band error then this returns the error message,
95+
/// otherwise returns nullptr.
96+
const char *getOutOfBandError() const {
97+
return orc_rt_WrapperFunctionResultGetOutOfBandError(&R);
98+
}
99+
100+
private:
101+
orc_rt_WrapperFunctionResult R;
102+
};
103+
104+
} // namespace orc_rt
105+
106+
#endif // ORC_RT_WRAPPERFUNCTIONRESULT_H

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_orc_rt_unittest(CoreTests
1616
ErrorTest.cpp
1717
MathTest.cpp
1818
RTTITest.cpp
19+
WrapperFunctionResultTest.cpp
1920
move_only_function-test.cpp
2021
span-test.cpp
2122
DISABLE_LLVM_LINK_LLVM_DYLIB

0 commit comments

Comments
 (0)