1/*===- c_api.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_API_H
15#define ORC_RT_C_API_H
16
17#include <assert.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22/* Helper to suppress strict prototype warnings. */
23#ifdef __clang__
24#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN                                       \
25  _Pragma("clang diagnostic push")                                             \
26      _Pragma("clang diagnostic error \"-Wstrict-prototypes\"")
27#define ORC_RT_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop")
28#else
29#define ORC_RT_C_STRICT_PROTOTYPES_BEGIN
30#define ORC_RT_C_STRICT_PROTOTYPES_END
31#endif
32
33/* Helper to wrap C code for C++ */
34#ifdef __cplusplus
35#define ORC_RT_C_EXTERN_C_BEGIN                                                \
36  extern "C" {                                                                 \
37  ORC_RT_C_STRICT_PROTOTYPES_BEGIN
38#define ORC_RT_C_EXTERN_C_END                                                  \
39  ORC_RT_C_STRICT_PROTOTYPES_END                                               \
40  }
41#else
42#define ORC_RT_C_EXTERN_C_BEGIN ORC_RT_C_STRICT_PROTOTYPES_BEGIN
43#define ORC_RT_C_EXTERN_C_END ORC_RT_C_STRICT_PROTOTYPES_END
44#endif
45
46ORC_RT_C_EXTERN_C_BEGIN
47
48typedef union {
49  char *ValuePtr;
50  char Value[sizeof(char *)];
51} __orc_rt_CWrapperFunctionResultDataUnion;
52
53/**
54 * __orc_rt_CWrapperFunctionResult is a kind of C-SmallVector with an
55 * out-of-band error state.
56 *
57 * If Size == 0 and Data.ValuePtr is non-zero then the value is in the
58 * 'out-of-band error' state, and Data.ValuePtr points at a malloc-allocated,
59 * null-terminated string error message.
60 *
61 * If Size <= sizeof(__orc_rt_CWrapperFunctionResultData) then the value is in
62 * the 'small' state and the content is held in the first Size bytes of
63 * Data.Value.
64 *
65 * If Size > sizeof(OrtRTCWrapperFunctionResultData) then the value is in the
66 * 'large' state and the content is held in the first Size bytes of the
67 * memory pointed to by Data.ValuePtr. This memory must have been allocated by
68 * malloc, and will be freed with free when this value is destroyed.
69 */
70typedef struct {
71  __orc_rt_CWrapperFunctionResultDataUnion Data;
72  size_t Size;
73} __orc_rt_CWrapperFunctionResult;
74
75typedef struct __orc_rt_CSharedOpaqueJITProcessControl
76    *__orc_rt_SharedJITProcessControlRef;
77
78/**
79 * Zero-initialize an __orc_rt_CWrapperFunctionResult.
80 */
81static inline void
82__orc_rt_CWrapperFunctionResultInit(__orc_rt_CWrapperFunctionResult *R) {
83  R->Size = 0;
84  R->Data.ValuePtr = 0;
85}
86
87/**
88 * Create an __orc_rt_CWrapperFunctionResult with an uninitialized buffer of
89 * size Size. The buffer is returned via the DataPtr argument.
90 */
91static inline __orc_rt_CWrapperFunctionResult
92__orc_rt_CWrapperFunctionResultAllocate(size_t Size) {
93  __orc_rt_CWrapperFunctionResult R;
94  R.Size = Size;
95  // If Size is 0 ValuePtr must be 0 or it is considered an out-of-band error.
96  R.Data.ValuePtr = 0;
97  if (Size > sizeof(R.Data.Value))
98    R.Data.ValuePtr = (char *)malloc(Size);
99  return R;
100}
101
102/**
103 * Create an __orc_rt_WrapperFunctionResult from the given data range.
104 */
105static inline __orc_rt_CWrapperFunctionResult
106__orc_rt_CreateCWrapperFunctionResultFromRange(const char *Data, size_t Size) {
107  __orc_rt_CWrapperFunctionResult R;
108  R.Size = Size;
109  if (R.Size > sizeof(R.Data.Value)) {
110    char *Tmp = (char *)malloc(Size);
111    memcpy(Tmp, Data, Size);
112    R.Data.ValuePtr = Tmp;
113  } else
114    memcpy(R.Data.Value, Data, Size);
115  return R;
116}
117
118/**
119 * Create an __orc_rt_CWrapperFunctionResult by copying the given string,
120 * including the null-terminator.
121 *
122 * This function copies the input string. The client is responsible for freeing
123 * the ErrMsg arg.
124 */
125static inline __orc_rt_CWrapperFunctionResult
126__orc_rt_CreateCWrapperFunctionResultFromString(const char *Source) {
127  return __orc_rt_CreateCWrapperFunctionResultFromRange(Source,
128                                                        strlen(Source) + 1);
129}
130
131/**
132 * Create an __orc_rt_CWrapperFunctionResult representing an out-of-band
133 * error.
134 *
135 * This function copies the input string. The client is responsible for freeing
136 * the ErrMsg arg.
137 */
138static inline __orc_rt_CWrapperFunctionResult
139__orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(const char *ErrMsg) {
140  __orc_rt_CWrapperFunctionResult R;
141  R.Size = 0;
142  char *Tmp = (char *)malloc(strlen(ErrMsg) + 1);
143  strcpy(Tmp, ErrMsg);
144  R.Data.ValuePtr = Tmp;
145  return R;
146}
147
148/**
149 * This should be called to destroy __orc_rt_CWrapperFunctionResult values
150 * regardless of their state.
151 */
152static inline void
153__orc_rt_DisposeCWrapperFunctionResult(__orc_rt_CWrapperFunctionResult *R) {
154  if (R->Size > sizeof(R->Data.Value) ||
155      (R->Size == 0 && R->Data.ValuePtr))
156    free(R->Data.ValuePtr);
157}
158
159/**
160 * Get a pointer to the data contained in the given
161 * __orc_rt_CWrapperFunctionResult.
162 */
163static inline char *
164__orc_rt_CWrapperFunctionResultData(__orc_rt_CWrapperFunctionResult *R) {
165  assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
166         "Cannot get data for out-of-band error value");
167  return R->Size > sizeof(R->Data.Value) ? R->Data.ValuePtr : R->Data.Value;
168}
169
170/**
171 * Safely get the size of the given __orc_rt_CWrapperFunctionResult.
172 *
173 * Asserts that we're not trying to access the size of an error value.
174 */
175static inline size_t
176__orc_rt_CWrapperFunctionResultSize(const __orc_rt_CWrapperFunctionResult *R) {
177  assert((R->Size != 0 || R->Data.ValuePtr == NULL) &&
178         "Cannot get size for out-of-band error value");
179  return R->Size;
180}
181
182/**
183 * Returns 1 if this value is equivalent to a value just initialized by
184 * __orc_rt_CWrapperFunctionResultInit, 0 otherwise.
185 */
186static inline size_t
187__orc_rt_CWrapperFunctionResultEmpty(const __orc_rt_CWrapperFunctionResult *R) {
188  return R->Size == 0 && R->Data.ValuePtr == 0;
189}
190
191/**
192 * Returns a pointer to the out-of-band error string for this
193 * __orc_rt_CWrapperFunctionResult, or null if there is no error.
194 *
195 * The __orc_rt_CWrapperFunctionResult retains ownership of the error
196 * string, so it should be copied if the caller wishes to preserve it.
197 */
198static inline const char *__orc_rt_CWrapperFunctionResultGetOutOfBandError(
199    const __orc_rt_CWrapperFunctionResult *R) {
200  return R->Size == 0 ? R->Data.ValuePtr : 0;
201}
202
203ORC_RT_C_EXTERN_C_END
204
205#endif /* ORC_RT_C_API_H */
206