Skip to content

Commit fb74667

Browse files
authored
Refactored dict representation and writing. (#1605)
1 parent 7a2dd42 commit fb74667

3 files changed

Lines changed: 23 additions & 40 deletions

File tree

src/metadata/trace_dump.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ pub mod trace_dump_runtime {
711711
let data = value
712712
.mappings
713713
.iter()
714-
.map(|(k, &i)| {
714+
.map(|(&k, &i)| {
715715
let p = value
716716
.elements
717717
.byte_offset((value.layout.size() * i) as isize);
@@ -721,7 +721,6 @@ pub mod trace_dump_runtime {
721721
ty: info.ty.clone(),
722722
},
723723
};
724-
let k = Felt::from_bytes_le(k);
725724
(k, v)
726725
})
727726
.collect::<HashMap<Felt, Value>>();
@@ -739,7 +738,7 @@ pub mod trace_dump_runtime {
739738
.dict
740739
.mappings
741740
.iter()
742-
.map(|(k, &i)| {
741+
.map(|(&k, &i)| {
743742
let p = value
744743
.dict
745744
.elements
@@ -750,17 +749,15 @@ pub mod trace_dump_runtime {
750749
ty: info.ty.clone(),
751750
},
752751
};
753-
let k = Felt::from_bytes_le(k);
754752
(k, v)
755753
})
756754
.collect::<HashMap<Felt, Value>>();
757-
let key = Felt::from_bytes_le(value.key);
758755

759756
Value::FeltDictEntry {
760757
ty: info.ty.clone(),
761758
data,
762759
count: value.dict.count,
763-
key,
760+
key: *value.key,
764761
}
765762
}
766763
CoreTypeConcrete::Span(_) => todo!("CoreTypeConcrete::Span"),
@@ -920,7 +917,7 @@ pub mod trace_dump_runtime {
920917
#[derive(Debug)]
921918
struct FeltDictEntry<'a> {
922919
dict: &'a FeltDict,
923-
key: &'a [u8; 32],
920+
key: &'a Felt,
924921
}
925922

926923
#[repr(C, align(16))]

src/runtime.rs

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use cairo_lang_sierra_gas::core_libfunc_cost::{
1212
use itertools::Itertools;
1313
use lambdaworks_math::field::fields::mersenne31::extensions::Degree4ExtensionField;
1414
use lazy_static::lazy_static;
15-
use num_bigint::BigInt;
1615
use num_traits::{ToPrimitive, Zero};
1716
use rand::Rng;
1817
use starknet_curve::curve_params::BETA;
@@ -30,7 +29,6 @@ use std::{
3029
fs::File,
3130
io::Write,
3231
mem::{forget, ManuallyDrop},
33-
ops::Shl,
3432
os::fd::FromRawFd,
3533
ptr::{self, null_mut},
3634
rc::Rc,
@@ -191,7 +189,7 @@ pub unsafe extern "C" fn cairo_native__libfunc__blake_compress(
191189
/// Felt252 type used in cairo native runtime
192190
#[derive(Debug)]
193191
pub struct FeltDict {
194-
pub mappings: HashMap<[u8; 32], usize>,
192+
pub mappings: HashMap<Felt, usize>,
195193

196194
pub layout: Layout,
197195
pub elements: *mut (),
@@ -308,7 +306,7 @@ pub unsafe extern "C" fn cairo_native__dict_get(
308306
let num_mappings = dict.mappings.len();
309307
let has_capacity = num_mappings != dict.mappings.capacity();
310308

311-
let (is_present, index) = match dict.mappings.entry(*key) {
309+
let (is_present, index) = match dict.mappings.entry(Felt::from_bytes_le(key)) {
312310
Entry::Occupied(entry) => (true, *entry.get()),
313311
Entry::Vacant(entry) => {
314312
entry.insert(num_mappings);
@@ -364,24 +362,22 @@ unsafe fn create_dict_entries_array(dict: &mut FeltDict) -> ArrayAbi<c_void> {
364362

365363
// Allocate data separately (no inline prefix)
366364
let data_ptr = libc_malloc(tuple_stride * dict.mappings.len());
365+
let mut work_ptr = data_ptr;
367366

368367
// Get the stride for the inner types of the tuple
369368
let key_size = Layout::new::<Felt252Abi>().pad_to_align().size();
370-
let generic_ty_size = dict.layout.pad_to_align().size();
371-
372-
for (key, elem_index) in &dict.mappings {
373-
// Move the ptr to the offset of the tuple we want to modify
374-
let key_ptr = data_ptr.byte_add(tuple_stride * elem_index) as *mut [u8; 32];
375-
376-
// Save the key and move to the offset of the 'first_value'
377-
*key_ptr = *key;
378-
let first_val_ptr = key_ptr.byte_add(key_size) as *mut u8;
379-
first_val_ptr.write_bytes(0, generic_ty_size);
380-
381-
// Get the element, move to the offset of the 'last_value' and save the element in that address
382-
let element = dict.elements.byte_add(generic_ty_size * elem_index) as *mut u8;
383-
let last_val_ptr = first_val_ptr.byte_add(generic_ty_size);
384-
std::ptr::copy_nonoverlapping(element, last_val_ptr, generic_ty_size);
369+
let element_size = dict.layout.pad_to_align().size();
370+
371+
for (key, elem_index) in dict.mappings.iter().sorted() {
372+
let key_ptr = work_ptr as *mut [u8; 32];
373+
let default_value_ptr = work_ptr.byte_add(key_size) as *mut u8;
374+
let final_value_ptr = default_value_ptr.byte_add(element_size);
375+
work_ptr = work_ptr.byte_add(tuple_stride);
376+
377+
*key_ptr = key.to_bytes_le();
378+
default_value_ptr.write_bytes(0, element_size);
379+
let value = dict.elements.byte_add(element_size * elem_index) as *mut u8;
380+
final_value_ptr.copy_from_nonoverlapping(value, element_size);
385381
}
386382

387383
// Allocate and initialize ArrayMetadata struct
@@ -444,7 +440,7 @@ pub unsafe extern "C" fn cairo_native__dict_squash(
444440
range_check_ptr: &mut u64,
445441
gas_ptr: &mut u64,
446442
) {
447-
let dict = Rc::from_raw(dict_ptr);
443+
let dict = &*dict_ptr;
448444

449445
*gas_ptr +=
450446
(dict.count.saturating_sub(dict.mappings.len() as u64)) * *DICT_GAS_REFUND_PER_ACCESS;
@@ -453,11 +449,8 @@ pub unsafe extern "C" fn cairo_native__dict_squash(
453449
// https://github.com/starkware-libs/cairo/blob/v2.12.0-dev.1/crates/cairo-lang-sierra-to-casm/src/invocations/felt252_dict.rs?plain=1#L131-L136
454450
*range_check_ptr += 2;
455451

456-
let no_big_keys = dict
457-
.mappings
458-
.keys()
459-
.map(Felt::from_bytes_le)
460-
.all(|key| key < Felt::from(BigInt::from(1).shl(128)));
452+
let u128_max = Felt::from(u128::MAX);
453+
let no_big_keys = dict.mappings.keys().all(|key| *key <= u128_max);
461454
let number_of_keys = dict.mappings.len() as u64;
462455

463456
// How we update the range check depends on whether we have any big key or not.
@@ -498,8 +491,6 @@ pub unsafe extern "C" fn cairo_native__dict_squash(
498491
// For each non unique accessed key, we increase the range check an additional time.
499492
// https://github.com/starkware-libs/cairo/blob/v2.12.0-dev.1/crates/cairo-lang-sierra-to-casm/src/invocations/felt252_dict.rs?plain=1#L602
500493
*range_check_ptr += dict.count.saturating_sub(dict.mappings.len() as u64);
501-
502-
forget(dict);
503494
}
504495

505496
/// Compute `ec_point_from_x_nz(x)` and store it.

src/values.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,12 +433,11 @@ impl Value {
433433
// next key must be called before next_value
434434

435435
for (key, value) in map.iter() {
436-
let key = key.to_bytes_le();
437436
let value =
438437
value.to_ptr(arena, registry, &info.ty, find_dict_drop_override)?;
439438

440439
let index = value_map.mappings.len();
441-
value_map.mappings.insert(key, index);
440+
value_map.mappings.insert(*key, index);
442441

443442
std::ptr::copy_nonoverlapping(
444443
value.cast::<u8>().as_ptr(),
@@ -851,10 +850,6 @@ impl Value {
851850

852851
let mut output_map = HashMap::with_capacity(dict.mappings.len());
853852
for (&key, &index) in dict.mappings.iter() {
854-
let mut key = key;
855-
key[31] &= 0x0F; // Filter out first 4 bits (they're outside an i252).
856-
857-
let key = Felt::from_bytes_le(&key);
858853
// The dictionary items are not being dropped here. They'll be dropped along
859854
// with the dictionary (if requested using `should_drop`).
860855
output_map.insert(

0 commit comments

Comments
 (0)