aboutsummaryrefslogtreecommitdiff
path: root/include/ccdjit.h
blob: 799912515a675708c3e0a507f498eb57a20dc3ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
#ifndef CCDJIT_PUBLIC_H
#define CCDJIT_PUBLIC_H

/*
 * CCDJIT public embedding API
 *
 * This header is the stable boundary for hosts that want to compile and run C
 * code at runtime.  The implementation lives in ccdjit.c, but the intended use
 * should be clear from this file alone.
 *
 * Basic use:
 *
 *      ccdjit_context *ctx = ccdjit_context_new(NULL);
 *      ccdjit_module *module = NULL;
 *
 *      if (ccdjit_compile_string(ctx, source, "plugin.c", &module) == 0) {
 *              int result = 0;
 *              ccdjit_module_call_main(module, 0, NULL, &result);
 *              ccdjit_module_free(module);
 *      }
 *      ccdjit_context_free(ctx);
 *
 * Return convention:
 *      Functions returning int use 0 for success and -1 for failure unless
 *      documented otherwise.  On failure, call ccdjit_context_last_error().
 *
 * Lifetime:
 *      A context owns options, include paths, registered symbols, and the last
 *      diagnostic.  A module owns generated code or a loaded CCDJIT binary.
 *      Modules keep their context state alive, so ccdjit_context_free() may be
 *      called before ccdjit_module_free(); the context is released when the
 *      last module using it is freed.
 *      Function pointers returned by ccdjit_module_symbol() are invalid after
 *      ccdjit_module_free().
 *
 * Runtime policy:
 *      Module calls, symbol lookup, and emission intentionally consult the
 *      current context options, sandbox settings, resource limits, registered
 *      symbols, resolver callback, and loaded libraries.  Machine code that
 *      has already been compiled may contain resolved external addresses; use
 *      a new module or function-handle replacement when changing symbol
 *      bindings must affect already compiled call sites.
 *
 * Threads:
 *      Public API entry points are internally serialized, and module calls,
 *      symbol lookup, emission, and lazy compilation take a module lock.  Raw
 *      function pointers returned by ccdjit_module_symbol() are still host
 *      pointers: do not free or replace their module while those pointers may
 *      run, and prefer typed handle/call helpers for dynamic bindings.
 *
 * Safety:
 *      Normal calls run in the host process.  Set sandbox_execution to
 *      CCDJIT_SANDBOX_PROCESS to run ccdjit_module_call_main() in a child
 *      process with optional resource, syscall, and filesystem limits.  Child
 *      crashes are reported through ccdjit_diagnostic.
 */

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#define CCDJIT_VERSION_MAJOR	 1
#define CCDJIT_VERSION_MINOR	 0
#define CCDJIT_VERSION_PATCH	 0
#define CCDJIT_VERSION_STRING	 "1.0.0"
#define CCDJIT_API_ABI_VERSION	 1
#define CCDJITB2_FORMAT_VERSION	 2
#define CCDJITB2_FLAG_DEBUG_INFO 1u

typedef struct ccdjit_context ccdjit_context;
typedef struct ccdjit_module ccdjit_module;
typedef struct ccdjit_function_handle ccdjit_function_handle;
typedef struct ccdjit_execution_result ccdjit_execution_result;

typedef struct {
	/* Host compiler or linker driver.  NULL uses $CC, then cc. */
	const char *driver;

	/* Extra linker arguments such as -L, -l, or -Wl options. */
	const char *const *link_args;
	size_t link_arg_count;

	/* Print the host linker command to stderr when nonzero. */
	int verbose;

	/* Wall-clock driver timeout.  Zero uses the default. */
	unsigned int timeout_ms;

	/* Captured driver stdout/stderr cap.  Zero uses the default. */
	size_t output_limit_bytes;
} ccdjit_link_options;

/*
 * Host symbol callback.  Return NULL when the name is unknown.
 *
 * The returned pointer is used as an external function or object address by
 * generated code.  Keep any pointed-to object alive while modules using it may
 * run.
 */
typedef void *(*ccdjit_symbol_resolver)(const char *name, void *userdata);

typedef enum {
	/* Run generated code directly in the host process. */
	CCDJIT_SANDBOX_OFF = 0,

	/* Run ccdjit_module_call_main() in a forked child process. */
	CCDJIT_SANDBOX_PROCESS = 1,
} ccdjit_sandbox_mode;

