Skip to main content

shape_jit/ffi/
iterator.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 1 site
3//     jit_box(HK_STRING, ...) — jit_iter_next string char iteration
4//   Category B (intermediate/consumed): 0 sites
5//   Category C (heap islands): 0 sites
6//!
7//! Iterator FFI Functions for JIT
8//!
9//! Functions for iterator operations (done check, next element) in JIT-compiled code.
10
11use super::super::context::JITRange;
12use super::super::jit_array::JitArray;
13use super::super::nan_boxing::*;
14use std::collections::HashMap;
15
16// ============================================================================
17// Iterator Operations
18// ============================================================================
19
20/// Check if iterator is exhausted
21/// Stack input: [iter, idx]
22/// Returns: TAG_BOOL_TRUE if done, TAG_BOOL_FALSE otherwise
23pub extern "C" fn jit_iter_done(iter_bits: u64, idx_bits: u64) -> u64 {
24    unsafe {
25        let idx = if is_number(idx_bits) {
26            unbox_number(idx_bits) as i64
27        } else {
28            return TAG_BOOL_TRUE; // Invalid index = done
29        };
30
31        if idx < 0 {
32            return TAG_BOOL_TRUE;
33        }
34
35        let done = match heap_kind(iter_bits) {
36            Some(HK_ARRAY) => {
37                let arr = jit_unbox::<JitArray>(iter_bits);
38                idx as usize >= arr.len()
39            }
40            Some(HK_STRING) => {
41                let s = jit_unbox::<String>(iter_bits);
42                idx as usize >= s.chars().count()
43            }
44            Some(HK_JIT_OBJECT) => {
45                // Check if it's a Range object with start/end fields
46                let obj = jit_unbox::<HashMap<String, u64>>(iter_bits);
47                if let (Some(&start_bits), Some(&end_bits)) = (obj.get("start"), obj.get("end")) {
48                    if is_number(start_bits) && is_number(end_bits) {
49                        let start = unbox_number(start_bits) as i64;
50                        let end = unbox_number(end_bits) as i64;
51                        let count = end - start;
52                        count <= 0 || idx >= count
53                    } else {
54                        true
55                    }
56                } else {
57                    true
58                }
59            }
60            Some(HK_RANGE) => {
61                let range = jit_unbox::<JITRange>(iter_bits);
62                if is_number(range.start) && is_number(range.end) {
63                    let start = unbox_number(range.start) as i64;
64                    let end = unbox_number(range.end) as i64;
65                    let count = end - start;
66                    count <= 0 || idx >= count
67                } else {
68                    true
69                }
70            }
71            _ => true, // Unknown type = done
72        };
73
74        if done { TAG_BOOL_TRUE } else { TAG_BOOL_FALSE }
75    }
76}
77
78/// Get next element from iterator
79/// Stack input: [iter, idx]
80/// Returns: Element at idx, or TAG_NULL if out of bounds
81pub extern "C" fn jit_iter_next(iter_bits: u64, idx_bits: u64) -> u64 {
82    unsafe {
83        let idx = if is_number(idx_bits) {
84            unbox_number(idx_bits) as i64
85        } else {
86            return TAG_NULL;
87        };
88
89        if idx < 0 {
90            return TAG_NULL;
91        }
92
93        match heap_kind(iter_bits) {
94            Some(HK_ARRAY) => {
95                let arr = jit_unbox::<JitArray>(iter_bits);
96                arr.get(idx as usize).copied().unwrap_or(TAG_NULL)
97            }
98            Some(HK_STRING) => {
99                let s = jit_unbox::<String>(iter_bits);
100                if let Some(ch) = s.chars().nth(idx as usize) {
101                    jit_box(HK_STRING, ch.to_string())
102                } else {
103                    TAG_NULL
104                }
105            }
106            Some(HK_JIT_OBJECT) => {
107                let obj = jit_unbox::<HashMap<String, u64>>(iter_bits);
108                if let (Some(&start_bits), Some(&end_bits)) = (obj.get("start"), obj.get("end")) {
109                    if is_number(start_bits) && is_number(end_bits) {
110                        let start = unbox_number(start_bits) as i64;
111                        let end = unbox_number(end_bits) as i64;
112                        let count = end - start;
113                        if count <= 0 || idx >= count {
114                            TAG_NULL
115                        } else {
116                            box_number((start + idx) as f64)
117                        }
118                    } else {
119                        TAG_NULL
120                    }
121                } else {
122                    TAG_NULL
123                }
124            }
125            Some(HK_RANGE) => {
126                let range = jit_unbox::<JITRange>(iter_bits);
127                if is_number(range.start) && is_number(range.end) {
128                    let start = unbox_number(range.start) as i64;
129                    let end = unbox_number(range.end) as i64;
130                    let count = end - start;
131                    if count <= 0 || idx >= count {
132                        TAG_NULL
133                    } else {
134                        box_number((start + idx) as f64)
135                    }
136                } else {
137                    TAG_NULL
138                }
139            }
140            _ => TAG_NULL,
141        }
142    }
143}