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 
46 ORC_RT_C_EXTERN_C_BEGIN
47 
48 typedef 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  */
70 typedef struct {
71   orc_rt_CWrapperFunctionResultDataUnion Data;
72   size_t Size;
73 } orc_rt_CWrapperFunctionResult;
74 
75 typedef struct orc_rt_CSharedOpaqueJITProcessControl
76     *orc_rt_SharedJITProcessControlRef;
77 
78 /**
79  * Zero-initialize an orc_rt_CWrapperFunctionResult.
80  */
81 static inline void
orc_rt_CWrapperFunctionResultInit(orc_rt_CWrapperFunctionResult * R)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  */
91 static inline orc_rt_CWrapperFunctionResult
orc_rt_CWrapperFunctionResultAllocate(size_t Size)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  */
105 static inline orc_rt_CWrapperFunctionResult
orc_rt_CreateCWrapperFunctionResultFromRange(const char * Data,size_t Size)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  */
125 static inline orc_rt_CWrapperFunctionResult
orc_rt_CreateCWrapperFunctionResultFromString(const char * Source)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  */
138 static inline orc_rt_CWrapperFunctionResult
orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(const char * ErrMsg)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  */
152 static inline void
orc_rt_DisposeCWrapperFunctionResult(orc_rt_CWrapperFunctionResult * R)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  */
163 static inline char *
orc_rt_CWrapperFunctionResultData(orc_rt_CWrapperFunctionResult * R)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  */
175 static inline size_t
orc_rt_CWrapperFunctionResultSize(const orc_rt_CWrapperFunctionResult * R)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  */
186 static inline size_t
orc_rt_CWrapperFunctionResultEmpty(const orc_rt_CWrapperFunctionResult * R)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  */
orc_rt_CWrapperFunctionResultGetOutOfBandError(const orc_rt_CWrapperFunctionResult * R)198 static inline const char *orc_rt_CWrapperFunctionResultGetOutOfBandError(
199     const orc_rt_CWrapperFunctionResult *R) {
200   return R->Size == 0 ? R->Data.ValuePtr : 0;
201 }
202 
203 ORC_RT_C_EXTERN_C_END
204 
205 #endif /* ORC_RT_C_API_H */
206