typedef enum {
	/*
	 * Minimal child profile: enough to write the result pipe, write
	 * captured output, and exit.  Unexpected syscalls are trapped.
	 */
	CCDJIT_SANDBOX_SYSCALL_STRICT = 0,

	/* STRICT plus read/close for simple stdio-style code. */
	CCDJIT_SANDBOX_SYSCALL_STDIO = 1,

	/* STDIO plus mmap/munmap/mprotect/brk/clock_gettime. */
	CCDJIT_SANDBOX_SYSCALL_RUNTIME = 2,

	/* Disable the seccomp filter.  Resource limits still apply. */
	CCDJIT_SANDBOX_SYSCALL_PERMISSIVE = 3,
} ccdjit_sandbox_syscall_policy;

typedef enum {
	/* Runtime file syscalls are denied by the syscall policy. */
	CCDJIT_SANDBOX_FS_NONE = 0,

	/* Permit read-only access under explicitly added roots. */
	CCDJIT_SANDBOX_FS_READ_ONLY_ROOTS = 1,

	/* Permit writes only for roots added with writable != 0. */
	CCDJIT_SANDBOX_FS_WRITABLE_ROOTS = 2,
} ccdjit_sandbox_filesystem_policy;

typedef struct {
	/* Allow #include to read files from include paths. */
	int allow_filesystem_includes;

	/* Allow the preprocessor to discover and read host system includes. */
	int allow_system_includes;

	/* Allow executable mappings for JIT code and loaded CCDJIT binaries. */
	int allow_executable_memory;

	/* ccdjit_sandbox_mode.  Default is CCDJIT_SANDBOX_OFF. */
	int sandbox_execution;

	/* ccdjit_sandbox_syscall_policy.  Default is STRICT. */
	int sandbox_syscalls;

	/* ccdjit_sandbox_filesystem_policy.  Default is FS_NONE. */
	int sandbox_filesystem;

	/*
	 * In sandbox mode, default dlsym lookup is disabled unless this is set.
	 * Prefer explicit ccdjit_context_register_symbol() capabilities.
	 */
	int sandbox_allow_implicit_symbols;

	/* Wall-clock timeout for one sandboxed main call.  Zero means no limit.
	 */
	unsigned int sandbox_timeout_ms;

	/* RLIMIT_CPU for sandboxed calls, rounded up to seconds by the OS. */
	unsigned int sandbox_cpu_time_ms;

	/* RLIMIT_AS for sandboxed calls.  Zero means keep the host default. */
	size_t sandbox_address_space_bytes;

	/* RLIMIT_STACK for sandboxed calls.  Zero means keep the host default.
	 */
	size_t sandbox_stack_bytes;

	/* RLIMIT_FSIZE for sandboxed calls.  Zero means keep the host default.
	 */
	size_t sandbox_file_size_bytes;

	/* Captured stdout/stderr cap for sandboxed calls.  Zero means 64 KiB.
	 */
	size_t sandbox_output_limit_bytes;

	/* Emit and retain optional debug/source mapping metadata. */
	int debug_info;

	/*
	 * Preprocessor output byte cap.  Zero uses the default currently 128
	 * MiB.
	 */
	size_t preprocessor_output_limit_bytes;

	/* Macro expansion recursion cap.  Zero uses the default. */
	unsigned int preprocessor_macro_depth_limit;

	/* Nested include cap.  Zero uses the default. */
	unsigned int preprocessor_include_depth_limit;

	/*
	 * Optional compiler driver used for host system include and builtin
	 * macro probes.  NULL auto-detects from $CC, then common cc drivers.
	 */
	const char *preprocessor_compiler;

	/* Wall-clock timeout for one compiler probe.  Zero uses the default. */
	unsigned int preprocessor_probe_timeout_ms;

	/* Captured compiler-probe output cap.  Zero uses the default. */
	size_t preprocessor_probe_output_limit_bytes;
} ccdjit_options;

typedef struct {
	/* Compiler phase such as LEXER, PARSER, JIT, API, or SANDBOX. */
	const char *phase;

	/* Source file, binary path, symbol name, or "<input>". */
	const char *filename;

	/* Human-readable error text owned by the context. */
	const char *message;

	/* Optional source excerpt for lexer/parser/type diagnostics. */
	const char *source_line;
	const char *caret_line;

	/* One-based line and column when available, otherwise zero. */
	int line;
	int column;

	/* ccdjit_diagnostic_code plus optional code-specific detail. */
	int code;
	int subcode;

	/* Raw child wait status or errno-style value for sandbox/API failures.
	 */
	int status;

	/* Signal that terminated the sandbox child, or zero. */
	int signal_number;

	/* Faulting address for sandboxed crash diagnostics, when available. */
	int has_fault_address;
	uintptr_t fault_address;
} ccdjit_diagnostic;

