1use crate::lcnf::*;
6use crate::native_backend::*;
7
8use super::types::{
9 AllocStrategy, AllocatorCodegen, ArrayCodegen, BigNatCodegen, ClosureCodegen, ClosureLayout,
10 ClosureRepr, ExternalObjectCodegen, LayoutCache, LayoutComputer, ObjectLayout, ObjectTag,
11 RcCodegen, RcStrategy, RcUseAnalysis, RuntimeConfig, RuntimeModuleBuilder, StringCodegen,
12 StringLayout, ThunkCodegen, TypeInfo,
13};
14
15pub(super) fn align_up(value: usize, align: usize) -> usize {
17 (value + align - 1) & !(align - 1)
18}
19pub(super) fn is_boxed_type(ty: &LcnfType) -> bool {
21 matches!(
22 ty,
23 LcnfType::Object
24 | LcnfType::Var(_)
25 | LcnfType::Fun(_, _)
26 | LcnfType::Ctor(_, _)
27 | LcnfType::LcnfString
28 )
29}
30pub(super) fn scalar_type_size(ty: &LcnfType) -> usize {
32 match ty {
33 LcnfType::Nat => 8,
34 LcnfType::Unit | LcnfType::Erased | LcnfType::Irrelevant => 0,
35 _ => 8,
36 }
37}
38#[cfg(test)]
39mod tests {
40 use super::*;
41 #[test]
42 pub(super) fn test_object_tag_roundtrip() {
43 for tag in [
44 ObjectTag::Scalar,
45 ObjectTag::Closure,
46 ObjectTag::Array,
47 ObjectTag::Struct,
48 ObjectTag::External,
49 ObjectTag::String,
50 ObjectTag::BigNat,
51 ObjectTag::Thunk,
52 ] {
53 let n = tag.to_u8();
54 let back = ObjectTag::from_u8(n).expect("back should be valid");
55 assert_eq!(tag, back);
56 }
57 assert!(ObjectTag::from_u8(255).is_none());
58 }
59 #[test]
60 pub(super) fn test_object_tag_display() {
61 assert_eq!(ObjectTag::Scalar.to_string(), "scalar");
62 assert_eq!(ObjectTag::Closure.to_string(), "closure");
63 assert_eq!(ObjectTag::Struct.to_string(), "struct");
64 }
65 #[test]
66 pub(super) fn test_ctor_layout() {
67 let layout = ObjectLayout::for_ctor(0, 2, 0);
68 assert_eq!(layout.num_obj_fields, 2);
69 assert_eq!(layout.scalar_size, 0);
70 assert!(layout.total_size >= ObjectLayout::HEADER_SIZE + 16);
71 assert_eq!(layout.alignment, 8);
72 assert_eq!(layout.obj_field_offset(0), ObjectLayout::HEADER_SIZE);
73 assert_eq!(layout.obj_field_offset(1), ObjectLayout::HEADER_SIZE + 8);
74 }
75 #[test]
76 pub(super) fn test_closure_layout() {
77 let layout = ObjectLayout::for_closure(2, 3);
78 assert_eq!(layout.tag, ObjectTag::Closure);
79 assert!(layout.total_size > ObjectLayout::HEADER_SIZE);
80 assert_eq!(layout.num_obj_fields, 3);
81 }
82 #[test]
83 pub(super) fn test_array_layout() {
84 let layout = ObjectLayout::for_array(10);
85 assert_eq!(layout.tag, ObjectTag::Array);
86 assert_eq!(layout.num_obj_fields, 10);
87 }
88 #[test]
89 pub(super) fn test_external_layout() {
90 let layout = ObjectLayout::for_external();
91 assert_eq!(layout.tag, ObjectTag::External);
92 assert_eq!(layout.num_obj_fields, 0);
93 }
94 #[test]
95 pub(super) fn test_layout_display() {
96 let layout = ObjectLayout::for_ctor(0, 2, 8);
97 let s = layout.to_string();
98 assert!(s.contains("obj_fields=2"));
99 assert!(s.contains("scalar=8"));
100 }
101 #[test]
102 pub(super) fn test_align_up() {
103 assert_eq!(align_up(0, 8), 0);
104 assert_eq!(align_up(1, 8), 8);
105 assert_eq!(align_up(8, 8), 8);
106 assert_eq!(align_up(9, 8), 16);
107 assert_eq!(align_up(16, 8), 16);
108 }
109 #[test]
110 pub(super) fn test_layout_computer_ctor() {
111 let mut computer = LayoutComputer::new();
112 let layout = computer.compute_ctor_layout("Pair", 0, &[LcnfType::Nat, LcnfType::Object]);
113 assert_eq!(layout.num_obj_fields, 1);
114 assert!(layout.scalar_size > 0);
115 }
116 #[test]
117 pub(super) fn test_layout_computer_cache() {
118 let mut computer = LayoutComputer::new();
119 let layout1 = computer.compute_ctor_layout("Nil", 0, &[]);
120 let layout2 = computer.compute_ctor_layout("Nil", 0, &[]);
121 assert_eq!(layout1, layout2);
122 }
123 #[test]
124 pub(super) fn test_layout_computer_register_type() {
125 let mut computer = LayoutComputer::new();
126 computer.register_type(TypeInfo {
127 name: "Bool".to_string(),
128 constructors: vec![
129 ("False".to_string(), 0, vec![]),
130 ("True".to_string(), 1, vec![]),
131 ],
132 is_recursive: false,
133 });
134 let layouts = computer.compute_layout("Bool");
135 assert_eq!(layouts.len(), 2);
136 }
137 #[test]
138 pub(super) fn test_rc_codegen_inc() {
139 let mut rc = RcCodegen::new(true);
140 let insts = rc.emit_rc_inc(Register::virt(5));
141 assert!(insts.len() >= 2);
142 let has_call = insts.iter().any(|i| matches!(i, NativeInst::Call { .. }));
143 assert!(has_call);
144 }
145 #[test]
146 pub(super) fn test_rc_codegen_dec() {
147 let mut rc = RcCodegen::new(true);
148 let insts = rc.emit_rc_dec(Register::virt(5));
149 assert!(insts.len() >= 2);
150 }
151 #[test]
152 pub(super) fn test_rc_codegen_is_unique() {
153 let mut rc = RcCodegen::new(true);
154 let inst = rc.emit_rc_is_unique(Register::virt(5));
155 assert!(matches!(inst, NativeInst::Call { .. }));
156 }
157 #[test]
158 pub(super) fn test_rc_codegen_disabled() {
159 let mut rc = RcCodegen::new(false);
160 let insts = rc.emit_rc_inc(Register::virt(0));
161 assert!(insts.len() == 1);
162 assert!(matches!(insts[0], NativeInst::Comment(_)));
163 }
164 #[test]
165 pub(super) fn test_rc_codegen_inc_n() {
166 let mut rc = RcCodegen::new(true);
167 let insts = rc.emit_rc_inc_n(Register::virt(5), 3);
168 assert!(!insts.is_empty());
169 }
170 #[test]
171 pub(super) fn test_allocator_codegen_system() {
172 let mut alloc = AllocatorCodegen::new(AllocStrategy::System);
173 let insts = alloc.emit_alloc(64, 8);
174 assert!(insts.len() >= 2);
175 }
176 #[test]
177 pub(super) fn test_allocator_codegen_free() {
178 let mut alloc = AllocatorCodegen::new(AllocStrategy::System);
179 let insts = alloc.emit_free(Register::virt(5));
180 assert!(insts.len() >= 2);
181 }
182 #[test]
183 pub(super) fn test_allocator_codegen_bump_no_free() {
184 let mut alloc = AllocatorCodegen::new(AllocStrategy::Bump);
185 let insts = alloc.emit_free(Register::virt(5));
186 assert!(insts.len() == 1);
187 assert!(matches!(insts[0], NativeInst::Comment(_)));
188 }
189 #[test]
190 pub(super) fn test_allocator_alloc_ctor() {
191 let mut alloc = AllocatorCodegen::new(AllocStrategy::LeanRuntime);
192 let insts = alloc.emit_alloc_ctor(0, 2, 0);
193 assert!(!insts.is_empty());
194 }
195 #[test]
196 pub(super) fn test_allocator_alloc_closure() {
197 let mut alloc = AllocatorCodegen::new(AllocStrategy::LeanRuntime);
198 let insts = alloc.emit_alloc_closure("my_func", 2, 1);
199 assert!(!insts.is_empty());
200 }
201 #[test]
202 pub(super) fn test_closure_layout_new() {
203 let layout = ClosureLayout::new(2, 3);
204 assert_eq!(layout.arity, 2);
205 assert_eq!(layout.num_captured, 3);
206 assert!(layout.env_offset > ObjectLayout::HEADER_SIZE);
207 assert_eq!(layout.env_size, 24);
208 }
209 #[test]
210 pub(super) fn test_closure_layout_offsets() {
211 let layout = ClosureLayout::new(1, 2);
212 let off0 = layout.captured_var_offset(0);
213 let off1 = layout.captured_var_offset(1);
214 assert_eq!(off1 - off0, 8);
215 }
216 #[test]
217 pub(super) fn test_closure_layout_display() {
218 let layout = ClosureLayout::new(2, 3);
219 let s = layout.to_string();
220 assert!(s.contains("arity=2"));
221 assert!(s.contains("captured=3"));
222 }
223 #[test]
224 pub(super) fn test_closure_codegen_create() {
225 let mut codegen = ClosureCodegen::new();
226 let insts = codegen.emit_closure_create("add", 2, &[Register::virt(0), Register::virt(1)]);
227 assert!(!insts.is_empty());
228 let call_count = insts
229 .iter()
230 .filter(|i| matches!(i, NativeInst::Call { .. }))
231 .count();
232 assert!(call_count >= 3);
233 }
234 #[test]
235 pub(super) fn test_closure_codegen_apply() {
236 let mut codegen = ClosureCodegen::new();
237 let insts = codegen.emit_closure_apply(Register::virt(0), &[Register::virt(1)]);
238 assert!(!insts.is_empty());
239 }
240 #[test]
241 pub(super) fn test_closure_codegen_partial_apply() {
242 let mut codegen = ClosureCodegen::new();
243 let insts = codegen.emit_partial_apply(Register::virt(0), &[Register::virt(1)]);
244 assert!(!insts.is_empty());
245 }
246 #[test]
247 pub(super) fn test_closure_codegen_partial_apply_empty() {
248 let mut codegen = ClosureCodegen::new();
249 let insts = codegen.emit_partial_apply(Register::virt(0), &[]);
250 assert!(insts.len() == 1);
251 assert!(matches!(insts[0], NativeInst::Comment(_)));
252 }
253 #[test]
254 pub(super) fn test_runtime_config_default() {
255 let cfg = RuntimeConfig::default();
256 assert_eq!(cfg.rc_strategy, RcStrategy::Standard);
257 assert_eq!(cfg.alloc_strategy, AllocStrategy::LeanRuntime);
258 assert_eq!(cfg.closure_repr, ClosureRepr::Standard);
259 assert!(!cfg.debug_checks);
260 }
261 #[test]
262 pub(super) fn test_runtime_config_display() {
263 let cfg = RuntimeConfig::default();
264 let s = cfg.to_string();
265 assert!(s.contains("Standard"));
266 assert!(s.contains("LeanRuntime"));
267 }
268 #[test]
269 pub(super) fn test_is_boxed_type() {
270 assert!(is_boxed_type(&LcnfType::Object));
271 assert!(is_boxed_type(&LcnfType::LcnfString));
272 assert!(is_boxed_type(&LcnfType::Ctor("List".into(), vec![])));
273 assert!(!is_boxed_type(&LcnfType::Nat));
274 assert!(!is_boxed_type(&LcnfType::Unit));
275 }
276 #[test]
277 pub(super) fn test_scalar_type_size() {
278 assert_eq!(scalar_type_size(&LcnfType::Nat), 8);
279 assert_eq!(scalar_type_size(&LcnfType::Unit), 0);
280 assert_eq!(scalar_type_size(&LcnfType::Erased), 0);
281 }
282 #[test]
283 pub(super) fn test_conditional_reset() {
284 let mut rc = RcCodegen::new(true);
285 let insts = rc.emit_conditional_reset(Register::virt(0), 2, 0);
286 assert!(insts.len() >= 3);
287 }
288}
289#[cfg(test)]
290mod runtime_extended_tests {
291 use super::*;
292 pub(super) fn vid(n: u64) -> LcnfVarId {
293 LcnfVarId(n)
294 }
295 pub(super) fn mk_fun_decl(name: &str, body: LcnfExpr) -> LcnfFunDecl {
296 LcnfFunDecl {
297 name: name.to_string(),
298 original_name: None,
299 params: vec![],
300 ret_type: LcnfType::Nat,
301 body,
302 is_recursive: false,
303 is_lifted: false,
304 inline_cost: 1,
305 }
306 }
307 pub(super) fn mk_module(decls: Vec<LcnfFunDecl>) -> LcnfModule {
308 LcnfModule {
309 fun_decls: decls,
310 extern_decls: vec![],
311 name: "test".to_string(),
312 metadata: LcnfModuleMetadata::default(),
313 }
314 }
315 #[test]
316 pub(super) fn test_string_layout_standard() {
317 let layout = StringLayout::standard();
318 assert!(!layout.is_sso);
319 assert_eq!(layout.len_offset, ObjectLayout::HEADER_SIZE);
320 assert!(layout.data_offset > layout.len_offset);
321 }
322 #[test]
323 pub(super) fn test_string_layout_sso() {
324 let layout = StringLayout::sso(15);
325 assert!(layout.is_sso);
326 assert_eq!(layout.sso_max_len, 15);
327 assert!(layout.sso_total_size > 0);
328 }
329 #[test]
330 pub(super) fn test_string_layout_alloc_size_standard() {
331 let layout = StringLayout::standard();
332 let size = layout.alloc_size(100);
333 assert!(size >= layout.data_offset + 100);
334 }
335 #[test]
336 pub(super) fn test_string_layout_alloc_size_sso_short() {
337 let layout = StringLayout::sso(15);
338 let size = layout.alloc_size(10);
339 assert_eq!(size, layout.sso_total_size);
340 }
341 #[test]
342 pub(super) fn test_string_layout_alloc_size_sso_long() {
343 let layout = StringLayout::sso(15);
344 let size_long = layout.alloc_size(100);
345 assert!(size_long > layout.sso_total_size);
346 }
347 #[test]
348 pub(super) fn test_string_layout_display() {
349 let layout = StringLayout::sso(8);
350 let s = layout.to_string();
351 assert!(s.contains("sso=true"));
352 assert!(s.contains("max_len=8"));
353 }
354 #[test]
355 pub(super) fn test_array_codegen_alloc() {
356 let mut codegen = ArrayCodegen::default();
357 let insts = codegen.emit_alloc_array(16);
358 assert!(!insts.is_empty());
359 assert!(insts.iter().any(|i| matches!(i, NativeInst::Call { .. })));
360 }
361 #[test]
362 pub(super) fn test_array_codegen_get() {
363 let mut codegen = ArrayCodegen::default();
364 let insts = codegen.emit_array_get(Register::virt(0), Register::virt(1));
365 assert!(!insts.is_empty());
366 }
367 #[test]
368 pub(super) fn test_array_codegen_set() {
369 let mut codegen = ArrayCodegen::default();
370 let insts = codegen.emit_array_set(Register::virt(0), Register::virt(1), Register::virt(2));
371 assert!(!insts.is_empty());
372 }
373 #[test]
374 pub(super) fn test_array_codegen_push() {
375 let mut codegen = ArrayCodegen::default();
376 let insts = codegen.emit_array_push(Register::virt(0), Register::virt(1));
377 assert!(!insts.is_empty());
378 }
379 #[test]
380 pub(super) fn test_array_codegen_size() {
381 let mut codegen = ArrayCodegen::default();
382 let insts = codegen.emit_array_size(Register::virt(0));
383 assert!(!insts.is_empty());
384 }
385 #[test]
386 pub(super) fn test_string_codegen_lit() {
387 let mut codegen = StringCodegen::default();
388 let insts = codegen.emit_string_lit("hello");
389 assert!(!insts.is_empty());
390 }
391 #[test]
392 pub(super) fn test_string_codegen_append() {
393 let mut codegen = StringCodegen::default();
394 let insts = codegen.emit_string_append(Register::virt(0), Register::virt(1));
395 assert!(!insts.is_empty());
396 }
397 #[test]
398 pub(super) fn test_string_codegen_length() {
399 let mut codegen = StringCodegen::default();
400 let insts = codegen.emit_string_length(Register::virt(0));
401 assert!(!insts.is_empty());
402 assert!(insts.iter().any(|i| matches!(i, NativeInst::Load { .. })));
403 }
404 #[test]
405 pub(super) fn test_string_codegen_eq() {
406 let mut codegen = StringCodegen::default();
407 let insts = codegen.emit_string_eq(Register::virt(0), Register::virt(1));
408 assert!(!insts.is_empty());
409 }
410 #[test]
411 pub(super) fn test_thunk_codegen_alloc() {
412 let mut codegen = ThunkCodegen::new();
413 let insts = codegen.emit_alloc_thunk("my_lazy_fn");
414 assert!(!insts.is_empty());
415 }
416 #[test]
417 pub(super) fn test_thunk_codegen_force() {
418 let mut codegen = ThunkCodegen::new();
419 let insts = codegen.emit_force_thunk(Register::virt(5));
420 assert!(!insts.is_empty());
421 }
422 #[test]
423 pub(super) fn test_thunk_codegen_is_evaluated() {
424 let mut codegen = ThunkCodegen::new();
425 let insts = codegen.emit_is_evaluated(Register::virt(3));
426 assert!(!insts.is_empty());
427 }
428 #[test]
429 pub(super) fn test_bignat_codegen_add() {
430 let mut codegen = BigNatCodegen::new();
431 let insts = codegen.emit_add(Register::virt(0), Register::virt(1));
432 assert!(!insts.is_empty());
433 }
434 #[test]
435 pub(super) fn test_bignat_codegen_mul() {
436 let mut codegen = BigNatCodegen::new();
437 let insts = codegen.emit_mul(Register::virt(0), Register::virt(1));
438 assert!(!insts.is_empty());
439 }
440 #[test]
441 pub(super) fn test_bignat_codegen_sub() {
442 let mut codegen = BigNatCodegen::new();
443 let insts = codegen.emit_sub(Register::virt(0), Register::virt(1));
444 assert!(!insts.is_empty());
445 }
446 #[test]
447 pub(super) fn test_bignat_codegen_div() {
448 let mut codegen = BigNatCodegen::new();
449 let insts = codegen.emit_div(Register::virt(0), Register::virt(1));
450 assert!(!insts.is_empty());
451 }
452 #[test]
453 pub(super) fn test_bignat_codegen_cmp() {
454 let mut codegen = BigNatCodegen::new();
455 let insts = codegen.emit_cmp(Register::virt(0), Register::virt(1));
456 assert!(!insts.is_empty());
457 }
458 #[test]
459 pub(super) fn test_bignat_codegen_of_u64() {
460 let mut codegen = BigNatCodegen::new();
461 let insts = codegen.emit_of_u64(42);
462 assert!(!insts.is_empty());
463 }
464 #[test]
465 pub(super) fn test_external_codegen_alloc() {
466 let mut codegen = ExternalObjectCodegen::new();
467 let insts = codegen.emit_alloc_external(Register::virt(0), "my_finalizer");
468 assert!(!insts.is_empty());
469 }
470 #[test]
471 pub(super) fn test_external_codegen_get_data() {
472 let mut codegen = ExternalObjectCodegen::new();
473 let insts = codegen.emit_get_external_data(Register::virt(0));
474 assert!(!insts.is_empty());
475 assert!(insts.iter().any(|i| matches!(i, NativeInst::Load { .. })));
476 }
477 #[test]
478 pub(super) fn test_runtime_module_builder_new() {
479 let config = RuntimeConfig::default();
480 let builder = RuntimeModuleBuilder::new(config);
481 assert_eq!(builder.instruction_count(), 0);
482 }
483 #[test]
484 pub(super) fn test_runtime_module_builder_emit_ctor() {
485 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
486 builder.emit_ctor(0, 2, 0);
487 assert!(builder.instruction_count() > 0);
488 }
489 #[test]
490 pub(super) fn test_runtime_module_builder_emit_closure() {
491 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
492 let env = vec![Register::virt(0), Register::virt(1)];
493 builder.emit_closure("my_fn", 2, &env);
494 assert!(builder.call_count() > 0);
495 }
496 #[test]
497 pub(super) fn test_runtime_module_builder_emit_inc_dec() {
498 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
499 builder.emit_inc(Register::virt(5));
500 builder.emit_dec(Register::virt(5));
501 assert!(builder.instruction_count() > 0);
502 }
503 #[test]
504 pub(super) fn test_runtime_module_builder_emit_nat_add() {
505 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
506 builder.emit_nat_add(Register::virt(0), Register::virt(1));
507 assert!(!builder.instructions().is_empty());
508 }
509 #[test]
510 pub(super) fn test_runtime_module_builder_emit_str_append() {
511 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
512 builder.emit_str_append(Register::virt(0), Register::virt(1));
513 assert!(!builder.instructions().is_empty());
514 }
515 #[test]
516 pub(super) fn test_runtime_module_builder_comment_count() {
517 let mut builder = RuntimeModuleBuilder::new(RuntimeConfig::default());
518 builder.emit_ctor(0, 1, 0);
519 assert!(builder.comment_count() > 0);
520 }
521 #[test]
522 pub(super) fn test_rc_use_analysis_new() {
523 let analysis = RcUseAnalysis::new();
524 assert_eq!(analysis.use_count(vid(0)), 0);
525 }
526 #[test]
527 pub(super) fn test_rc_use_analysis_single_use() {
528 let mut analysis = RcUseAnalysis::new();
529 let module = mk_module(vec![mk_fun_decl(
530 "f",
531 LcnfExpr::Return(LcnfArg::Var(vid(5))),
532 )]);
533 analysis.analyze_module(&module);
534 assert_eq!(analysis.use_count(vid(5)), 1);
535 }
536 #[test]
537 pub(super) fn test_rc_use_analysis_multi_use() {
538 let mut analysis = RcUseAnalysis::new();
539 let module = mk_module(vec![mk_fun_decl(
540 "f",
541 LcnfExpr::TailCall(
542 LcnfArg::Var(vid(1)),
543 vec![LcnfArg::Var(vid(1)), LcnfArg::Var(vid(2))],
544 ),
545 )]);
546 analysis.analyze_module(&module);
547 assert_eq!(analysis.use_count(vid(1)), 2);
548 assert_eq!(analysis.use_count(vid(2)), 1);
549 }
550 #[test]
551 pub(super) fn test_rc_use_analysis_multi_use_vars() {
552 let mut analysis = RcUseAnalysis::new();
553 analysis.analyze_module(&mk_module(vec![mk_fun_decl(
554 "f",
555 LcnfExpr::TailCall(
556 LcnfArg::Var(vid(3)),
557 vec![LcnfArg::Var(vid(3)), LcnfArg::Var(vid(3))],
558 ),
559 )]));
560 let multi = analysis.multi_use_vars();
561 assert!(multi.iter().any(|(v, _)| *v == vid(3)));
562 }
563 #[test]
564 pub(super) fn test_layout_cache_new() {
565 let cache = LayoutCache::new();
566 assert_eq!(cache.ctor_count(), 0);
567 assert_eq!(cache.closure_count(), 0);
568 }
569 #[test]
570 pub(super) fn test_layout_cache_get_ctor() {
571 let mut cache = LayoutCache::new();
572 let layout = cache.get_ctor("Pair", 0, 2, 0);
573 assert_eq!(layout.num_obj_fields, 2);
574 assert_eq!(cache.ctor_count(), 1);
575 let layout2 = cache.get_ctor("Pair", 0, 2, 0);
576 assert_eq!(layout2.num_obj_fields, 2);
577 assert_eq!(cache.ctor_count(), 1);
578 }
579 #[test]
580 pub(super) fn test_layout_cache_get_closure() {
581 let mut cache = LayoutCache::new();
582 let layout = cache.get_closure(2, 3);
583 assert_eq!(layout.arity, 2);
584 assert_eq!(layout.num_captured, 3);
585 assert_eq!(cache.closure_count(), 1);
586 let layout2 = cache.get_closure(2, 3);
587 assert_eq!(layout2.arity, 2);
588 assert_eq!(cache.closure_count(), 1);
589 }
590 #[test]
591 pub(super) fn test_layout_cache_clear() {
592 let mut cache = LayoutCache::new();
593 cache.get_ctor("Nil", 0, 0, 0);
594 cache.get_closure(1, 1);
595 cache.clear();
596 assert_eq!(cache.ctor_count(), 0);
597 assert_eq!(cache.closure_count(), 0);
598 }
599 #[test]
600 pub(super) fn test_object_tag_invalid_from_u8() {
601 assert!(ObjectTag::from_u8(8).is_none());
602 assert!(ObjectTag::from_u8(100).is_none());
603 }
604 #[test]
605 pub(super) fn test_object_tag_all_values() {
606 let tags: Vec<ObjectTag> = (0u8..8).filter_map(ObjectTag::from_u8).collect();
607 assert_eq!(tags.len(), 8);
608 }
609 #[test]
610 pub(super) fn test_object_layout_scalar_offset() {
611 let layout = ObjectLayout::for_ctor(0, 3, 16);
612 let scalar_off = layout.scalar_offset();
613 assert_eq!(scalar_off, ObjectLayout::HEADER_SIZE + 3 * 8);
614 }
615 #[test]
616 pub(super) fn test_object_layout_for_external_size() {
617 let layout = ObjectLayout::for_external();
618 assert!(layout.total_size >= ObjectLayout::HEADER_SIZE + 24);
619 }
620 #[test]
621 pub(super) fn test_closure_codegen_apply_5_args() {
622 let mut codegen = ClosureCodegen::new();
623 let args: Vec<Register> = (1..=5).map(Register::virt).collect();
624 let insts = codegen.emit_closure_apply(Register::virt(0), &args);
625 assert!(!insts.is_empty());
626 let has_apply_n = insts.iter().any(|i| {
627 if let NativeInst::Call {
628 func: NativeValue::FRef(name),
629 ..
630 } = i
631 {
632 name.contains("lean_apply_n")
633 } else {
634 false
635 }
636 });
637 assert!(has_apply_n);
638 }
639 #[test]
640 pub(super) fn test_alloc_strategy_pool() {
641 let mut alloc = AllocatorCodegen::new(AllocStrategy::Pool);
642 let insts = alloc.emit_free(Register::virt(0));
643 assert!(insts.iter().any(|i| matches!(i, NativeInst::Call { .. })));
644 }
645 #[test]
646 pub(super) fn test_alloc_strategy_bump_alloc() {
647 let mut alloc = AllocatorCodegen::new(AllocStrategy::Bump);
648 let insts = alloc.emit_alloc(64, 8);
649 assert!(insts.iter().any(|i| {
650 if let NativeInst::Call {
651 func: NativeValue::FRef(name),
652 ..
653 } = i
654 {
655 name == "bump_alloc"
656 } else {
657 false
658 }
659 }));
660 }
661}