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;
12// super::super::jit_array::JitArray removed — see jit_array.rs SURFACE
13// comment. The HK_ARRAY arms surface per ADR-006 §2.7.4 / W10
14// jit-playbook §5.
15use super::jit_kinds::*;
16use super::value_ffi::*;
17use std::collections::HashMap;
18
19// ============================================================================
20// Iterator Operations
21// ============================================================================
22
23/// Check if iterator is exhausted
24/// Stack input: [iter, idx]
25/// Returns: TAG_BOOL_TRUE if done, TAG_BOOL_FALSE otherwise
26pub extern "C" fn jit_iter_done(iter_bits: u64, idx_bits: u64) -> u64 {
27 unsafe {
28 let idx = if is_number(idx_bits) {
29 unbox_number(idx_bits) as i64
30 } else {
31 return TAG_BOOL_TRUE; // Invalid index = done
32 };
33
34 if idx < 0 {
35 return TAG_BOOL_TRUE;
36 }
37
38 let done = match heap_kind(iter_bits) {
39 Some(HK_ARRAY) => {
40 // SURFACE (W10 jit-playbook §5 / ADR-006 §2.7.4):
41 // length read decoded the deleted JitArray layout.
42 // Kinded rebuild reads `Arc<TypedArrayData>::len`.
43 todo!(
44 "phase-2c §2.7.4 / W10 jit-playbook §5: \
45 JitArray rebuild — jit_iter_done HK_ARRAY arm."
46 )
47 }
48 Some(HK_STRING) => {
49 let s = unbox_string(iter_bits);
50 idx as usize >= s.chars().count()
51 }
52 Some(HK_JIT_OBJECT) => {
53 // Check if it's a Range object with start/end fields
54 let obj = unified_unbox::<HashMap<String, u64>>(iter_bits);
55 if let (Some(&start_bits), Some(&end_bits)) = (obj.get("start"), obj.get("end")) {
56 if is_number(start_bits) && is_number(end_bits) {
57 let start = unbox_number(start_bits) as i64;
58 let end = unbox_number(end_bits) as i64;
59 let count = end - start;
60 count <= 0 || idx >= count
61 } else {
62 true
63 }
64 } else {
65 true
66 }
67 }
68 Some(HK_RANGE) => {
69 let range = unified_unbox::<JITRange>(iter_bits);
70 if is_number(range.start) && is_number(range.end) {
71 let start = unbox_number(range.start) as i64;
72 let end = unbox_number(range.end) as i64;
73 let count = end - start;
74 count <= 0 || idx >= count
75 } else {
76 true
77 }
78 }
79 _ => true, // Unknown type = done
80 };
81
82 if done { TAG_BOOL_TRUE } else { TAG_BOOL_FALSE }
83 }
84}
85
86/// Get next element from iterator
87/// Stack input: [iter, idx]
88/// Returns: Element at idx, or TAG_NULL if out of bounds
89pub extern "C" fn jit_iter_next(iter_bits: u64, idx_bits: u64) -> u64 {
90 unsafe {
91 let idx = if is_number(idx_bits) {
92 unbox_number(idx_bits) as i64
93 } else {
94 return TAG_NULL;
95 };
96
97 if idx < 0 {
98 return TAG_NULL;
99 }
100
101 match heap_kind(iter_bits) {
102 Some(HK_ARRAY) => {
103 // SURFACE (W10 jit-playbook §5 / ADR-006 §2.7.4):
104 // index read decoded the deleted JitArray layout.
105 // Kinded rebuild reads Arc<TypedArrayData> per
106 // ADR-006 §2.7.6/Q8.
107 todo!(
108 "phase-2c §2.7.4 / W10 jit-playbook §5: \
109 JitArray rebuild — jit_iter_next HK_ARRAY arm."
110 )
111 }
112 Some(HK_STRING) => {
113 let s = unbox_string(iter_bits);
114 if let Some(ch) = s.chars().nth(idx as usize) {
115 box_string(ch.to_string())
116 } else {
117 TAG_NULL
118 }
119 }
120 Some(HK_JIT_OBJECT) => {
121 let obj = unified_unbox::<HashMap<String, u64>>(iter_bits);
122 if let (Some(&start_bits), Some(&end_bits)) = (obj.get("start"), obj.get("end")) {
123 if is_number(start_bits) && is_number(end_bits) {
124 let start = unbox_number(start_bits) as i64;
125 let end = unbox_number(end_bits) as i64;
126 let count = end - start;
127 if count <= 0 || idx >= count {
128 TAG_NULL
129 } else {
130 box_number((start + idx) as f64)
131 }
132 } else {
133 TAG_NULL
134 }
135 } else {
136 TAG_NULL
137 }
138 }
139 Some(HK_RANGE) => {
140 let range = unified_unbox::<JITRange>(iter_bits);
141 if is_number(range.start) && is_number(range.end) {
142 let start = unbox_number(range.start) as i64;
143 let end = unbox_number(range.end) as i64;
144 let count = end - start;
145 if count <= 0 || idx >= count {
146 TAG_NULL
147 } else {
148 box_number((start + idx) as f64)
149 }
150 } else {
151 TAG_NULL
152 }
153 }
154 _ => TAG_NULL,
155 }
156 }
157}