Skip to content

Commit 1ccf12f

Browse files
committed
feat(native): add frame-relative callable ABI
1 parent cdf8b89 commit 1ccf12f

7 files changed

Lines changed: 387 additions & 37 deletions

File tree

src/vm/aot/artifact.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use super::super::jit::JitConfig;
1212
use super::compile::CompiledProgram;
1313

1414
const MAGIC: [u8; 4] = *b"PAT\0";
15-
const VERSION: u16 = 3;
16-
const ABI_VERSION: u16 = 2;
15+
const VERSION: u16 = 4;
16+
const ABI_VERSION: u16 = 3;
1717
const FLAGS: u16 = 0;
1818

1919
#[derive(Debug)]

src/vm/aot/compile.rs

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@ use std::time::Instant;
1414
use crate::vm::native::ExecutableBuffer;
1515
#[cfg(feature = "cranelift-jit")]
1616
use crate::vm::native::{
17-
HeapIntrinsicAddrs, HeapIntrinsicRefs, OP_BUILTIN_CALL, OP_CALL, STATUS_CONTINUE, STATUS_ERROR,
18-
alloc_buffer_signature, alloc_byte_buffer_entry_address, alloc_value_buffer_entry_address,
19-
aot_call_boundary_interrupt_entry_address, array_push_entry_address, box_heap_value_signature,
20-
clear_value_slot_entry_address, clone_value_signature, clone_value_to_slot_entry_address,
21-
collection_get_signature, collection_mutation_signature, collection_set_entry_address,
22-
copy_bytes_entry_address, copy_bytes_signature, detect_native_stack_layout, entry_signature,
23-
free_buffer_signature, helper_entry_offset, helper_signature,
17+
HeapIntrinsicAddrs, HeapIntrinsicRefs, NativeFrameState, OP_BUILTIN_CALL, OP_CALL,
18+
STATUS_CONTINUE, STATUS_ERROR, alloc_buffer_signature, alloc_byte_buffer_entry_address,
19+
alloc_value_buffer_entry_address, aot_call_boundary_interrupt_entry_address,
20+
array_push_entry_address, box_heap_value_signature, clear_value_slot_entry_address,
21+
clone_value_signature, clone_value_to_slot_entry_address, collection_get_signature,
22+
collection_mutation_signature, collection_set_entry_address, copy_bytes_entry_address,
23+
copy_bytes_signature, detect_native_stack_layout, entry_signature, frame_state_entry_address,
24+
frame_state_signature, free_buffer_signature, helper_entry_offset, helper_signature,
2425
init_null_value_slot_entry_address, jump_with_status, pack_shared_signature, resolve_offsets,
25-
restore_exit_signature, restore_exit_state_entry_address,
26-
shared_array_from_buffer_entry_address, shared_bytes_from_buffer_entry_address,
27-
shared_string_from_buffer_entry_address, value_eq_entry_address, value_eq_signature,
28-
value_slot_signature, write_heap_value_to_slot_entry_address, zero_bytes_entry_address,
26+
restore_active_exit_state_entry_address, restore_exit_signature,
27+
restore_exit_state_entry_address, shared_array_from_buffer_entry_address,
28+
shared_bytes_from_buffer_entry_address, shared_string_from_buffer_entry_address,
29+
value_eq_entry_address, value_eq_signature, value_slot_signature,
30+
write_heap_value_to_slot_entry_address, zero_bytes_entry_address,
2931
};
3032
use crate::vm::{Program, Value, Vm, VmError, VmResult};
3133
#[cfg(feature = "cranelift-jit")]
@@ -219,6 +221,7 @@ struct AotDeoptHelperRefs {
219221
helper_ref: cranelift_codegen::ir::SigRef,
220222
vm_status_ref: cranelift_codegen::ir::SigRef,
221223
interrupt_ref: cranelift_codegen::ir::SigRef,
224+
frame_state_ref: cranelift_codegen::ir::SigRef,
222225
clone_value_ref: cranelift_codegen::ir::SigRef,
223226
value_eq_ref: cranelift_codegen::ir::SigRef,
224227
init_null_slot_ref: cranelift_codegen::ir::SigRef,
@@ -233,6 +236,7 @@ struct AotDeoptHelperRefs {
233236
#[derive(Clone, Copy)]
234237
struct AotDeoptHelperAddrs {
235238
aot_interrupt: usize,
239+
frame_state: usize,
236240
clone_value: usize,
237241
value_eq: usize,
238242
init_null_slot: usize,
@@ -381,6 +385,7 @@ fn compile_ssa(
381385
let sigs_started = Instant::now();
382386
let helper_sig = helper_signature(pointer_type, call_conv);
383387
let alloc_buffer_sig = alloc_buffer_signature(pointer_type, call_conv);
388+
let frame_state_sig = frame_state_signature(pointer_type, call_conv);
384389
let free_buffer_sig = free_buffer_signature(pointer_type, call_conv);
385390
let pack_shared_sig = pack_shared_signature(pointer_type, call_conv);
386391
let copy_bytes_sig = copy_bytes_signature(pointer_type, call_conv);
@@ -408,14 +413,15 @@ fn compile_ssa(
408413
};
409414
let helper_addrs = AotDeoptHelperAddrs {
410415
aot_interrupt: aot_call_boundary_interrupt_entry_address(),
416+
frame_state: frame_state_entry_address(),
411417
clone_value: clone_value_to_slot_entry_address(),
412418
value_eq: value_eq_entry_address(),
413419
init_null_slot: init_null_value_slot_entry_address(),
414420
clear_value_slot: clear_value_slot_entry_address(),
415421
box_heap_value: write_heap_value_to_slot_entry_address(),
416422
array_push: array_push_entry_address(),
417423
collection_set: collection_set_entry_address(),
418-
restore_exit: restore_exit_state_entry_address(),
424+
restore_exit: restore_active_exit_state_entry_address(),
419425
};
420426
let addr_setup_elapsed = addr_setup_started.elapsed();
421427

@@ -462,6 +468,7 @@ fn compile_ssa(
462468
helper_ref: b.import_signature(helper_sig),
463469
vm_status_ref: b.import_signature(vm_status_sig),
464470
interrupt_ref: b.import_signature(interrupt_sig),
471+
frame_state_ref: b.import_signature(frame_state_sig),
465472
clone_value_ref: b.import_signature(clone_value_sig),
466473
value_eq_ref: b.import_signature(value_eq_sig),
467474
init_null_slot_ref: b.import_signature(value_slot_sig.clone()),
@@ -558,6 +565,8 @@ fn compile_ssa(
558565
pointer_type,
559566
layout,
560567
offsets,
568+
helper_refs,
569+
helper_addrs,
561570
checkpoint,
562571
)?;
563572
b.ins()
@@ -685,15 +694,57 @@ fn compile_ssa(
685694
}
686695

687696
#[cfg(feature = "cranelift-jit")]
697+
#[allow(clippy::too_many_arguments)]
688698
fn load_checkpoint_args(
689699
b: &mut FunctionBuilder,
690700
vm_ptr: cranelift_codegen::ir::Value,
691701
exit_block: Block,
692702
pointer_type: cranelift_codegen::ir::Type,
693703
layout: crate::vm::native::NativeStackLayout,
694704
offsets: crate::vm::native::ResolvedOffsets,
705+
helper_refs: AotDeoptHelperRefs,
706+
helper_addrs: AotDeoptHelperAddrs,
695707
checkpoint: &AotCheckpoint,
696708
) -> Result<Vec<cranelift_codegen::ir::Value>, AotCompileError> {
709+
let frame_state_size =
710+
u32::try_from(std::mem::size_of::<NativeFrameState>()).map_err(|_| {
711+
AotCompileError::Codegen("native frame state size out of range".to_string())
712+
})?;
713+
let frame_state_align = std::mem::align_of::<NativeFrameState>().trailing_zeros() as u8;
714+
let frame_state_slot = b.create_sized_stack_slot(StackSlotData::new(
715+
StackSlotKind::ExplicitSlot,
716+
frame_state_size,
717+
frame_state_align,
718+
));
719+
let frame_state_ptr = b.ins().stack_addr(pointer_type, frame_state_slot, 0);
720+
call_status_helper(
721+
b,
722+
exit_block,
723+
pointer_type,
724+
helper_refs.frame_state_ref,
725+
helper_addrs.frame_state,
726+
&[vm_ptr, frame_state_ptr],
727+
)?;
728+
let stack_base_offset =
729+
i32::try_from(std::mem::offset_of!(NativeFrameState, operand_stack_base)).map_err(
730+
|_| AotCompileError::Codegen("frame stack-base offset out of range".to_string()),
731+
)?;
732+
let local_base_offset = i32::try_from(std::mem::offset_of!(NativeFrameState, local_base))
733+
.map_err(|_| {
734+
AotCompileError::Codegen("frame local-base offset out of range".to_string())
735+
})?;
736+
let stack_base = b.ins().load(
737+
pointer_type,
738+
MemFlags::new(),
739+
frame_state_ptr,
740+
stack_base_offset,
741+
);
742+
let local_base = b.ins().load(
743+
pointer_type,
744+
MemFlags::new(),
745+
frame_state_ptr,
746+
local_base_offset,
747+
);
697748
let stack_len = b
698749
.ins()
699750
.load(pointer_type, MemFlags::new(), vm_ptr, offsets.stack_len);
@@ -703,7 +754,8 @@ fn load_checkpoint_args(
703754
AotCompileError::Codegen("checkpoint stack length out of range".to_string())
704755
})?,
705756
);
706-
let stack_ok = b.ins().icmp(IntCC::Equal, stack_len, expected_stack_len);
757+
let expected_stack_total = b.ins().iadd(stack_base, expected_stack_len);
758+
let stack_ok = b.ins().icmp(IntCC::Equal, stack_len, expected_stack_total);
707759
let stack_match = b.create_block();
708760
let stack_error = b.ins().iconst(types::I32, STATUS_ERROR as i64);
709761
b.ins().brif(
@@ -724,7 +776,10 @@ fn load_checkpoint_args(
724776
AotCompileError::Codegen("checkpoint locals length out of range".to_string())
725777
})?,
726778
);
727-
let locals_ok = b.ins().icmp(IntCC::Equal, locals_len, expected_locals_len);
779+
let expected_locals_total = b.ins().iadd(local_base, expected_locals_len);
780+
let locals_ok = b
781+
.ins()
782+
.icmp(IntCC::Equal, locals_len, expected_locals_total);
728783
let locals_match = b.create_block();
729784
let locals_error = b.ins().iconst(types::I32, STATUS_ERROR as i64);
730785
b.ins().brif(
@@ -742,6 +797,8 @@ fn load_checkpoint_args(
742797
let locals_ptr = b
743798
.ins()
744799
.load(pointer_type, MemFlags::new(), vm_ptr, offsets.locals_ptr);
800+
let stack_ptr = ssa_value_addr(b, pointer_type, stack_ptr, stack_base, layout.value.size);
801+
let locals_ptr = ssa_value_addr(b, pointer_type, locals_ptr, local_base, layout.value.size);
745802

746803
let mut args = Vec::with_capacity(checkpoint.stack.len() + checkpoint.locals.len());
747804
for (index, repr) in checkpoint.stack.iter().copied().enumerate() {

src/vm/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ pub(crate) fn checked_int_rem(lhs: i64, rhs: i64) -> VmResult<i64> {
459459
fn compute_program_cache_key(program: &Program) -> u64 {
460460
let mut hasher = StableHasher::default();
461461
crate::bytecode::BYTECODE_ABI_VERSION.hash(&mut hasher);
462+
native::NATIVE_CALLABLE_ABI_VERSION.hash(&mut hasher);
462463
program.code.hash(&mut hasher);
463464
program.local_count.hash(&mut hasher);
464465
for constant in &program.constants {
@@ -966,6 +967,13 @@ impl Vm {
966967
}
967968

968969
#[inline(always)]
970+
fn active_operand_stack_base(&self) -> usize {
971+
self.execution_frames
972+
.last()
973+
.map(|frame| frame.operand_stack_base)
974+
.unwrap_or(0)
975+
}
976+
969977
fn active_local_base(&self) -> usize {
970978
self.execution_frames
971979
.last()

0 commit comments

Comments
 (0)