typedef enum {
	CCDJIT_DIAG_NONE = 0,
	CCDJIT_DIAG_LEXER = 1,
	CCDJIT_DIAG_PARSER = 2,
	CCDJIT_DIAG_PREPROCESSOR = 3,
	CCDJIT_DIAG_TYPE = 4,
	CCDJIT_DIAG_JIT = 5,
	CCDJIT_DIAG_UNRESOLVED_SYMBOL = 6,
	CCDJIT_DIAG_SANDBOX = 7,
	CCDJIT_DIAG_SANDBOX_TIMEOUT = 8,
	CCDJIT_DIAG_SANDBOX_FORBIDDEN_SYSCALL = 9,
	CCDJIT_DIAG_SANDBOX_CRASH = 10,
	CCDJIT_DIAG_INVALID_OPTIONS = 11,
	CCDJIT_DIAG_INVALID_ARGUMENT = 12,
	CCDJIT_DIAG_UNSUPPORTED_ABI = 13,
	CCDJIT_DIAG_MALFORMED_BINARY = 14,
	CCDJIT_DIAG_HOST_LINKER = 15,
	CCDJIT_DIAG_OUT_OF_MEMORY = 16,
} ccdjit_diagnostic_code;

typedef enum {
	CCDJIT_SYMBOL_UNKNOWN = 0,
	CCDJIT_SYMBOL_FUNCTION = 1,
	CCDJIT_SYMBOL_OBJECT = 2,
} ccdjit_symbol_kind;

typedef enum {
	CCDJIT_TYPE_INT = 0,
	CCDJIT_TYPE_CHAR = 1,
	CCDJIT_TYPE_BOOL = 2,
	CCDJIT_TYPE_VOID = 3,
	CCDJIT_TYPE_FLOAT = 4,
	CCDJIT_TYPE_DOUBLE = 5,
	CCDJIT_TYPE_LONG = 6,
	CCDJIT_TYPE_SHORT = 7,
	CCDJIT_TYPE_STRUCT = 8,
	CCDJIT_TYPE_ENUM = 9,
	CCDJIT_TYPE_UNION = 10,
	CCDJIT_TYPE_FLOAT128 = 11,
} ccdjit_type_base;

typedef struct {
	int has_type;
	int base;
	int pointer_level;
	int array_size;
	int is_unsigned;
	int is_complex;
	int is_atomic;
} ccdjit_type_info;

typedef struct {
	int kind;
	int has_signature;
	ccdjit_type_info type;
	ccdjit_type_info return_type;
	size_t parameter_count;
	int is_variadic;
	size_t size;
} ccdjit_symbol_info;

typedef struct {
	int process;
	int seccomp;
	int landlock;
} ccdjit_sandbox_capabilities;

typedef struct {
	const char *filename;
	const char *function;
	int line;
	int column;
	uintptr_t address;
	size_t size;
} ccdjit_debug_location;

/*
 * Create a compiler context.  Passing NULL uses permissive CLI-like defaults.
 * Invalid options return NULL; call ccdjit_context_last_error(NULL) for the
 * thread-local creation diagnostic.
 */
ccdjit_context *ccdjit_context_new(const ccdjit_options *options);

int ccdjit_version_major(void);
int ccdjit_version_minor(void);
int ccdjit_version_patch(void);
const char *ccdjit_version_string(void);
int ccdjit_api_abi_version(void);
int ccdjit_binary_format_version(void);
const char *ccdjit_git_commit(void);
int ccdjit_sandbox_capabilities_query(ccdjit_sandbox_capabilities *out);

/* Free the context and all context-owned diagnostics/options/lists. */
void ccdjit_context_free(ccdjit_context *ctx);

/* Add a preprocessor include search path, like -I. */
int ccdjit_context_add_include_path(ccdjit_context *ctx, const char *path);

/* Restrict filesystem includes to this root when include roots are used. */
int ccdjit_context_add_include_root(ccdjit_context *ctx, const char *path);

/* Add a preprocessor definition, like -DNAME or -DNAME=value. */
int ccdjit_context_add_define(ccdjit_context *ctx, const char *define);

/* Grant generated code an explicit external symbol capability. */
int ccdjit_context_register_symbol(ccdjit_context *ctx, const char *name,
    void *addr);

/* Add an explicit shared library path for external symbol lookup. */
int ccdjit_context_add_library(ccdjit_context *ctx, const char *path);

