NAME
XS::JIT - Lightweight JIT compiler for XS code
VERSION
Version 0.03
SYNOPSIS
use XS::JIT;
# Compile C code and install functions
XS::JIT->compile(
code => $c_code,
name => 'MyModule::JIT::Foo',
functions => {
# Simple form - XS::JIT generates a wrapper
'Foo::get' => 'jit_get',
# Hashref form - for XS-native functions (no wrapper)
'Foo::new' => { source => 'jit_new', is_xs_native => 1 },
'Foo::name' => { source => 'jit_name', is_xs_native => 1 },
},
cache_dir => '_CACHED_XS', # optional, defaults to _CACHED_XS
force => 0, # optional, force recompile
);
DESCRIPTION
XS::JIT is a lightweight alternative to Inline::C for runtime JIT compilation of XS code. It's specifically optimized for use cases where you're generating C code dynamically and need to compile and load it at runtime.
Unlike Inline::C, XS::JIT:
Skips C code parsing (no Parse::RecDescent dependency)
Skips xsubpp (generates C code directly)
Uses direct compiler invocation (no make/Makefile.PL)
Provides a C API for use from other XS modules
METHODS
compile
my $ok = XS::JIT->compile(%options);
Compiles C code and installs the specified functions into Perl namespaces.
Options:
- code (required)
-
The C source code to compile. This should be valid C code that uses the Perl C API (EXTERN.h, perl.h, XSUB.h are included automatically).
- name (required)
-
A unique module name for caching purposes (e.g., "MyApp::JIT::Class_0"). This is used to generate the boot function name and cache path.
- functions (required)
-
A hashref mapping target Perl function names to source C function names. Values can be either a simple string (the C function name) or a hashref with options:
# Simple string form functions => { 'Package::method' => 'c_function_name', } # Hashref form with options functions => { 'Package::method' => { source => 'c_function_name', is_xs_native => 1, # function handles XS stack itself }, }The
is_xs_nativeoption is important for performance. Set it to 1 when your C function is already written as a proper XS function usingXS_EUPXS(),dXSARGS,ST(), andXSRETURN(). This tells XS::JIT to create a simple alias instead of generating a wrapper function, avoiding any overhead. - cache_dir
-
Optional. Directory for caching compiled modules. Defaults to "_CACHED_XS".
- force
-
Optional. If true, forces recompilation even if a cached version exists.
Returns 1 on success, 0 on failure.
is_cached
my $cached = XS::JIT->is_cached($code, $name, $cache_dir);
Checks if a compiled module exists in the cache.
Arguments:
- $code
-
The C source code.
- $name
-
The module name.
- $cache_dir
-
Optional. Cache directory. Defaults to "_CACHED_XS".
Returns 1 if cached, 0 otherwise.
generate_code
my $c_code = XS::JIT->generate_code($user_code, $name, \%functions);
Generates the complete C source code with XS wrappers and boot function, without compiling it. Useful for debugging or custom build processes.
Arguments:
- $user_code
-
The user's C source code.
- $name
-
The module name (used for boot function naming).
- \%functions
-
A hashref mapping Perl function names to C function names.
Returns the complete generated C code as a string.
inc_dir
my $dir = XS::JIT->inc_dir();
Returns the directory containing the XS::JIT header file (xs_jit.h). This is useful for modules that want to use the XS::JIT C API.
Dies if the installation directory cannot be found.
cflags
my $cflags = XS::JIT->cflags();
Returns compiler flags needed to compile code that uses the XS::JIT C API. Currently returns -I/path/to/xs_jit.h.
libs
my $libs = XS::JIT->libs();
Returns linker flags needed for XS::JIT in the format -L/path -lxs_jit.
static_libs
my $lib_path = XS::JIT->static_libs();
Returns the full path to the static library libxs_jit.a, or undef if not found. Useful for build systems that prefer explicit static linking.
Use both cflags and libs in your Makefile.PL:
use XS::JIT;
WriteMakefile(
...
INC => XS::JIT->cflags(),
LIBS => [XS::JIT->libs()],
);
WRITING C FUNCTIONS
XS::JIT supports two styles of C functions: wrapper-style functions that return an SV*, and XS-native functions that handle the stack directly.
Wrapper-Style Functions (default)
These functions take SV* self as the first argument and return an SV*. XS::JIT generates a wrapper that handles the Perl stack:
SV* my_getter(SV* self) {
dTHX;
/* self is the invocant (class or object) */
return newSVpv("hello", 0);
}
XS-Native Functions (recommended for performance)
For best performance, write functions using the XS conventions directly and set is_xs_native => 1 in the function mapping. This avoids wrapper overhead entirely:
XS_EUPXS(my_getter) {
dVAR; dXSARGS;
PERL_UNUSED_VAR(cv);
SV* self = ST(0);
HV* hv = (HV*)SvRV(self);
SV** valp = hv_fetch(hv, "value", 5, 0);
ST(0) = (valp && *valp) ? *valp : &PL_sv_undef;
XSRETURN(1);
}
Register with:
functions => {
'Package::getter' => { source => 'my_getter', is_xs_native => 1 },
}
Functions with Variable Arguments
Use JIT_ARGS or dTHX; dXSARGS to access additional arguments:
SV* my_setter(SV* self, ...) {
JIT_ARGS;
if (items < 2) {
croak("Value required");
}
SV* value = ST(1); /* First argument after self */
/* ... do something with value ... */
return newSVsv(value);
}
Returning Self for Method Chaining
When returning self for method chaining, you must increment the reference count:
SV* my_chainable(SV* self, ...) {
JIT_ARGS;
/* ... modify object ... */
SvREFCNT_inc(self);
return self;
}
Creating Objects
SV* my_constructor(SV* class_sv, ...) {
dTHX;
const char* classname = SvPV_nolen(class_sv);
HV* self_hv = newHV();
/* Store attributes */
hv_store(self_hv, "attr", 4, newSViv(0), 0);
/* Bless and return */
return sv_bless(newRV_noinc((SV*)self_hv),
gv_stashpv(classname, GV_ADD));
}
C API
XS::JIT provides a C API that can be used directly from other XS modules without Perl stack overhead. Include the header file:
#include "xs_jit.h"
The function mapping structure:
typedef struct {
const char *target; /* "Package::funcname" - where to install */
const char *source; /* "c_func_name" - function in user's C code */
int has_varargs; /* 1 if function takes variable arguments */
int is_xs_native; /* 1 if function is already XS-native */
} XS_JIT_Func;
Example usage:
XS_JIT_Func funcs[] = {
{ "Foo::new", "jit_new", 0, 1 }, /* XS-native, no wrapper */
{ "Foo::name", "jit_name", 0, 1 }, /* XS-native, no wrapper */
{ NULL, NULL, 0, 0 }
};
xs_jit_compile(aTHX_ c_code, "MyModule::JIT::Foo",
funcs, 2, NULL, 0);
Set is_xs_native to 1 when your functions use XS_EUPXS(), dXSARGS, and XSRETURN() directly. This creates simple aliases instead of wrappers.
The header file location can be found programmatically:
use XS::JIT;
print XS::JIT->inc_dir(), "\n";
Or use the cflags method in your Makefile.PL:
use XS::JIT;
WriteMakefile(
...
INC => XS::JIT->cflags(),
);
CONVENIENCE MACROS
JIT_ARGS
The JIT_ARGS macro initializes both the thread context and the XS argument stack in a single statement. Use this at the start of functions that need to access variable arguments:
SV* my_function(SV* self, ...) {
JIT_ARGS; /* expands to: dTHX; dXSARGS */
if (items < 2) croak("Need at least one argument");
SV* arg = ST(1);
return newSVsv(arg);
}
This is equivalent to:
SV* my_function(SV* self, ...) {
dTHX;
dXSARGS;
...
}
INLINE::C COMPATIBILITY
XS::JIT provides the following macros for compatibility with code written for Inline::C:
Inline_Stack_Vars - equivalent to dXSARGS
Inline_Stack_Items - number of arguments (items)
Inline_Stack_Item(x) - get argument x (ST(x))
Inline_Stack_Reset - reset stack pointer (sp = mark)
Inline_Stack_Push(x) - push value onto stack (XPUSHs(x))
Inline_Stack_Done - finalize stack (PUTBACK)
Inline_Stack_Return(x) - return x values (XSRETURN(x))
Inline_Stack_Void - return no values (XSRETURN(0))
BENCHMARK
============================================================
XS::JIT vs Inline::C Benchmark
============================================================
Testing XS::JIT...
----------------------------------------
First compile: 0.3311 seconds
Already loaded: 0.000026 seconds
Runtime (10k iterations): 0.0094 seconds
Testing Inline::C...
----------------------------------------
First compile: 0.7568 seconds
Runtime (10k iterations): 0.0127 seconds
============================================================
Summary
============================================================
First compile speedup: 2.3x faster
Runtime performance: 1.36x faster (XS::JIT)
SEE ALSO
Inline::C - The original runtime C compiler for Perl (which has more features)
perlxs - XS language reference
perlguts - Perl internal functions for XS programming
perlapi - Perl API listing
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)