infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
401_large_stack.c File Reference

Unit test for FFI calls with a large number of arguments passed on the stack. More...

#include "common/double_tap.h"
#include "types.h"
#include <infix/infix.h>
#include <math.h>
#include <string.h>
Include dependency graph for 401_large_stack.c:

Macros

#define DBLTAP_IMPLEMENTATION
 
#define MAX_REG_DOUBLES   8
 
#define ONE_STACK_DOUBLE   (MAX_REG_DOUBLES + 1)
 
#define ARG(N)   c23_maybe_unused double arg##N
 
#define LIST10(M, p)   M(p##0), M(p##1), M(p##2), M(p##3), M(p##4), M(p##5), M(p##6), M(p##7), M(p##8), M(p##9)
 
#define LIST100(M, p)
 
#define ARGS_0_TO_99
 
#define ARGS_100_TO_499   LIST100(ARG, 1), LIST100(ARG, 2), LIST100(ARG, 3), LIST100(ARG, 4)
 
#define ARGS_500_TO_519   LIST10(ARG, 50), LIST10(ARG, 51)
 
#define NUM_LARGE_ARGS   520
 

Functions

double sum_max_reg_doubles (double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8)
 A function that takes the maximum number of doubles that can fit in registers.
 
double sum_one_stack_double (double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8, double a9)
 A function that takes just enough doubles to force one onto the stack.
 
double large_stack_callee (ARGS_0_TO_99, ARGS_100_TO_499, ARGS_500_TO_519)
 
int many_args_callback_handler (int a, double b, int c, const char *d, Point e, float f)
 A type-safe handler for a reverse call with mixed register and stack arguments.
 
void execute_many_args_callback (int(*func_ptr)(int, double, int, const char *, Point, float))
 A C harness to call the JIT-compiled reverse trampoline.
 
 subtest ("Forward calls with register and stack arguments")
 
 subtest ("Reverse call (callback) with stack arguments")
 

Variables

 TEST
 

Detailed Description

Unit test for FFI calls with a large number of arguments passed on the stack.

This test file is a stress test for the ABI implementation's handling of the stack. Modern calling conventions pass the first several arguments in registers, but all subsequent arguments are passed on the stack. This test verifies that infix can correctly handle both scenarios.

It covers:

  1. Register-Only Calls: A call is made with the maximum number of arguments that can fit in registers, ensuring the register-passing logic is correct.
  2. One Stack Argument: A call is made with just enough arguments to force one argument to be placed on the stack, verifying the transition from registers to the stack.
  3. Large Stack Allocation (>4KB): A call is made with a very large number of arguments (520 doubles), forcing the JIT-compiled trampoline to allocate a significant amount of stack space (>4KB). This is a regression test for bugs where stack offsets were calculated incorrectly for large frames, and it stress-tests the stack allocation and argument marshalling logic.
  4. Reverse Calls with Stack Arguments: A reverse trampoline is created for a function with enough arguments to require some to be passed on the stack. This verifies that the reverse call stub can correctly retrieve arguments from the caller's stack frame in addition to registers.

Macro Definition Documentation

◆ ARG

#define ARG (   N)    c23_maybe_unused double arg##N

◆ ARGS_0_TO_99

#define ARGS_0_TO_99
Value:
LIST10(ARG, ), LIST10(ARG, 1), LIST10(ARG, 2), LIST10(ARG, 3), LIST10(ARG, 4), LIST10(ARG, 5), LIST10(ARG, 6), \
LIST10(ARG, 7), LIST10(ARG, 8), LIST10(ARG, 9)
#define ARG(N)
Definition 401_large_stack.c:90
#define LIST10(M, p)
Definition 401_large_stack.c:91

◆ ARGS_100_TO_499

#define ARGS_100_TO_499   LIST100(ARG, 1), LIST100(ARG, 2), LIST100(ARG, 3), LIST100(ARG, 4)

◆ ARGS_500_TO_519

#define ARGS_500_TO_519   LIST10(ARG, 50), LIST10(ARG, 51)

◆ DBLTAP_IMPLEMENTATION

#define DBLTAP_IMPLEMENTATION

◆ LIST10

#define LIST10 (   M,
 
)    M(p##0), M(p##1), M(p##2), M(p##3), M(p##4), M(p##5), M(p##6), M(p##7), M(p##8), M(p##9)

◆ LIST100

#define LIST100 (   M,
 
)
Value:
LIST10(M, p##0), LIST10(M, p##1), LIST10(M, p##2), LIST10(M, p##3), LIST10(M, p##4), LIST10(M, p##5), \
LIST10(M, p##6), LIST10(M, p##7), LIST10(M, p##8), LIST10(M, p##9)

◆ MAX_REG_DOUBLES

#define MAX_REG_DOUBLES   8

◆ NUM_LARGE_ARGS

#define NUM_LARGE_ARGS   520

◆ ONE_STACK_DOUBLE

#define ONE_STACK_DOUBLE   (MAX_REG_DOUBLES + 1)

Function Documentation

◆ execute_many_args_callback()

void execute_many_args_callback ( int(*)(int, double, int, const char *, Point, float)  func_ptr)

A C harness to call the JIT-compiled reverse trampoline.

◆ large_stack_callee()

double large_stack_callee ( ARGS_0_TO_99  ,
ARGS_100_TO_499  ,
ARGS_500_TO_519   
)

◆ many_args_callback_handler()

int many_args_callback_handler ( int  a,
double  b,
int  c,
const char *  d,
Point  e,
float  f 
)

A type-safe handler for a reverse call with mixed register and stack arguments.

◆ subtest() [1/2]

subtest ( "Forward calls with register and stack arguments"  )

◆ subtest() [2/2]

subtest ( "Reverse call (callback) with stack arguments"  )

◆ sum_max_reg_doubles()

double sum_max_reg_doubles ( double  a1,
double  a2,
double  a3,
double  a4,
double  a5,
double  a6,
double  a7,
double  a8 
)

A function that takes the maximum number of doubles that can fit in registers.

◆ sum_one_stack_double()

double sum_one_stack_double ( double  a1,
double  a2,
double  a3,
double  a4,
double  a5,
double  a6,
double  a7,
double  a8,
double  a9 
)

A function that takes just enough doubles to force one onto the stack.

Variable Documentation

◆ TEST

TEST
Initial value:
{
plan(2)
#define plan(count)
Definition double_tap.h:163