/* Install a fallback external symbol resolver. */
void ccdjit_context_set_symbol_resolver(ccdjit_context *ctx,
    ccdjit_symbol_resolver resolver, void *userdata);

/* Update sandbox mode, syscall policy, filesystem policy, and symbol policy. */
int ccdjit_context_set_sandbox_options(ccdjit_context *ctx, int mode,
    int syscall_policy, int filesystem_policy, int allow_implicit_symbols);

/* Update all sandbox resource limits in one call. */
int ccdjit_context_set_sandbox_limits(ccdjit_context *ctx,
    unsigned int timeout_ms, unsigned int cpu_time_ms,
    size_t address_space_bytes, size_t stack_bytes, size_t file_size_bytes,
    size_t output_limit_bytes);

/* Update preprocessor resource limits.  Passing zero keeps the default. */
int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx,
    size_t output_limit_bytes, unsigned int macro_depth,
    unsigned int include_depth);

/* Select the compiler driver used by system include and builtin macro probes.
 */
int ccdjit_context_set_preprocessor_compiler(ccdjit_context *ctx,
    const char *compiler);

/* Update compiler-probe timeout/output limits.  Passing zero keeps defaults. */
int ccdjit_context_set_preprocessor_probe_limits(ccdjit_context *ctx,
    unsigned int timeout_ms, size_t output_limit_bytes);

/* Free this thread's cached compiler probe results and system include paths. */
void ccdjit_preprocessor_free_probe_cache(void);

/* Enable or disable executable memory for future compile/load/call paths. */
int ccdjit_context_set_executable_memory(ccdjit_context *ctx, int allow);

/* Enable or disable optional debug/source mapping metadata. */
int ccdjit_context_set_debug_info(ccdjit_context *ctx, int enable);

/*
 * Add a Landlock filesystem root for sandboxed execution.
 *
 * writable is only honored when sandbox_filesystem is
 * CCDJIT_SANDBOX_FS_WRITABLE_ROOTS.  On systems without Landlock, requesting a
 * root-based filesystem policy fails while entering the sandbox.
 */
int ccdjit_context_add_sandbox_filesystem_root(ccdjit_context *ctx,
    const char *path, int writable);

/*
 * Return the last error for this context.  Passing NULL returns the
 * thread-local diagnostic for context creation or NULL-context API failures.
 * The pointer is context-owned or thread-local.
 */
const ccdjit_diagnostic *ccdjit_context_last_error(ccdjit_context *ctx);

/* Return captured sandbox stdout/stderr from the last sandboxed main call. */
const char *ccdjit_context_last_stdout(ccdjit_context *ctx);
const char *ccdjit_context_last_stderr(ccdjit_context *ctx);

/*
 * Owned execution result snapshot for bindings and concurrent hosts.
 *
 * Result objects keep copies of the call status, integer result, diagnostic,
 * captured stdout, and captured stderr.  They are not invalidated by later
 * calls on the same context.
 */
void ccdjit_execution_result_free(ccdjit_execution_result *result);
int ccdjit_execution_result_status(const ccdjit_execution_result *result);
int ccdjit_execution_result_has_value(const ccdjit_execution_result *result);
int ccdjit_execution_result_value(const ccdjit_execution_result *result);
const ccdjit_diagnostic *ccdjit_execution_result_diagnostic(
    const ccdjit_execution_result *result);
const char *ccdjit_execution_result_stdout(
    const ccdjit_execution_result *result);
const char *ccdjit_execution_result_stderr(
    const ccdjit_execution_result *result);
int ccdjit_execution_result_signal(const ccdjit_execution_result *result);
int ccdjit_execution_result_has_fault_address(
    const ccdjit_execution_result *result);
uintptr_t ccdjit_execution_result_fault_address(
    const ccdjit_execution_result *result);

/* Compile a source file into a live JIT module. */
int ccdjit_compile_file(ccdjit_context *ctx, const char *path,
    ccdjit_module **out);

/* Compile a source string into a live JIT module. */
int ccdjit_compile_string(ccdjit_context *ctx, const char *source,
    const char *filename, ccdjit_module **out);

/*
 * Compile a source file into a live JIT module without requiring main().
 * Use ccdjit_module_symbol() to find and call exported config/plugin symbols.
 */
int ccdjit_compile_file_module(ccdjit_context *ctx, const char *path,
    ccdjit_module **out);

/*
 * Compile a source string into a live JIT module without requiring main().
 * Use ccdjit_module_symbol() to find and call exported config/plugin symbols.
 */
int ccdjit_compile_string_module(ccdjit_context *ctx, const char *source,
    const char *filename, ccdjit_module **out);

