1use crate::context::{JITClosure, JITContext};
16use crate::ffi::object::conversion::{jit_bits_to_nanboxed_with_ctx, nanboxed_to_jit_bits};
17use crate::jit_array::JitArray;
18use crate::nan_boxing::*;
19use shape_runtime::module_exports::RawCallableInvoker;
20use shape_value::ValueWord;
21use std::ffi::c_void;
22use std::sync::Arc;
23
24pub extern "C" fn jit_call_function(
27 ctx: *mut JITContext,
28 function_id: u16,
29 _args: *const u64, _arg_count: usize,
31) -> u64 {
32 unsafe {
33 if ctx.is_null() {
34 return TAG_NULL;
35 }
36 let ctx_ref = &mut *ctx;
37
38 if ctx_ref.function_table.is_null() || (function_id as usize) >= ctx_ref.function_table_len
40 {
41 return TAG_NULL;
42 }
43
44 let fn_ptr = *ctx_ref.function_table.add(function_id as usize);
46
47 let _result_code = fn_ptr(ctx);
50
51 if ctx_ref.stack_ptr > 0 {
53 ctx_ref.stack_ptr -= 1;
54 ctx_ref.stack[ctx_ref.stack_ptr]
55 } else {
56 TAG_NULL
57 }
58 }
59}
60
61pub extern "C" fn jit_call_value(ctx: *mut JITContext) -> u64 {
65 unsafe {
66 if ctx.is_null() {
67 return TAG_NULL;
68 }
69 let ctx_ref = &mut *ctx;
70
71 if ctx_ref.stack_ptr == 0 {
73 return TAG_NULL;
74 }
75 ctx_ref.stack_ptr -= 1;
76 let arg_count_bits = ctx_ref.stack[ctx_ref.stack_ptr];
77 let arg_count = if is_number(arg_count_bits) {
78 unbox_number(arg_count_bits) as usize
79 } else {
80 return TAG_NULL;
81 };
82
83 let mut args = Vec::with_capacity(arg_count);
85 for _ in 0..arg_count {
86 if ctx_ref.stack_ptr == 0 {
87 return TAG_NULL;
88 }
89 ctx_ref.stack_ptr -= 1;
90 args.push(ctx_ref.stack[ctx_ref.stack_ptr]);
91 }
92 args.reverse();
93
94 if ctx_ref.stack_ptr == 0 {
96 return TAG_NULL;
97 }
98 ctx_ref.stack_ptr -= 1;
99 let callee_bits = ctx_ref.stack[ctx_ref.stack_ptr];
100
101 if is_inline_function(callee_bits) {
102 let function_id = unbox_function_id(callee_bits);
104
105 if ctx_ref.function_table.is_null()
106 || (function_id as usize) >= ctx_ref.function_table_len
107 {
108 return TAG_NULL;
109 }
110
111 for &arg in &args {
113 ctx_ref.stack[ctx_ref.stack_ptr] = arg;
114 ctx_ref.stack_ptr += 1;
115 }
116
117 let fn_ptr = *ctx_ref.function_table.add(function_id as usize);
118 let _result_code = fn_ptr(ctx);
119
120 if ctx_ref.stack_ptr > 0 {
122 ctx_ref.stack_ptr -= 1;
123 ctx_ref.stack[ctx_ref.stack_ptr]
124 } else {
125 TAG_NULL
126 }
127 } else if is_heap_kind(callee_bits, HK_CLOSURE) {
128 let closure = jit_unbox::<JITClosure>(callee_bits);
130 let function_id = closure.function_id;
131
132 if ctx_ref.function_table.is_null()
133 || (function_id as usize) >= ctx_ref.function_table_len
134 {
135 return TAG_NULL;
136 }
137
138 for i in 0..closure.captures_count as usize {
140 ctx_ref.stack[ctx_ref.stack_ptr] = *closure.captures_ptr.add(i);
141 ctx_ref.stack_ptr += 1;
142 }
143 for &arg in &args {
144 ctx_ref.stack[ctx_ref.stack_ptr] = arg;
145 ctx_ref.stack_ptr += 1;
146 }
147
148 let fn_ptr = *ctx_ref.function_table.add(function_id as usize);
149 let _result_code = fn_ptr(ctx);
150
151 if ctx_ref.stack_ptr > 0 {
153 ctx_ref.stack_ptr -= 1;
154 ctx_ref.stack[ctx_ref.stack_ptr]
155 } else {
156 TAG_NULL
157 }
158 } else {
159 TAG_NULL
160 }
161 }
162}
163
164pub extern "C" fn jit_control_fold(ctx: *mut JITContext) -> u64 {
167 unsafe {
168 if ctx.is_null() {
169 return TAG_NULL;
170 }
171 let ctx_ref = &mut *ctx;
172
173 if ctx_ref.stack_ptr == 0 {
175 return TAG_NULL;
176 }
177 ctx_ref.stack_ptr -= 1;
178
179 if ctx_ref.stack_ptr == 0 {
181 return TAG_NULL;
182 }
183 ctx_ref.stack_ptr -= 1;
184 let initial = ctx_ref.stack[ctx_ref.stack_ptr];
185
186 if ctx_ref.stack_ptr == 0 {
188 return TAG_NULL;
189 }
190 ctx_ref.stack_ptr -= 1;
191 let callback = ctx_ref.stack[ctx_ref.stack_ptr];
192
193 if ctx_ref.stack_ptr == 0 {
195 return TAG_NULL;
196 }
197 ctx_ref.stack_ptr -= 1;
198 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
199
200 if !is_heap_kind(array_bits, HK_ARRAY) {
201 return TAG_NULL;
202 }
203
204 let elements = jit_unbox::<JitArray>(array_bits);
205
206 let mut accumulator = initial;
207 for (index, &value) in elements.iter().enumerate() {
208 ctx_ref.stack[ctx_ref.stack_ptr] = callback;
210 ctx_ref.stack_ptr += 1;
211 ctx_ref.stack[ctx_ref.stack_ptr] = accumulator;
212 ctx_ref.stack_ptr += 1;
213 ctx_ref.stack[ctx_ref.stack_ptr] = value;
214 ctx_ref.stack_ptr += 1;
215 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
216 ctx_ref.stack_ptr += 1;
217 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(3.0); ctx_ref.stack_ptr += 1;
219
220 accumulator = jit_call_value(ctx);
221 }
222
223 accumulator
224 }
225}
226
227pub extern "C" fn jit_control_reduce(ctx: *mut JITContext) -> u64 {
230 jit_control_fold(ctx)
232}
233
234pub extern "C" fn jit_control_map(ctx: *mut JITContext) -> u64 {
237 unsafe {
238 if ctx.is_null() {
239 return TAG_NULL;
240 }
241 let ctx_ref = &mut *ctx;
242
243 if ctx_ref.stack_ptr == 0 {
245 return TAG_NULL;
246 }
247 ctx_ref.stack_ptr -= 1;
248
249 if ctx_ref.stack_ptr == 0 {
251 return TAG_NULL;
252 }
253 ctx_ref.stack_ptr -= 1;
254 let callback = ctx_ref.stack[ctx_ref.stack_ptr];
255
256 if ctx_ref.stack_ptr == 0 {
258 return TAG_NULL;
259 }
260 ctx_ref.stack_ptr -= 1;
261 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
262
263 if !is_heap_kind(array_bits, HK_ARRAY) {
264 return TAG_NULL;
265 }
266
267 let elements = jit_unbox::<JitArray>(array_bits);
268
269 let mut results = Vec::with_capacity(elements.len());
270 for (index, &value) in elements.iter().enumerate() {
271 ctx_ref.stack[ctx_ref.stack_ptr] = callback;
273 ctx_ref.stack_ptr += 1;
274 ctx_ref.stack[ctx_ref.stack_ptr] = value;
275 ctx_ref.stack_ptr += 1;
276 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
277 ctx_ref.stack_ptr += 1;
278 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
280
281 let result = jit_call_value(ctx);
282 results.push(result);
283 }
284
285 for &r in &results {
287 crate::ffi::gc::jit_write_barrier(0, r);
288 }
289 jit_box(HK_ARRAY, JitArray::from_vec(results))
290 }
291}
292
293pub extern "C" fn jit_control_filter(ctx: *mut JITContext) -> u64 {
296 unsafe {
297 if ctx.is_null() {
298 return TAG_NULL;
299 }
300 let ctx_ref = &mut *ctx;
301
302 if ctx_ref.stack_ptr == 0 {
304 return TAG_NULL;
305 }
306 ctx_ref.stack_ptr -= 1;
307
308 if ctx_ref.stack_ptr == 0 {
310 return TAG_NULL;
311 }
312 ctx_ref.stack_ptr -= 1;
313 let predicate = ctx_ref.stack[ctx_ref.stack_ptr];
314
315 if ctx_ref.stack_ptr == 0 {
317 return TAG_NULL;
318 }
319 ctx_ref.stack_ptr -= 1;
320 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
321
322 if !is_heap_kind(array_bits, HK_ARRAY) {
323 return TAG_NULL;
324 }
325
326 let elements = jit_unbox::<JitArray>(array_bits);
327
328 let mut results = Vec::new();
329 for (index, &value) in elements.iter().enumerate() {
330 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
332 ctx_ref.stack_ptr += 1;
333 ctx_ref.stack[ctx_ref.stack_ptr] = value;
334 ctx_ref.stack_ptr += 1;
335 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
336 ctx_ref.stack_ptr += 1;
337 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
339
340 let result = jit_call_value(ctx);
341 if result == TAG_BOOL_TRUE {
342 results.push(value);
343 }
344 }
345
346 jit_box(HK_ARRAY, JitArray::from_vec(results))
347 }
348}
349
350pub extern "C" fn jit_control_foreach(ctx: *mut JITContext, _count: usize) -> u64 {
353 unsafe {
354 if ctx.is_null() {
355 return TAG_NULL;
356 }
357 let ctx_ref = &mut *ctx;
358
359 if ctx_ref.stack_ptr == 0 {
361 return TAG_NULL;
362 }
363 ctx_ref.stack_ptr -= 1;
364 let callback = ctx_ref.stack[ctx_ref.stack_ptr];
365
366 if ctx_ref.stack_ptr == 0 {
368 return TAG_NULL;
369 }
370 ctx_ref.stack_ptr -= 1;
371 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
372
373 if !is_heap_kind(array_bits, HK_ARRAY) {
374 return TAG_NULL;
375 }
376
377 let elements = jit_unbox::<JitArray>(array_bits);
378
379 for (index, &value) in elements.iter().enumerate() {
380 ctx_ref.stack[ctx_ref.stack_ptr] = callback;
382 ctx_ref.stack_ptr += 1;
383 ctx_ref.stack[ctx_ref.stack_ptr] = value;
384 ctx_ref.stack_ptr += 1;
385 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
386 ctx_ref.stack_ptr += 1;
387 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
389
390 let _result = jit_call_value(ctx);
391 }
392
393 TAG_NULL }
395}
396
397pub extern "C" fn jit_control_find(ctx: *mut JITContext) -> u64 {
400 unsafe {
401 if ctx.is_null() {
402 return TAG_NULL;
403 }
404 let ctx_ref = &mut *ctx;
405
406 if ctx_ref.stack_ptr == 0 {
408 return TAG_NULL;
409 }
410 ctx_ref.stack_ptr -= 1;
411
412 if ctx_ref.stack_ptr == 0 {
414 return TAG_NULL;
415 }
416 ctx_ref.stack_ptr -= 1;
417 let predicate = ctx_ref.stack[ctx_ref.stack_ptr];
418
419 if ctx_ref.stack_ptr == 0 {
421 return TAG_NULL;
422 }
423 ctx_ref.stack_ptr -= 1;
424 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
425
426 if !is_heap_kind(array_bits, HK_ARRAY) {
427 return TAG_NULL;
428 }
429
430 let elements = jit_unbox::<JitArray>(array_bits);
431
432 for (index, &value) in elements.iter().enumerate() {
433 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
435 ctx_ref.stack_ptr += 1;
436 ctx_ref.stack[ctx_ref.stack_ptr] = value;
437 ctx_ref.stack_ptr += 1;
438 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
439 ctx_ref.stack_ptr += 1;
440 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
442
443 let result = jit_call_value(ctx);
444 if result == TAG_BOOL_TRUE {
445 return value;
446 }
447 }
448
449 TAG_NULL }
451}
452
453unsafe fn jit_callable_invoker(
454 ctx: *mut c_void,
455 callable: &ValueWord,
456 args: &[ValueWord],
457) -> Result<ValueWord, String> {
458 if ctx.is_null() {
459 return Err("native callback invoker received null JIT context".to_string());
460 }
461
462 let jit_ctx = unsafe { &mut *(ctx as *mut JITContext) };
463 let base_sp = jit_ctx.stack_ptr;
464 let needed = args.len().saturating_add(2); if base_sp.saturating_add(needed) > jit_ctx.stack.len() {
466 return Err("native callback exceeded JIT stack capacity".to_string());
467 }
468
469 jit_ctx.stack[jit_ctx.stack_ptr] = nanboxed_to_jit_bits(callable);
470 jit_ctx.stack_ptr += 1;
471 for arg in args {
472 jit_ctx.stack[jit_ctx.stack_ptr] = nanboxed_to_jit_bits(arg);
473 jit_ctx.stack_ptr += 1;
474 }
475 jit_ctx.stack[jit_ctx.stack_ptr] = box_number(args.len() as f64);
476 jit_ctx.stack_ptr += 1;
477
478 let result_bits = jit_call_value(jit_ctx as *mut JITContext);
479 jit_ctx.stack_ptr = base_sp;
480 Ok(jit_bits_to_nanboxed_with_ctx(
481 result_bits,
482 jit_ctx as *const JITContext,
483 ))
484}
485
486enum ForeignInvokeMode {
491 Any,
492 NativeOnly,
493 DynamicOnly,
494}
495
496unsafe fn jit_call_foreign_impl(
497 ctx: *mut JITContext,
498 foreign_idx: u32,
499 arg_count: usize,
500 mode: ForeignInvokeMode,
501) -> u64 {
502 if ctx.is_null() {
503 return TAG_NULL;
504 }
505 let ctx_ref = unsafe { &mut *ctx };
506 if ctx_ref.foreign_bridge_ptr.is_null() {
507 return TAG_NULL;
508 }
509 if ctx_ref.stack_ptr < arg_count {
510 return TAG_NULL;
511 }
512
513 let args_start = ctx_ref.stack_ptr - arg_count;
514 let mut args = Vec::with_capacity(arg_count);
515 for idx in args_start..ctx_ref.stack_ptr {
516 args.push(jit_bits_to_nanboxed_with_ctx(
517 ctx_ref.stack[idx],
518 ctx as *const JITContext,
519 ));
520 }
521 ctx_ref.stack_ptr = args_start;
522
523 let bridge = unsafe {
524 &*(ctx_ref.foreign_bridge_ptr as *const crate::foreign_bridge::JitForeignBridgeState)
525 };
526 let raw_invoker = RawCallableInvoker {
527 ctx: ctx as *mut c_void,
528 invoke: jit_callable_invoker,
529 };
530
531 let result = match mode {
532 ForeignInvokeMode::Any => bridge.invoke(foreign_idx as usize, &args, Some(raw_invoker)),
533 ForeignInvokeMode::NativeOnly => {
534 bridge.invoke_native(foreign_idx as usize, &args, Some(raw_invoker))
535 }
536 ForeignInvokeMode::DynamicOnly => bridge.invoke_dynamic(foreign_idx as usize, &args),
537 };
538
539 match result {
540 Ok(result) => nanboxed_to_jit_bits(&result),
541 Err(err) => {
542 let err_nb = ValueWord::from_err(ValueWord::from_string(Arc::new(err)));
543 nanboxed_to_jit_bits(&err_nb)
544 }
545 }
546}
547
548pub extern "C" fn jit_call_foreign(
549 ctx: *mut JITContext,
550 foreign_idx: u32,
551 arg_count: usize,
552) -> u64 {
553 unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::Any) }
554}
555
556pub extern "C" fn jit_call_foreign_native(
557 ctx: *mut JITContext,
558 foreign_idx: u32,
559 arg_count: usize,
560) -> u64 {
561 unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::NativeOnly) }
562}
563
564pub extern "C" fn jit_call_foreign_dynamic(
565 ctx: *mut JITContext,
566 foreign_idx: u32,
567 arg_count: usize,
568) -> u64 {
569 unsafe { jit_call_foreign_impl(ctx, foreign_idx, arg_count, ForeignInvokeMode::DynamicOnly) }
570}
571
572unsafe fn jit_call_foreign_native_args_fixed<const N: usize>(
573 ctx: *mut JITContext,
574 foreign_idx: u32,
575 args: [u64; N],
576) -> u64 {
577 if ctx.is_null() {
578 return TAG_NULL;
579 }
580 let ctx_ref = unsafe { &mut *ctx };
581 if ctx_ref.foreign_bridge_ptr.is_null() {
582 return TAG_NULL;
583 }
584
585 let bridge = unsafe {
586 &*(ctx_ref.foreign_bridge_ptr as *const crate::foreign_bridge::JitForeignBridgeState)
587 };
588 let raw_invoker = RawCallableInvoker {
589 ctx: ctx as *mut c_void,
590 invoke: jit_callable_invoker,
591 };
592 let boxed_args: [ValueWord; N] = std::array::from_fn(|idx| {
593 jit_bits_to_nanboxed_with_ctx(args[idx], ctx as *const JITContext)
594 });
595
596 match bridge.invoke_native(foreign_idx as usize, &boxed_args, Some(raw_invoker)) {
597 Ok(result) => nanboxed_to_jit_bits(&result),
598 Err(err) => {
599 let err_nb = ValueWord::from_err(ValueWord::from_string(Arc::new(err)));
600 nanboxed_to_jit_bits(&err_nb)
601 }
602 }
603}
604
605macro_rules! define_jit_call_foreign_native_fixed {
606 ($name:ident, [$($arg:ident),*]) => {
607 pub extern "C" fn $name(
608 ctx: *mut JITContext,
609 foreign_idx: u32,
610 $($arg: u64),*
611 ) -> u64 {
612 unsafe { jit_call_foreign_native_args_fixed(ctx, foreign_idx, [$($arg),*]) }
613 }
614 };
615}
616
617define_jit_call_foreign_native_fixed!(jit_call_foreign_native_0, []);
618define_jit_call_foreign_native_fixed!(jit_call_foreign_native_1, [arg0]);
619define_jit_call_foreign_native_fixed!(jit_call_foreign_native_2, [arg0, arg1]);
620define_jit_call_foreign_native_fixed!(jit_call_foreign_native_3, [arg0, arg1, arg2]);
621define_jit_call_foreign_native_fixed!(jit_call_foreign_native_4, [arg0, arg1, arg2, arg3]);
622define_jit_call_foreign_native_fixed!(jit_call_foreign_native_5, [arg0, arg1, arg2, arg3, arg4]);
623define_jit_call_foreign_native_fixed!(
624 jit_call_foreign_native_6,
625 [arg0, arg1, arg2, arg3, arg4, arg5]
626);
627define_jit_call_foreign_native_fixed!(
628 jit_call_foreign_native_7,
629 [arg0, arg1, arg2, arg3, arg4, arg5, arg6]
630);
631define_jit_call_foreign_native_fixed!(
632 jit_call_foreign_native_8,
633 [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7]
634);
635
636pub unsafe extern "C" fn jit_vm_fallback_trampoline(
638 _ctx: *mut std::ffi::c_void,
639 _function_id: u32,
640 _args_ptr: *const u64,
641 _args_len: u32,
642) -> u64 {
643 TAG_NULL
644}
645
646pub extern "C" fn jit_control_find_index(ctx: *mut JITContext) -> u64 {
649 unsafe {
650 if ctx.is_null() {
651 return box_number(-1.0);
652 }
653 let ctx_ref = &mut *ctx;
654
655 if ctx_ref.stack_ptr == 0 {
657 return box_number(-1.0);
658 }
659 ctx_ref.stack_ptr -= 1;
660
661 if ctx_ref.stack_ptr == 0 {
663 return box_number(-1.0);
664 }
665 ctx_ref.stack_ptr -= 1;
666 let predicate = ctx_ref.stack[ctx_ref.stack_ptr];
667
668 if ctx_ref.stack_ptr == 0 {
670 return box_number(-1.0);
671 }
672 ctx_ref.stack_ptr -= 1;
673 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
674
675 if !is_heap_kind(array_bits, HK_ARRAY) {
676 return box_number(-1.0);
677 }
678
679 let elements = jit_unbox::<JitArray>(array_bits);
680
681 for (index, &value) in elements.iter().enumerate() {
682 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
684 ctx_ref.stack_ptr += 1;
685 ctx_ref.stack[ctx_ref.stack_ptr] = value;
686 ctx_ref.stack_ptr += 1;
687 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
688 ctx_ref.stack_ptr += 1;
689 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
691
692 let result = jit_call_value(ctx);
693 if result == TAG_BOOL_TRUE {
694 return box_number(index as f64);
695 }
696 }
697
698 box_number(-1.0) }
700}
701
702pub extern "C" fn jit_control_some(ctx: *mut JITContext) -> u64 {
705 unsafe {
706 if ctx.is_null() {
707 return TAG_BOOL_FALSE;
708 }
709 let ctx_ref = &mut *ctx;
710
711 if ctx_ref.stack_ptr == 0 {
713 return TAG_BOOL_FALSE;
714 }
715 ctx_ref.stack_ptr -= 1;
716
717 if ctx_ref.stack_ptr == 0 {
719 return TAG_BOOL_FALSE;
720 }
721 ctx_ref.stack_ptr -= 1;
722 let predicate = ctx_ref.stack[ctx_ref.stack_ptr];
723
724 if ctx_ref.stack_ptr == 0 {
726 return TAG_BOOL_FALSE;
727 }
728 ctx_ref.stack_ptr -= 1;
729 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
730
731 if !is_heap_kind(array_bits, HK_ARRAY) {
732 return TAG_BOOL_FALSE;
733 }
734
735 let elements = jit_unbox::<JitArray>(array_bits);
736
737 for (index, &value) in elements.iter().enumerate() {
738 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
740 ctx_ref.stack_ptr += 1;
741 ctx_ref.stack[ctx_ref.stack_ptr] = value;
742 ctx_ref.stack_ptr += 1;
743 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
744 ctx_ref.stack_ptr += 1;
745 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
747
748 let result = jit_call_value(ctx);
749 if result == TAG_BOOL_TRUE {
750 return TAG_BOOL_TRUE;
751 }
752 }
753
754 TAG_BOOL_FALSE
755 }
756}
757
758pub extern "C" fn jit_control_every(ctx: *mut JITContext) -> u64 {
761 unsafe {
762 if ctx.is_null() {
763 return TAG_BOOL_FALSE;
764 }
765 let ctx_ref = &mut *ctx;
766
767 if ctx_ref.stack_ptr == 0 {
769 return TAG_BOOL_FALSE;
770 }
771 ctx_ref.stack_ptr -= 1;
772
773 if ctx_ref.stack_ptr == 0 {
775 return TAG_BOOL_FALSE;
776 }
777 ctx_ref.stack_ptr -= 1;
778 let predicate = ctx_ref.stack[ctx_ref.stack_ptr];
779
780 if ctx_ref.stack_ptr == 0 {
782 return TAG_BOOL_FALSE;
783 }
784 ctx_ref.stack_ptr -= 1;
785 let array_bits = ctx_ref.stack[ctx_ref.stack_ptr];
786
787 if !is_heap_kind(array_bits, HK_ARRAY) {
788 return TAG_BOOL_FALSE;
789 }
790
791 let elements = jit_unbox::<JitArray>(array_bits);
792
793 if elements.is_empty() {
794 return TAG_BOOL_TRUE; }
796
797 for (index, &value) in elements.iter().enumerate() {
798 ctx_ref.stack[ctx_ref.stack_ptr] = predicate;
800 ctx_ref.stack_ptr += 1;
801 ctx_ref.stack[ctx_ref.stack_ptr] = value;
802 ctx_ref.stack_ptr += 1;
803 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(index as f64);
804 ctx_ref.stack_ptr += 1;
805 ctx_ref.stack[ctx_ref.stack_ptr] = box_number(2.0); ctx_ref.stack_ptr += 1;
807
808 let result = jit_call_value(ctx);
809 if result != TAG_BOOL_TRUE {
810 return TAG_BOOL_FALSE;
811 }
812 }
813
814 TAG_BOOL_TRUE
815 }
816}
817
818#[cfg(test)]
819mod tests {
820 use super::*;
821
822 #[test]
823 fn native_fixed_arity_helpers_return_null_for_null_context() {
824 assert_eq!(jit_call_foreign_native_0(std::ptr::null_mut(), 0), TAG_NULL);
825 assert_eq!(
826 jit_call_foreign_native_1(std::ptr::null_mut(), 0, TAG_NULL),
827 TAG_NULL
828 );
829 assert_eq!(
830 jit_call_foreign_native_2(std::ptr::null_mut(), 0, TAG_NULL, TAG_NULL),
831 TAG_NULL
832 );
833 assert_eq!(
834 jit_call_foreign_native_3(std::ptr::null_mut(), 0, TAG_NULL, TAG_NULL, TAG_NULL),
835 TAG_NULL
836 );
837 assert_eq!(
838 jit_call_foreign_native_4(
839 std::ptr::null_mut(),
840 0,
841 TAG_NULL,
842 TAG_NULL,
843 TAG_NULL,
844 TAG_NULL
845 ),
846 TAG_NULL
847 );
848 assert_eq!(
849 jit_call_foreign_native_5(
850 std::ptr::null_mut(),
851 0,
852 TAG_NULL,
853 TAG_NULL,
854 TAG_NULL,
855 TAG_NULL,
856 TAG_NULL
857 ),
858 TAG_NULL
859 );
860 assert_eq!(
861 jit_call_foreign_native_6(
862 std::ptr::null_mut(),
863 0,
864 TAG_NULL,
865 TAG_NULL,
866 TAG_NULL,
867 TAG_NULL,
868 TAG_NULL,
869 TAG_NULL
870 ),
871 TAG_NULL
872 );
873 assert_eq!(
874 jit_call_foreign_native_7(
875 std::ptr::null_mut(),
876 0,
877 TAG_NULL,
878 TAG_NULL,
879 TAG_NULL,
880 TAG_NULL,
881 TAG_NULL,
882 TAG_NULL,
883 TAG_NULL
884 ),
885 TAG_NULL
886 );
887 assert_eq!(
888 jit_call_foreign_native_8(
889 std::ptr::null_mut(),
890 0,
891 TAG_NULL,
892 TAG_NULL,
893 TAG_NULL,
894 TAG_NULL,
895 TAG_NULL,
896 TAG_NULL,
897 TAG_NULL,
898 TAG_NULL
899 ),
900 TAG_NULL
901 );
902 }
903}