use crate::context::JITContext;
use crate::ffi::value_ffi::*;
#[allow(unused_imports)]
use crate::ffi::jit_kinds::*;
use std::ffi::c_void;
use std::cell::Cell;
thread_local! {
static TRAMPOLINE_VM: Cell<*mut shape_vm::VirtualMachine> = const { Cell::new(std::ptr::null_mut()) };
static JIT_RUNTIME_ERROR: std::cell::RefCell<Option<String>> =
const { std::cell::RefCell::new(None) };
}
pub fn set_jit_runtime_error(message: String) {
JIT_RUNTIME_ERROR.with(|cell| *cell.borrow_mut() = Some(message));
}
pub fn take_jit_runtime_error() -> Option<String> {
JIT_RUNTIME_ERROR.with(|cell| cell.borrow_mut().take())
}
pub unsafe fn set_trampoline_vm(vm: *mut shape_vm::VirtualMachine) {
TRAMPOLINE_VM.with(|cell| cell.set(vm));
}
pub fn unset_trampoline_vm() {
TRAMPOLINE_VM.with(|cell| cell.set(std::ptr::null_mut()));
}
pub fn with_trampoline_vm<F, R>(f: F) -> Option<R>
where
F: FnOnce(&shape_vm::VirtualMachine) -> R,
{
TRAMPOLINE_VM.with(|cell| {
let vm_ptr = cell.get();
if vm_ptr.is_null() {
None
} else {
Some(f(unsafe { &*vm_ptr }))
}
})
}
pub fn with_trampoline_vm_mut<F, R>(f: F) -> Option<R>
where
F: FnOnce(&mut shape_vm::VirtualMachine) -> R,
{
TRAMPOLINE_VM.with(|cell| {
let vm_ptr = cell.get();
if vm_ptr.is_null() {
None
} else {
Some(f(unsafe { &mut *vm_ptr }))
}
})
}
fn dispatch_call_via_trampoline_vm(
function_id: u32,
upvalue_bits: Option<&[u64]>,
jit_args: &[u64],
jit_ctx: *mut JITContext,
) -> u64 {
use shape_value::NativeKind;
let raise_trampoline_error = |message: String| {
set_jit_runtime_error(message);
if !jit_ctx.is_null() {
unsafe { (*jit_ctx).pending_call_error = 1 };
}
};
let arg_pairs: Vec<(u64, NativeKind)> = jit_args
.iter()
.copied()
.map(|bits| (bits, NativeKind::UInt64))
.collect();
with_trampoline_vm_mut(|vm| {
let func_id = function_id as u16;
match upvalue_bits {
Some(caps) => {
let capture_pairs: Vec<(u64, NativeKind)> = caps
.iter()
.copied()
.map(|bits| (bits, NativeKind::UInt64))
.collect();
match vm.jit_trampoline_call_closure(func_id, &capture_pairs, &arg_pairs, None) {
Ok(bits) => bits,
Err(e) => {
raise_trampoline_error(e.to_string());
TAG_NULL
}
}
}
None => {
use shape_value::{KindedSlot, ValueSlot};
let callee = KindedSlot::new(
ValueSlot::from_raw(func_id as u64),
NativeKind::UInt64,
);
let kinded_args: Vec<KindedSlot> = arg_pairs
.iter()
.map(|(bits, kind)| {
KindedSlot::new(ValueSlot::from_raw(*bits), *kind)
})
.collect();
match vm.call_value_immediate_nb(&callee, &kinded_args, None) {
Ok(result) => {
let bits = result.slot.raw();
std::mem::forget(result);
std::mem::forget(callee);
std::mem::forget(kinded_args);
bits
}
Err(e) => {
raise_trampoline_error(e.to_string());
TAG_NULL
}
}
}
}
})
.unwrap_or_else(|| {
raise_trampoline_error(format!(
"JIT value-call for function {} could not reach the interpreter \
trampoline",
function_id,
));
TAG_NULL
})
}
fn dispatch_module_fn_call(
_module_fn_id: u32,
_jit_args: &[u64],
_ctx: *mut JITContext,
) -> u64 {
todo!(
"phase-2c §2.7.10/Q11: JIT-side kinded handler ABI rebuild — \
dispatch_module_fn_call. ModuleFunction callee construction and \
the call_value_immediate_nb dispatch shell now take &KindedSlot \
per ADR-006 §2.7.10/Q11; the deleted ValueWord::from_module_function \
constructor needs a kinded replacement at the producing call \
signature per §2.7.5. See \
docs/cluster-audits/wave-10-jit-playbook.md §5."
)
}
pub extern "C" fn jit_call_function(
ctx: *mut JITContext,
function_id: u16,
_args: *const u64, _arg_count: usize,
) -> u64 {
unsafe {
if ctx.is_null() {
return TAG_NULL;
}
let ctx_ref = &mut *ctx;
if ctx_ref.function_table.is_null() || (function_id as usize) >= ctx_ref.function_table_len
{
return TAG_NULL;
}
let fn_ptr = *ctx_ref.function_table.add(function_id as usize);
let _result_code = fn_ptr(ctx);
if ctx_ref.stack_ptr > 0 {
ctx_ref.stack_ptr -= 1;
ctx_ref.stack[ctx_ref.stack_ptr]
} else {
TAG_NULL
}
}
}
pub extern "C" fn jit_call_value(ctx: *mut JITContext) -> u64 {
use crate::ffi::jit_kinds::unified_unbox;
use crate::ffi::stack_kind_code;
use crate::context::JITClosure;
use shape_value::{HeapKind, NativeKind, heap_value::HeapValue};
use std::sync::Arc;
unsafe {
if ctx.is_null() {
return TAG_NULL;
}
let ctx_ref = &mut *ctx;
if ctx_ref.stack_ptr == 0 {
tracing::debug!(
target: "shape_jit",
"jit-call-value BAIL: stack_ptr=0 at arg_count pop",
);
return TAG_NULL;
}
ctx_ref.stack_ptr -= 1;
let arg_count = ctx_ref.stack[ctx_ref.stack_ptr] as usize;
ctx_ref.stack_kinds[ctx_ref.stack_ptr] = stack_kind_code::SENTINEL;
let mut arg_pairs: Vec<(u64, NativeKind)> = Vec::with_capacity(arg_count);
for _ in 0..arg_count {
if ctx_ref.stack_ptr == 0 {
return TAG_NULL;
}
ctx_ref.stack_ptr -= 1;
let bits = ctx_ref.stack[ctx_ref.stack_ptr];
let code = ctx_ref.stack_kinds[ctx_ref.stack_ptr];
ctx_ref.stack_kinds[ctx_ref.stack_ptr] = stack_kind_code::SENTINEL;
let kind = match stack_kind_code::decode(code) {
Some(k) => k,
None => {
tracing::debug!(
target: "shape_jit",
code,
stack_ptr = ctx_ref.stack_ptr,
"jit-call-value SURFACE \u{a7}2.7.7 / Q9: arg \
kind-byte is SENTINEL / reserved. The producing \
call site at `mir_compiler/terminators.rs` must \
stamp a concrete NativeKind for every push (no \
Bool-default fallback per \u{a7}2.7.7 #9).",
);
return TAG_NULL;
}
};
arg_pairs.push((bits, kind));
}
arg_pairs.reverse();
if ctx_ref.stack_ptr == 0 {
return TAG_NULL;
}
ctx_ref.stack_ptr -= 1;
let callee_bits = ctx_ref.stack[ctx_ref.stack_ptr];
let callee_code = ctx_ref.stack_kinds[ctx_ref.stack_ptr];
ctx_ref.stack_kinds[ctx_ref.stack_ptr] = stack_kind_code::SENTINEL;
let callee_kind = match stack_kind_code::decode(callee_code) {
Some(k) => k,
None => {
tracing::debug!(
target: "shape_jit",
callee_code,
stack_ptr = ctx_ref.stack_ptr,
"jit-call-value SURFACE \u{a7}2.7.7 / Q9: callee kind-byte \
is SENTINEL / reserved. The producing call site must \
stamp the callee's NativeKind from `operand_slot_kind` \
per ADR-006 \u{a7}2.7.11 / Q12. No Bool-default fallback \
(\u{a7}2.7.7 #9).",
);
return TAG_NULL;
}
};
let function_id: u16;
let mut vm_captures: Option<Vec<u64>> = None;
match callee_kind {
NativeKind::Ptr(HeapKind::Closure) => {
if callee_bits == 0 {
tracing::debug!(
target: "shape_jit",
"jit-call-value BAIL \u{a7}2.7.11/Q12: callee \
stamped Ptr(HeapKind::Closure) but bits=0 \u{2014} \
producing site emitted a null callee.",
);
return TAG_NULL;
}
if is_inline_function(callee_bits) {
function_id = unbox_function_id(callee_bits);
let args: Vec<u64> = arg_pairs.iter().map(|(b, _)| *b).collect();
if !ctx_ref.function_table.is_null()
&& (function_id as usize) < ctx_ref.function_table_len
{
let raw_fn_ptr =
*(ctx_ref.function_table as *const *const u8)
.add(function_id as usize);
if !raw_fn_ptr.is_null() {
ctx_ref.stack_ptr = 0;
let _signal = call_jit_fn_with_args(raw_fn_ptr, ctx, &args);
if ctx_ref.stack_ptr > 0 {
ctx_ref.stack_ptr -= 1;
let ret_bits = ctx_ref.stack[ctx_ref.stack_ptr];
ctx_ref.stack_kinds[ctx_ref.stack_ptr] =
stack_kind_code::SENTINEL;
return ret_bits;
}
return TAG_NULL;
}
}
return dispatch_call_via_trampoline_vm(
function_id as u32,
None,
&args,
ctx,
);
}
let arc = Arc::<HeapValue>::from_raw(callee_bits as *const HeapValue);
let extracted: Option<(u16, Vec<u64>)> = match &*arc {
HeapValue::ClosureRaw(block) => {
let fid = shape_value::v2::closure_raw::typed_closure_function_id(
block.as_ptr(),
);
let cap_count = block.layout().capture_count();
let mut caps: Vec<u64> = Vec::with_capacity(cap_count);
for idx in 0..cap_count {
let (cap_bits, cap_kind) = block.read_capture_kinded(idx);
let borrow_view = shape_value::KindedSlot::new(
shape_value::ValueSlot::from_raw(cap_bits),
cap_kind,
);
let retained = borrow_view.clone();
std::mem::forget(borrow_view);
std::mem::forget(retained);
caps.push(cap_bits);
}
Some((fid, caps))
}
other => {
tracing::debug!(
target: "shape_jit",
heap_kind = ?other.kind(),
"jit-call-value SURFACE \u{a7}2.7.6/Q8: callee \
stamped Ptr(HeapKind::Closure) but HeapValue \
arm is not ClosureRaw. Producing site \
mislabeled the slot kind.",
);
None
}
};
let _ = Arc::into_raw(arc);
match extracted {
Some((f, c)) => {
function_id = f;
vm_captures = Some(c);
}
None => return TAG_NULL,
}
}
NativeKind::Ptr(HeapKind::ModuleFn) => {
tracing::debug!(
target: "shape_jit",
"jit-call-value SURFACE \u{a7}2.7.26: ModuleFn callee \
not implemented in jit_call_value.",
);
return TAG_NULL;
}
NativeKind::UInt64
| NativeKind::Int64
| NativeKind::IntSize
| NativeKind::UIntSize
| NativeKind::NullableUInt64
| NativeKind::NullableInt64
| NativeKind::NullableIntSize
| NativeKind::NullableUIntSize => {
if is_inline_function(callee_bits) {
function_id = unbox_function_id(callee_bits);
} else if is_heap_kind(callee_bits, HK_CLOSURE) {
let closure = unified_unbox::<JITClosure>(callee_bits);
function_id = closure.function_id;
let count = closure.captures_count as usize;
let mut caps: Vec<u64> = Vec::with_capacity(count);
for i in 0..count {
caps.push(*closure.captures_ptr.add(i));
}
vm_captures = Some(caps);
} else {
tracing::debug!(
target: "shape_jit",
callee_bits,
"jit-call-value SURFACE \u{a7}2.7.5: callee_bits \
stamped UInt64 but is neither inline function \
(TAG_FUNCTION) nor unified-heap HK_CLOSURE. \
Producing site stamped the carrier kind but \
emitted bits that don't match either UInt64-class \
shape.",
);
return TAG_NULL;
}
}
other => {
tracing::debug!(
target: "shape_jit",
kind = ?other,
"jit-call-value SURFACE \u{a7}2.7.11/Q12: callee kind \
is not a recognized callable kind. The \u{a7}2.7.11/Q12 \
callee-classification kinds at the indirect-call entry \
are Ptr(HeapKind::Closure) (raw-Arc closure shape), \
Ptr(HeapKind::ModuleFn) (deferred), and UInt64/Int64-\
family (function-id and JIT-internal NaN-box shapes).",
);
return TAG_NULL;
}
}
let args: Vec<u64> = arg_pairs.iter().map(|(b, _)| *b).collect();
if vm_captures.is_none()
&& !ctx_ref.function_table.is_null()
&& (function_id as usize) < ctx_ref.function_table_len
{
let raw_fn_ptr =
*(ctx_ref.function_table as *const *const u8).add(function_id as usize);
if !raw_fn_ptr.is_null() {
ctx_ref.stack_ptr = 0;
let _signal = call_jit_fn_with_args(raw_fn_ptr, ctx, &args);
if ctx_ref.stack_ptr > 0 {
ctx_ref.stack_ptr -= 1;
let ret_bits = ctx_ref.stack[ctx_ref.stack_ptr];
ctx_ref.stack_kinds[ctx_ref.stack_ptr] = stack_kind_code::SENTINEL;
return ret_bits;
}
return TAG_NULL;
}
}
let upvalues: Option<&[u64]> = vm_captures.as_deref();
dispatch_call_via_trampoline_vm(
function_id as u32,
upvalues,
&args,
ctx,
)
}
}
pub(crate) unsafe fn call_jit_fn_with_args(
fn_ptr: *const u8,
ctx: *mut JITContext,
args: &[u64],
) -> i32 {
type F0 = unsafe extern "C" fn(*mut JITContext) -> i32;
type F1 = unsafe extern "C" fn(*mut JITContext, u64) -> i32;
type F2 = unsafe extern "C" fn(*mut JITContext, u64, u64) -> i32;
type F3 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64) -> i32;
type F4 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64, u64) -> i32;
type F5 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64, u64, u64) -> i32;
type F6 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64, u64, u64, u64) -> i32;
type F7 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64, u64, u64, u64, u64) -> i32;
type F8 = unsafe extern "C" fn(*mut JITContext, u64, u64, u64, u64, u64, u64, u64, u64) -> i32;
let result = match args.len() {
0 => std::mem::transmute::<_, F0>(fn_ptr)(ctx),
1 => std::mem::transmute::<_, F1>(fn_ptr)(ctx, args[0]),
2 => std::mem::transmute::<_, F2>(fn_ptr)(ctx, args[0], args[1]),
3 => std::mem::transmute::<_, F3>(fn_ptr)(ctx, args[0], args[1], args[2]),
4 => std::mem::transmute::<_, F4>(fn_ptr)(ctx, args[0], args[1], args[2], args[3]),
5 => std::mem::transmute::<_, F5>(fn_ptr)(ctx, args[0], args[1], args[2], args[3], args[4]),
6 => std::mem::transmute::<_, F6>(fn_ptr)(ctx, args[0], args[1], args[2], args[3], args[4], args[5]),
7 => std::mem::transmute::<_, F7>(fn_ptr)(ctx, args[0], args[1], args[2], args[3], args[4], args[5], args[6]),
8 => std::mem::transmute::<_, F8>(fn_ptr)(ctx, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]),
_ => {
-1
}
};
result
}
pub extern "C" fn jit_control_fold(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_fold. The deleted UnifiedArray-walk decoded element \
bits without per-element NativeKind tracking; the kinded rebuild \
reads Arc<TypedArrayData> per ADR-006 §2.7.6/Q8 and dispatches \
the callback through the §2.7.10/Q11 kinded handler ABI."
)
}
pub extern "C" fn jit_control_reduce(ctx: *mut JITContext) -> u64 {
jit_control_fold(ctx)
}
pub extern "C" fn jit_control_map(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_map. Receiver decode + result allocation both \
block on the kinded TypedArray<T> rebuild per ADR-006 §2.7.6/Q8."
)
}
pub extern "C" fn jit_control_filter(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_filter. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
pub extern "C" fn jit_control_foreach(_ctx: *mut JITContext, _count: usize) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_foreach. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
pub extern "C" fn jit_control_find(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_find. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
unsafe fn jit_callable_invoker(
_ctx: *mut c_void,
_callable: &u64,
_args: &[u64],
) -> Result<u64, String> {
Err(
"phase-2c §2.7.10/Q11: jit_callable_invoker is a kinded-ABI \
surface awaiting the value-call kind-companion lowering"
.to_string(),
)
}
enum ForeignInvokeMode {
Any,
NativeOnly,
DynamicOnly,
}
unsafe fn jit_call_foreign_impl(
_ctx: *mut JITContext,
_foreign_idx: u32,
_arg_count: usize,
_mode: ForeignInvokeMode,
) -> u64 {
todo!(
"phase-2c §2.7.10/Q11: JIT-side kinded foreign-call ABI rebuild — \
jit_call_foreign_impl. The foreign_bridge invoke / invoke_native / \
invoke_dynamic surfaces still take &[ValueWord]; once that crate's \
own kinded-ABI migration lands, args flow as &[KindedSlot] per \
ADR-006 §2.7.10/Q11 and the Err() arm constructs the Result::Err \
carrier through the kinded HeapKind::Err producer per §2.7.6/Q8. \
See docs/cluster-audits/wave-10-jit-playbook.md §5."
)
}
pub extern "C" fn jit_call_foreign(
ctx: *mut JITContext,
foreign_idx: u32,
arg_count: usize,
) -> u64 {
unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::Any) }
}
pub extern "C" fn jit_call_foreign_native(
ctx: *mut JITContext,
foreign_idx: u32,
arg_count: usize,
) -> u64 {
unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::NativeOnly) }
}
pub extern "C" fn jit_call_foreign_dynamic(
ctx: *mut JITContext,
foreign_idx: u32,
arg_count: usize,
) -> u64 {
unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::DynamicOnly) }
}
unsafe fn jit_call_foreign_native_args_fixed<const N: usize>(
_ctx: *mut JITContext,
_foreign_idx: u32,
_args: [u64; N],
) -> u64 {
todo!(
"phase-2c §2.7.10/Q11: JIT-side kinded foreign-call ABI rebuild — \
jit_call_foreign_native_args_fixed<N>. Same gating as \
jit_call_foreign_impl: foreign_bridge invoke_native still takes \
&[ValueWord]; once that crate's own kinded-ABI migration lands, \
the fixed-arity boxed_args array becomes [KindedSlot; N] per \
ADR-006 §2.7.10/Q11. See \
docs/cluster-audits/wave-10-jit-playbook.md §5."
)
}
macro_rules! define_jit_call_foreign_native_fixed {
($name:ident, [$($arg:ident),*]) => {
pub extern "C" fn $name(
ctx: *mut JITContext,
foreign_idx: u32,
$($arg: u64),*
) -> u64 {
unsafe { jit_call_foreign_native_args_fixed(ctx, foreign_idx, [$($arg),*]) }
}
};
}
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_0, []);
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_1, [arg0]);
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_2, [arg0, arg1]);
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_3, [arg0, arg1, arg2]);
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_4, [arg0, arg1, arg2, arg3]);
define_jit_call_foreign_native_fixed!(jit_call_foreign_native_5, [arg0, arg1, arg2, arg3, arg4]);
define_jit_call_foreign_native_fixed!(
jit_call_foreign_native_6,
[arg0, arg1, arg2, arg3, arg4, arg5]
);
define_jit_call_foreign_native_fixed!(
jit_call_foreign_native_7,
[arg0, arg1, arg2, arg3, arg4, arg5, arg6]
);
define_jit_call_foreign_native_fixed!(
jit_call_foreign_native_8,
[arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7]
);
pub unsafe extern "C" fn jit_vm_fallback_trampoline(
_ctx: *mut std::ffi::c_void,
_function_id: u32,
_args_ptr: *const u64,
_args_len: u32,
) -> u64 {
TAG_NULL
}
pub extern "C" fn jit_control_find_index(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_find_index. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
pub extern "C" fn jit_control_some(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_some. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
pub extern "C" fn jit_control_every(_ctx: *mut JITContext) -> u64 {
todo!(
"phase-2c §2.7.4 / W10 jit-playbook §5: JitArray rebuild — \
jit_control_every. Same kinded-TypedArray<T> rebuild as \
jit_control_map."
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn jit_runtime_error_channel_round_trips_and_clears() {
let _ = take_jit_runtime_error();
assert_eq!(take_jit_runtime_error(), None);
set_jit_runtime_error("Set.add(): key must be a string".to_string());
assert_eq!(
take_jit_runtime_error().as_deref(),
Some("Set.add(): key must be a string"),
);
assert_eq!(take_jit_runtime_error(), None);
}
#[test]
fn jit_runtime_error_channel_keeps_most_recent() {
let _ = take_jit_runtime_error();
set_jit_runtime_error("first error".to_string());
set_jit_runtime_error("second error".to_string());
assert_eq!(take_jit_runtime_error().as_deref(), Some("second error"));
let _ = take_jit_runtime_error();
}
#[test]
#[ignore = "SURFACE: jit_call_foreign_native_0 is extern \"C\" todo!() pending kinded foreign-call ABI rebuild (ADR-006 §2.7.10/Q11, docs/cluster-audits/wave-10-jit-playbook.md §5); extern C can't unwind, so #[should_panic] aborts the test process. Re-enable via `cargo test -- --ignored` once the underlying SURFACE closes."]
fn native_fixed_arity_helpers_surface_pending_kinded_abi() {
let _ = jit_call_foreign_native_0(std::ptr::null_mut(), 0);
}
#[allow(dead_code)]
fn native_fixed_arity_helpers_return_null_for_null_context() {
assert_eq!(jit_call_foreign_native_0(std::ptr::null_mut(), 0), TAG_NULL);
assert_eq!(
jit_call_foreign_native_1(std::ptr::null_mut(), 0, TAG_NULL),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_2(std::ptr::null_mut(), 0, TAG_NULL, TAG_NULL),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_3(std::ptr::null_mut(), 0, TAG_NULL, TAG_NULL, TAG_NULL),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_4(
std::ptr::null_mut(),
0,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL
),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_5(
std::ptr::null_mut(),
0,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL
),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_6(
std::ptr::null_mut(),
0,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL
),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_7(
std::ptr::null_mut(),
0,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL
),
TAG_NULL
);
assert_eq!(
jit_call_foreign_native_8(
std::ptr::null_mut(),
0,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL,
TAG_NULL
),
TAG_NULL
);
}
}