/* Convenience wrapper: compile a source string, call main, free the module. */
int ccdjit_eval_string(ccdjit_context *ctx, const char *source,
    const char *filename, int argc, char **argv, int *result_out);

/*
 * Find a function or object symbol in a module.
 *
 * Calling the returned function pointer runs in the host process even when the
 * context has sandbox_execution enabled.  Use ccdjit_module_call_main() for
 * sandboxed execution.
 */
void *ccdjit_module_symbol(ccdjit_module *module, const char *name);

/*
 * Inspect a module symbol without forcing the caller to cast blindly.
 *
 * JIT functions expose return type, parameter count, variadic flag, and
 * per-parameter metadata through ccdjit_module_function_parameter_type().
 * Object symbols expose their object type and size.  Loaded CCDJITB2 binaries
 * expose function/object kind and size but not full C signatures.
 */
int ccdjit_module_symbol_info(ccdjit_module *module, const char *name,
    ccdjit_symbol_info *out);

int ccdjit_module_function_parameter_type(ccdjit_module *module,
    const char *name, size_t index, ccdjit_type_info *out);

/*
 * Return a callable function pointer only when the JIT signature exactly
 * matches the expected return and parameter types.
 */
void *ccdjit_module_function_symbol_checked(ccdjit_module *module,
    const char *name, const ccdjit_type_info *return_type,
    const ccdjit_type_info *parameter_types, size_t parameter_count,
    int allow_variadic);

/* Map a live JIT instruction address to lightweight module-owned debug info. */
int ccdjit_module_debug_location(ccdjit_module *module, const void *address,
    ccdjit_debug_location *out);

/* Call module main(argc, argv).  Honors CCDJIT_SANDBOX_PROCESS. */
int ccdjit_module_call_main(ccdjit_module *module, int argc, char **argv,
    int *result_out);
int ccdjit_module_call_main_result(ccdjit_module *module, int argc, char **argv,
    ccdjit_execution_result **out);

/*
 * Call an exported JIT function with signature int name(int).
 *
 * Honors CCDJIT_SANDBOX_PROCESS like ccdjit_module_call_main().  Other
 * signatures and binary modules are rejected with a diagnostic.
 */
int ccdjit_module_call_i32(ccdjit_module *module, const char *symbol, int arg,
    int *result_out);
int ccdjit_module_call_i32_result(ccdjit_module *module, const char *symbol,
    int arg, ccdjit_execution_result **out);

/*
 * Compile and publish a named function behind a stable handle.
 *
 * The initial source and every replacement must define the same function
 * signature.  Calls through the handle do not expose raw function pointers, so
 * replacements can wait for active callers and then free old generated code.
 */
int ccdjit_function_handle_new(ccdjit_context *ctx, const char *source,
    const char *filename, const char *symbol, ccdjit_function_handle **out);

/*
 * Compile replacement source and atomically publish it on success.
 *
 * On compile failure or signature mismatch the old implementation remains
 * active and the context diagnostic describes the failure.
 */
int ccdjit_function_handle_replace(ccdjit_function_handle *handle,
    const char *source, const char *filename);

/* Call a handle whose published function has signature int name(int). */
int ccdjit_function_handle_call_i32(ccdjit_function_handle *handle, int arg,
    int *result_out);

/* Free a function handle and the currently published implementation. */
void ccdjit_function_handle_free(ccdjit_function_handle *handle);

/* Emit textual assembly-like bytes for inspection. */
int ccdjit_module_emit_assembly(ccdjit_module *module, FILE *out);

/* Emit a CCDJITB2 binary image. */
int ccdjit_module_emit_binary(ccdjit_module *module, FILE *out);

/* Emit an ELF64 relocatable object. */
int ccdjit_module_emit_object(ccdjit_module *module, FILE *out);

/*
 * Emit a linked host executable.
 *
 * This depends on the host compiler driver.  It is intended for trusted build
 * paths, not sandboxed execution.
 */
int ccdjit_module_emit_executable_file(ccdjit_module *module, const char *path,
    const ccdjit_link_options *options);

/* Emit a CCDJITB2 binary image directly to a path. */
int ccdjit_module_emit_binary_file(ccdjit_module *module, const char *path);

/* Load a CCDJITB2 binary image into executable memory. */
int ccdjit_module_load_binary(ccdjit_context *ctx, const char *path,
    ccdjit_module **out);

/* Free generated code, loaded binary storage, AST, and module-owned source. */
void ccdjit_module_free(ccdjit_module *module);

#ifdef __cplusplus
}
#endif

#endif