Skip to content

Commit 025181a

Browse files
moved array metadata to be behind a single pointer refrence (#1551)
1 parent 25359bb commit 025181a

6 files changed

Lines changed: 436 additions & 376 deletions

File tree

src/executor/contract.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use crate::{
4848
native_assert, native_panic,
4949
starknet::{handler::StarknetSyscallHandlerCallbacks, StarknetSyscallHandler},
5050
statistics::{SierraDeclaredTypeStats, SierraFuncStats, Statistics},
51-
types::TypeBuilder,
51+
types::{array::ArrayMetadata, TypeBuilder},
5252
utils::{
5353
decode_error_message, generate_function_name, get_integer_layout, get_types_total_size,
5454
libc_free, libc_malloc, BuiltinCosts,
@@ -482,47 +482,44 @@ impl AotContractExecutor {
482482
}
483483

484484
let felt_layout = get_integer_layout(252).pad_to_align();
485-
let refcount_offset = crate::types::array::calc_data_prefix_offset(felt_layout);
486485

487486
let len_u32: u32 = args
488487
.len()
489488
.try_into()
490489
.to_native_assert_error("number of arguments should fit into a u32")?;
491-
let array_ptr = match args.len() {
490+
491+
let data_ptr = match args.len() {
492492
0 => std::ptr::null_mut(),
493-
_ => unsafe {
494-
let array_ptr: *mut () =
495-
libc_malloc(felt_layout.size() * args.len() + refcount_offset).cast();
496-
497-
// Write reference count.
498-
array_ptr.cast::<(u32, u32)>().write((1, len_u32));
499-
array_ptr.byte_add(refcount_offset)
500-
},
493+
_ => unsafe { libc_malloc(felt_layout.size() * args.len()).cast::<u8>() },
501494
};
502495

503496
for (idx, elem) in args.iter().enumerate() {
504497
let f = elem.to_bytes_le();
505498
unsafe {
506499
std::ptr::copy_nonoverlapping(
507500
f.as_ptr().cast::<u8>(),
508-
array_ptr.byte_add(idx * felt_layout.size()).cast::<u8>(),
501+
data_ptr.byte_add(idx * felt_layout.size()).cast::<u8>(),
509502
felt_layout.size(),
510503
)
511504
};
512505
}
513506

514-
// Make double pointer.
515-
let array_ptr_ptr = if array_ptr.is_null() {
507+
// Allocate metadata struct: { refcount: u32, max_len: u32, data_ptr: *mut () }
508+
let metadata_ptr = if data_ptr.is_null() {
516509
ptr::null_mut()
517510
} else {
518511
unsafe {
519-
let array_ptr_ptr = libc_malloc(size_of::<*mut ()>()).cast::<*mut ()>();
520-
array_ptr_ptr.write(array_ptr);
521-
array_ptr_ptr
512+
let metadata = libc_malloc(size_of::<ArrayMetadata>()).cast::<ArrayMetadata>();
513+
metadata.write(ArrayMetadata {
514+
refcount: 1,
515+
max_len: len_u32,
516+
data_ptr,
517+
});
518+
metadata.cast::<()>()
522519
}
523520
};
524521

525-
array_ptr_ptr.to_bytes(&mut invoke_data, |_| unreachable!())?;
522+
metadata_ptr.to_bytes(&mut invoke_data, |_| unreachable!())?;
526523
if cfg!(target_arch = "aarch64") {
527524
0u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // start
528525
len_u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // end
@@ -653,18 +650,19 @@ impl AotContractExecutor {
653650
let value_layout = unsafe { Layout::from_size_align_unchecked(24, 8) };
654651
let mut value_ptr = unsafe { enum_ptr.byte_add(tag_layout.extend(value_layout)?.1).cast() };
655652

656-
let array_ptr_ptr = unsafe { *read_value::<*mut NonNull<()>>(&mut value_ptr) };
653+
let metadata_ptr = unsafe { *read_value::<*mut NonNull<()>>(&mut value_ptr) };
657654
let array_start = unsafe { *read_value::<u32>(&mut value_ptr) };
658655
let array_end = unsafe { *read_value::<u32>(&mut value_ptr) };
659656
let _array_capacity = unsafe { *read_value::<u32>(&mut value_ptr) };
660657

661658
let mut array_value = Vec::with_capacity((array_end - array_start) as usize);
662-
if !array_ptr_ptr.is_null() {
663-
let array_ptr = unsafe { array_ptr_ptr.read() };
659+
if !metadata_ptr.is_null() {
660+
let metadata = unsafe { metadata_ptr.cast::<ArrayMetadata>().read() };
661+
let data_ptr = metadata.data_ptr;
664662

665663
let elem_stride = felt_layout.pad_to_align().size();
666664
for i in array_start..array_end {
667-
let cur_elem_ptr = unsafe { array_ptr.byte_add(elem_stride * i as usize) };
665+
let cur_elem_ptr = unsafe { data_ptr.byte_add(elem_stride * i as usize) };
668666

669667
let mut data = unsafe { cur_elem_ptr.cast::<[u8; 32]>().read() };
670668
data[31] &= 0x0F; // Filter out first 4 bits (they're outside an i252).
@@ -673,13 +671,12 @@ impl AotContractExecutor {
673671
}
674672

675673
unsafe {
676-
let array_ptr = array_ptr.byte_sub(refcount_offset);
677674
native_assert!(
678-
array_ptr.cast::<u32>().read() == 1,
675+
metadata.refcount == 1,
679676
"return array should have a reference count of 1"
680677
);
681-
libc_free(array_ptr.as_ptr().cast());
682-
libc_free(array_ptr_ptr.cast());
678+
libc_free(data_ptr.cast());
679+
libc_free(metadata_ptr.cast());
683680
}
684681
}
685682

0 commit comments

Comments
 (0)