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}