view release on metacpan or search on metacpan
infix/src/arch/aarch64/abi_arm64_emitters.c view on Meta::CPAN
INFIX_INTERNAL void emit_arm64_arith_imm(
code_buffer * buf, bool is_sub, bool is64, bool set_flags, arm64_gpr dest, arm64_gpr base, uint32_t imm) {
uint32_t instr = is_sub ? 0x51000000 : 0x11000000;
if (is64)
instr |= (1u << 31);
if (set_flags)
instr |= (1u << 29);
if (imm <= 0xFFF) // Check for un-shifted 12-bit immediate.
instr |= (imm & 0xFFF) << 10;
else if ((imm & 0xFFF) == 0 && (imm >> 12) <= 0xFFF && (imm >> 12) > 0) { // Check for shifted 12-bit immediate.
instr |= (1u << 22); // 'sh' bit selects LSL #12 shift.
instr |= ((imm >> 12) & 0xFFF) << 10;
}
else {
// Immediate is too large. Load it into a scratch register (X15) and do a register-based operation.
arm64_gpr scratch_reg = X15_REG;
emit_arm64_load_u64_immediate(buf, scratch_reg, imm);
uint32_t reg_instr = is_sub ? 0x4B000000 : 0x0B000000;
if (is64)
reg_instr |= (1u << 31);
if (set_flags)
infix/src/arch/x64/abi_x64_emitters.c view on Meta::CPAN
bool b,
uint8_t aaa) // Masking/control bits
{
emit_byte(buf, 0x62);
// Byte 2: P0 - R, X, B, R' bits are inverted. 0 means 1, 1 means 0.
uint8_t p0 = 0;
p0 |= (R ? 0 : 1) << 7; // Inverted R bit
p0 |= (X ? 0 : 1) << 6; // Inverted X bit
p0 |= (B ? 0 : 1) << 5; // Inverted B bit
p0 |= (R_prime ? 0 : 1) << 4; // Inverted R' bit
p0 |= (map & 0x0F); // Low 4 bits select the opcode map (0F, 0F38, 0F3A)
emit_byte(buf, p0);
// Byte 3: P1
uint8_t p1 = 0;
p1 |= (pp & 0b11);
p1 |= (1 << 2); // ' (marks EVEX), must be 1
p1 |= ((~vvvv & 0xF) << 3); // vvvv field is inverted
p1 |= W ? (1 << 7) : 0;
emit_byte(buf, p1);
// Byte 4: P2
uint8_t p2 = 0;
infix/src/common/infix_config.h view on Meta::CPAN
/**
* @file infix_config.h
* @brief Platform, architecture, and ABI detection macros.
* @ingroup internal_common
*
* @details This header is the first to be included by `infix_internals.h` and is
* responsible for defining a consistent set of `INFIX_*` macros that describe the
* build environment. It is the central point of configuration for the entire library,
* adapting the build to different operating systems, compilers, and CPU architectures.
*
* Its most critical function is to select the correct **Application Binary Interface (ABI)**
* implementation to use for JIT code generation. This is achieved through a cascade
* of preprocessor checks that can be overridden by the user for cross-compilation.
* By the end of this file, exactly one `INFIX_ABI_*` macro must be defined, which
* determines which `abi_*.c` file is included in the unity build.
*
* @internal
*/
#pragma once
// System Feature Test Macros
/**
infix/src/jit/trampoline.c view on Meta::CPAN
extern const infix_direct_forward_abi_spec g_sysv_x64_direct_forward_spec;
#elif defined(INFIX_ABI_AAPCS64)
extern const infix_forward_abi_spec g_arm64_forward_spec;
extern const infix_reverse_abi_spec g_arm64_reverse_spec;
extern const infix_direct_forward_abi_spec g_arm64_direct_forward_spec;
#endif
/**
* @internal
* @brief Retrieves a pointer to the ABI specification v-table for forward calls.
* @details This function is the entry point to the ABI abstraction layer. It uses
* compile-time preprocessor macros (defined in `infix_config.h`) to select and
* return the correct v-table for the target platform.
* @return A pointer to the active `infix_forward_abi_spec`, or `nullptr` if the
* platform is unsupported.
*/
const infix_forward_abi_spec * get_current_forward_abi_spec() {
#if defined(INFIX_ABI_WINDOWS_X64)
return &g_win_x64_forward_spec;
#elif defined(INFIX_ABI_SYSV_X64)
return &g_sysv_x64_forward_spec;
#elif defined(INFIX_ABI_AAPCS64)
infix/src/jit/trampoline.c view on Meta::CPAN
#if defined(INFIX_ABI_WINDOWS_X64)
#include "../arch/x64/abi_win_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_SYSV_X64)
#include "../arch/x64/abi_sysv_x64.c"
#include "../arch/x64/abi_x64_emitters.c"
#elif defined(INFIX_ABI_AAPCS64)
#include "../arch/aarch64/abi_arm64.c"
#include "../arch/aarch64/abi_arm64_emitters.c"
#else
#error "No supported ABI was selected for the unity build in trampoline.c."
#endif
lib/Affix/Build.pod view on Meta::CPAN
While originally developed to compile test fixtures for the Affix suite, it has evolved into a robust tool for creating
polyglot extensions. It abstracts away the complexity of invoking various compilers, normalizing object file
extensions, handling platform-specific linker flags (such as MinGW vs. MSVC on Windows), and ensuring that language
runtimes (like the Go GC or .NET Runtime) are correctly initialized.
It serves as a powerful, polyglot alternative to C<Inline::*> modulesâallowing you to write native code in your
language of choice and instantly bind to it from Perl using L<Affix>.
=head2 Build Strategies
The builder automatically selects the optimal strategy based on the input sources:
=over
=item 1. B<Native Toolchain Strategy> (Single Language)
If you provide source files for only B<one> language, C<Affix::Build> delegates the entire build process to that
language's native toolchain (e.g., C<go build -buildmode=c-shared>, C<rustc --crate-type cdylib>, C<dotnet publish>).
This ensures that the language's standard library and runtime environment are configured exactly as intended by its
maintainers.
lib/Affix/Wrap.pod view on Meta::CPAN
Optional. An array reference of paths to search for C<#include "..."> directives. The directory of every file listed in
C<project_files> is automatically added to this list.
=item C<types>
Optional. A hash reference for manually mapping type names to L<Affix> type objects or definition strings. Very useful
for masking complex internal library structures behind Pointer[Void] handles.
=item C<driver>
Optional. Explicitly select the parser driver. Values are C<'Clang'> or C<'Regex'>. If omitted, C<Affix::Wrap> attempts
to find the C<clang> executable and falls back to Regex if unavailable.
=back
=head1 METHODS
=head2 wrap( $lib, [$target_package] )
$binder->wrap( $lib );
$binder->wrap( $lib, 'My::Package' );
t/019_fileio.t view on Meta::CPAN
affix $lib, 'c_read_char', [ Pointer [File] ] => Int;
affix $lib, 'c_create_tmpfile', [] => Pointer [File];
affix $lib, 'c_is_null_file', [ Pointer [File] ] => Int;
#
subtest 'Writing to a Perl filehandle from C' => sub {
my ( $fh, $filename ) = tempfile();
# Note: We use a real file because PerlIO_findFILE (used internally)
# requires a valid C-level FILE* which scalar handles (\$) might not provide.
# Turn off buffering to ensure C sees the file state immediately
my $old_fh = select($fh);
$| = 1;
select($old_fh);
my $bytes = c_write_to_file( $fh, 'Hello from C' );
ok $bytes > 0, 'C function returned success count';
close $fh;
# Verify content
open my $check, '<', $filename or die $!;
my $content = <$check>;
is $content, 'Hello from C', 'Data written by C appears in file';
unlink $filename;
};
t/019_fileio.t view on Meta::CPAN
# Define the struct type in Perl.
# Use Pointer[File] because the C struct member is FILE*.
typedef Logger => Struct [ log_file => Pointer [File], counter => Int ];
# Bind functions
affix $lib, 'init_logger', [ Pointer [ Logger() ], Pointer [File] ] => Void;
affix $lib, 'log_message', [ Pointer [ Logger() ], String ] => Void;
affix $lib, 'create_logger', [ Pointer [File] ] => Logger();
subtest 'File inside Struct (Pointer)' => sub {
my ( $fh, $filename ) = tempfile();
my $old_fh = select($fh);
$| = 1;
select($old_fh);
# Allocate struct memory
my $logger = malloc( sizeof( Logger() ) );
# Pass filehandle to C to store in struct
init_logger( $logger, $fh );
# Verify via C function
log_message( $logger, 'First message' );
log_message( $logger, 'Second message' );
t/019_fileio.t view on Meta::CPAN
is scalar(@lines), 2, 'File has 2 lines';
like $lines[0], qr/\[1\] First message/, 'Line 1 matches';
like $lines[1], qr/\[2\] Second message/, 'Line 2 matches';
free($logger);
# Keep $fh alive until test end to avoid closing underneath C
close $fh;
};
subtest 'File inside Struct (Value Return)' => sub {
my ( $fh, $filename ) = tempfile();
my $old_fh = select($fh);
$| = 1;
select($old_fh);
# Call C function returning a struct by value
my $logger_hash = create_logger($fh);
is $logger_hash->{counter}, 100, 'Counter is correct';
ok $logger_hash->{log_file}, 'Got filehandle back';
is ref( $logger_hash->{log_file} ), 'GLOB', 'It is a glob';
# Write using the returned handle to verify it works
# Note: $logger_hash->{log_file} wraps the same FILE* as $fh.
ok syswrite( $logger_hash->{log_file}, "Direct write from Perl\n" ), 'syswrite to the handle from Perl';
t/019_fileio.t view on Meta::CPAN
}
END_C2
# Array of Pointers to Files (FILE* files[3])
affix $lib2, 'write_all', [ Array [ Pointer [File], 3 ], String ] => Void;
my ( $fh1, $f1 ) = tempfile();
my ( $fh2, $f2 ) = tempfile();
my ( $fh3, $f3 ) = tempfile();
# Flush buffers
for my $h ( $fh1, $fh2, $fh3 ) { my $o = select($h); $| = 1; select($o); }
# Pass array of handles
write_all( [ $fh1, $fh2, $fh3 ], 'Broadcast' );
close $_ for ( $fh1, $fh2, $fh3 );
# Verify
for my $f ( $f1, $f2, $f3 ) {
open my $in, '<', $f;
is <$in>, 'Broadcast', "File $f written to";
close $in;