Skip to main content

shape_jit/ffi/object/
closure.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 1 site
3//     jit_box(HK_CLOSURE, ...) — jit_make_closure
4//   Category B (intermediate/consumed): 1 site
5//     JITClosure::new() allocates captures via Box — consumed by jit_box
6//   Category C (heap islands): 0 sites
7//!
8//! Closure Creation
9//!
10//! Functions for creating closures with captured values.
11
12use super::super::super::context::{JITClosure, JITContext};
13use super::super::super::nan_boxing::*;
14
15// ============================================================================
16// Closure Creation
17// ============================================================================
18
19/// Create a closure with captured values from the stack.
20///
21/// Supports unlimited captures via heap-allocated capture array.
22#[inline(always)]
23pub extern "C" fn jit_make_closure(
24    ctx: *mut JITContext,
25    function_id: u16,
26    captures_count: u16,
27) -> u64 {
28    unsafe {
29        if ctx.is_null() {
30            return box_function(function_id);
31        }
32
33        let ctx_ref = &mut *ctx;
34        let count = captures_count as usize;
35
36        // Check stack bounds
37        if ctx_ref.stack_ptr < count || ctx_ref.stack_ptr > 512 {
38            return box_function(function_id);
39        }
40
41        // Pop captured values from stack
42        let mut captures = Vec::with_capacity(count);
43        for _ in 0..count {
44            ctx_ref.stack_ptr -= 1;
45            captures.push(ctx_ref.stack[ctx_ref.stack_ptr]);
46        }
47        captures.reverse(); // Restore original order
48
49        // Create closure struct with dynamic captures
50        let closure = JITClosure::new(function_id, &captures);
51        jit_box(HK_CLOSURE, *closure)
52    }
53}