tidepool_codegen/
alloc.rs1use cranelift_codegen::ir::{self, types, InstBuilder, Value, MemFlags};
2use cranelift_frontend::FunctionBuilder;
3
4const VMCTX_ALLOC_PTR_OFFSET: i32 = 0;
6const VMCTX_ALLOC_LIMIT_OFFSET: i32 = 8;
8const VMCTX_GC_TRIGGER_OFFSET: i32 = 16;
10
11pub fn emit_alloc_fast_path(
26 builder: &mut FunctionBuilder,
27 vmctx_val: Value,
28 size: u64,
29 gc_trigger_sig: ir::SigRef,
30) -> Value {
31 let aligned_size = (size + 7) & !7;
32 let flags = MemFlags::trusted();
42
43 let alloc_ptr = builder.ins().load(types::I64, flags, vmctx_val, VMCTX_ALLOC_PTR_OFFSET);
45
46 let size_val = builder.ins().iconst(types::I64, aligned_size as i64);
48 let new_ptr = builder.ins().iadd(alloc_ptr, size_val);
49
50 let alloc_limit = builder.ins().load(types::I64, flags, vmctx_val, VMCTX_ALLOC_LIMIT_OFFSET);
52
53 let overflow = builder.ins().icmp(ir::condcodes::IntCC::UnsignedGreaterThan, new_ptr, alloc_limit);
55
56 let slow_block = builder.create_block();
57 let fast_store_block = builder.create_block();
58 let continue_block = builder.create_block();
59 builder.append_block_param(continue_block, types::I64); builder.ins().brif(overflow, slow_block, &[], fast_store_block, &[]);
62
63 builder.switch_to_block(fast_store_block);
65 builder.seal_block(fast_store_block);
66 builder.ins().store(flags, new_ptr, vmctx_val, VMCTX_ALLOC_PTR_OFFSET);
67 builder.ins().jump(continue_block, &[alloc_ptr]);
68
69 builder.switch_to_block(slow_block);
71 builder.seal_block(slow_block);
72
73 let gc_trigger_ptr = builder.ins().load(types::I64, flags, vmctx_val, VMCTX_GC_TRIGGER_OFFSET);
74 builder.ins().call_indirect(gc_trigger_sig, gc_trigger_ptr, &[vmctx_val]);
75
76 let post_gc_ptr = builder.ins().load(types::I64, flags, vmctx_val, VMCTX_ALLOC_PTR_OFFSET);
78 let post_gc_limit = builder.ins().load(types::I64, flags, vmctx_val, VMCTX_ALLOC_LIMIT_OFFSET);
79 let post_gc_new = builder.ins().iadd(post_gc_ptr, size_val);
80 let post_gc_overflow = builder
81 .ins()
82 .icmp(ir::condcodes::IntCC::UnsignedGreaterThan, post_gc_new, post_gc_limit);
83
84 let slow_fail_block = builder.create_block();
85 let slow_store_block = builder.create_block();
86
87 builder
88 .ins()
89 .brif(post_gc_overflow, slow_fail_block, &[], slow_store_block, &[]);
90
91 builder.switch_to_block(slow_store_block);
93 builder.seal_block(slow_store_block);
94 builder.ins().store(flags, post_gc_new, vmctx_val, VMCTX_ALLOC_PTR_OFFSET);
95 builder.ins().jump(continue_block, &[post_gc_ptr]);
96
97 builder.switch_to_block(slow_fail_block);
99 builder.seal_block(slow_fail_block);
100 builder.ins().trap(ir::TrapCode::unwrap_user(1));
102
103 builder.switch_to_block(continue_block);
105 builder.seal_block(continue_block);
106
107 builder.block_params(continue_block)[0]
108}