diff --git a/Cargo.lock b/Cargo.lock index d26542199..560cf465c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -99,7 +99,7 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1339,9 +1339,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", @@ -1349,9 +1349,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", @@ -1390,7 +1390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1417,7 +1417,7 @@ dependencies = [ "libc", "once_cell", "unicode-width", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1551,9 +1551,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -1751,7 +1751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -2111,13 +2111,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "3f187290c0ed3dfe3f7c85bedddd320949b68fc86ca0ceb71adfb05b3dc3af2a" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -3123,15 +3123,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -3384,9 +3384,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "sprs" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704ef26d974e8a452313ed629828cd9d4e4fa34667ca1ad9d6b1fffa43c6e166" +checksum = "8bff8419009a08f6cb7519a602c5590241fbff1446bcc823c07af15386eb801b" dependencies = [ "ndarray", "num-complex", @@ -3577,7 +3577,7 @@ dependencies = [ "getrandom", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -4088,7 +4088,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -4097,15 +4097,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/programs/benches/dict_insert.c b/programs/benches/dict_insert.c deleted file mode 100644 index ed0b2ad6f..000000000 --- a/programs/benches/dict_insert.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - - -typedef struct dict_insert_return_values -{ - uint64_t range_check_counter; - uint64_t segment_arena_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void *ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} dict_insert_return_values_t; - -static void run_bench(dict_insert_return_values_t *, uint64_t, uint64_t, uint64_t) - __attribute__((weakref("_mlir_ciface_dict_insert::dict_insert::main(f3)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - dict_insert_return_values_t return_values; - - run_bench(&return_values, 0, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/programs/benches/dict_snapshot.c b/programs/benches/dict_snapshot.c deleted file mode 100644 index 789bcb3bd..000000000 --- a/programs/benches/dict_snapshot.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - - -typedef struct dict_snapshot_return_values -{ - uint64_t range_check_counter; - uint64_t segment_arena_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void *ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} dict_snapshot_return_values_t; - -static void run_bench(dict_snapshot_return_values_t *, uint64_t, uint64_t, uint64_t) - __attribute__((weakref("_mlir_ciface_dict_snapshot::dict_snapshot::main(f4)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - dict_snapshot_return_values_t return_values; - - run_bench(&return_values, 0, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/programs/benches/factorial_2M.c b/programs/benches/factorial_2M.c deleted file mode 100644 index 0435f3740..000000000 --- a/programs/benches/factorial_2M.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - - -typedef struct factorial_return_values -{ - uint64_t range_check_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void* ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} factorial_return_values_t; - -static void run_bench(factorial_return_values_t*, uint64_t, uint64_t) -__attribute__((weakref("_mlir_ciface_factorial_2M::factorial_2M::main(f1)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - factorial_return_values_t return_values; - - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - run_bench(&return_values, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/programs/benches/fib_2M.c b/programs/benches/fib_2M.c deleted file mode 100644 index 343807619..000000000 --- a/programs/benches/fib_2M.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - - -typedef struct fib_return_values -{ - uint64_t range_check_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void *ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} fib_return_values_t; - -static void run_bench(fib_return_values_t *, uint64_t, uint64_t) - __attribute__((weakref("_mlir_ciface_fib_2M::fib_2M::main(f1)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - fib_return_values_t return_values; - - run_bench(&return_values, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/programs/benches/linear_search.c b/programs/benches/linear_search.c deleted file mode 100644 index 85c9b706a..000000000 --- a/programs/benches/linear_search.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - - -typedef struct linear_search_return_values -{ - uint64_t range_check_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void *ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} linear_search_return_values_t; - -static void run_bench(linear_search_return_values_t *, uint64_t, uint64_t) - __attribute__((weakref("_mlir_ciface_linear_search::linear_search::main(f4)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - linear_search_return_values_t return_values; - - run_bench(&return_values, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/programs/benches/logistic_map.c b/programs/benches/logistic_map.c deleted file mode 100644 index b88cd985a..000000000 --- a/programs/benches/logistic_map.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - - -typedef struct map_return_values -{ - uint64_t range_check_counter; - uint64_t remaining_gas; - struct { - uint8_t discriminant; - struct { - void *ptr; - uint32_t start; - uint32_t end; - uint32_t cap; - } err; - } result; -} map_return_values_t; - -static void run_bench(map_return_values_t *, uint64_t, uint64_t) - __attribute__((weakref("_mlir_ciface_logistic_map::logistic_map::main(f2)"))); - -extern uint64_t* cairo_native__set_costs_builtin(uint64_t*); - -int main() -{ - uint64_t BuiltinCosts[7] = {1, 4050, 583, 4085, 491, 230, 604}; - - cairo_native__set_costs_builtin(&BuiltinCosts[0]); - - map_return_values_t return_values; - - run_bench(&return_values, 0, 0xFFFFFFFFFFFFFFFF); - assert((return_values.result.discriminant & 0x1) == 0); - - return 0; -} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8f0464d08..f21d8cdaa 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -37,7 +37,6 @@ lazy_static! { (DICT_SQUASH_UNIQUE_KEY_COST.cost() - DICT_SQUASH_REPEATED_ACCESS_COST.cost()) as u64; } -#[no_mangle] #[allow(clippy::missing_safety_doc)] pub unsafe extern "C" fn cairo_native__get_version(target: *mut u8, length: usize) -> usize { let version = env!("CARGO_PKG_VERSION"); @@ -59,7 +58,6 @@ pub unsafe extern "C" fn cairo_native__get_version(target: *mut u8, length: usiz /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__debug__print( target_fd: i32, data: *const [u8; 32], @@ -99,7 +97,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__debug__print( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__pedersen( dst: &mut [u8; 32], lhs: &[u8; 32], @@ -133,7 +130,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__pedersen( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__hades_permutation( op0: &mut [u8; 32], op1: &mut [u8; 32], @@ -263,7 +259,6 @@ impl Drop for FeltDict { /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__dict_new( size: u64, align: u64, @@ -292,7 +287,6 @@ pub unsafe extern "C" fn cairo_native__dict_new( // Note: Using `Option` is ffi-safe thanks to Option's null // pointer optimization. Check out // https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization for more info. -#[no_mangle] pub unsafe extern "C" fn cairo_native__dict_drop(ptr: *const FeltDict) { drop(Rc::from_raw(ptr)); } @@ -303,7 +297,6 @@ pub unsafe extern "C" fn cairo_native__dict_drop(ptr: *const FeltDict) { /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__dict_dup(dict_ptr: *const FeltDict) -> *const FeltDict { let old_dict = Rc::from_raw(dict_ptr); let new_dict = Rc::clone(&old_dict); @@ -322,7 +315,6 @@ pub unsafe extern "C" fn cairo_native__dict_dup(dict_ptr: *const FeltDict) -> *c /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__dict_get( dict: *const FeltDict, key: &[u8; 32], @@ -372,7 +364,6 @@ pub unsafe extern "C" fn cairo_native__dict_get( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__dict_gas_refund(ptr: *const FeltDict) -> u64 { let dict = Rc::from_raw(ptr); let amount = @@ -392,7 +383,6 @@ pub unsafe extern "C" fn cairo_native__dict_gas_refund(ptr: *const FeltDict) -> /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_from_x_nz( point_ptr: &mut [[u8; 32]; 2], ) -> bool { @@ -430,7 +420,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_from_x_nz( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_try_new_nz( point_ptr: &mut [[u8; 32]; 2], ) -> bool { @@ -456,7 +445,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_try_new_nz( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_init(state_ptr: &mut [[u8; 32]; 4]) { // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-runner/src/casm_run/mod.rs#L1802 let mut rng = rand::thread_rng(); @@ -489,7 +477,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_init(state_ptr: &mu /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add( state_ptr: &mut [[u8; 32]; 4], point_ptr: &[[u8; 32]; 2], @@ -528,7 +515,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add_mul( state_ptr: &mut [[u8; 32]; 4], scalar_ptr: &[u8; 32], @@ -572,7 +558,6 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add_mul( /// /// This function is intended to be called from MLIR, deals with pointers, and is therefore /// definitely unsafe to use manually. -#[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_try_finalize_nz( point_ptr: &mut [[u8; 32]; 2], state_ptr: &[[u8; 32]; 4], @@ -615,7 +600,6 @@ thread_local! { /// Store the gas builtin in the internal thread local. Returns the old pointer, to restore it after execution. /// Not a runtime metadata method, it should be called before the program is executed. -#[no_mangle] pub extern "C" fn cairo_native__set_costs_builtin(ptr: *const u64) -> *const u64 { let old = BUILTIN_COSTS.get(); BUILTIN_COSTS.set(ptr); @@ -623,7 +607,6 @@ pub extern "C" fn cairo_native__set_costs_builtin(ptr: *const u64) -> *const u64 } /// Get the gas builtin from the internal thread local. -#[no_mangle] pub extern "C" fn cairo_native__get_costs_builtin() -> *const u64 { if BUILTIN_COSTS.get().is_null() { // We shouldn't panic here, but we can print a big message. diff --git a/scripts/bench-hyperfine.sh b/scripts/bench-hyperfine.sh index aa02a1e94..e802ba0da 100755 --- a/scripts/bench-hyperfine.sh +++ b/scripts/bench-hyperfine.sh @@ -39,37 +39,15 @@ mkdir -p "$OUTPUT_DIR" # Benchmarking code. run_bench() { base_path="${1%.cairo}" - base_name=$(basename $base_path) + base_name=$(basename "$base_path") - "$COMPILER_CLI" \ - -s "$base_path.cairo" \ - "$OUTPUT_DIR/$base_name.mlir" \ - "$OUTPUT_DIR/lib$base_name.so" \ - >> /dev/stderr - - "$MLIR_DIR/bin/clang" \ - -O3 \ - -march=native \ - -mtune=native \ - -fPIC \ - -Wno-override-module \ - "$base_path.c" \ - -L"$OUTPUT_DIR/" \ - -Wl,-rpath "$MLIR_DIR/lib" \ - -Wl,-rpath "$OUTPUT_DIR" \ - -l"$base_name" \ - -lm \ - -o "$OUTPUT_DIR/$base_name-march-native" \ - >> /dev/stderr - - hyperfine \ + hyperfine \ --warmup 3 \ --export-markdown "$OUTPUT_DIR/$base_name.md" \ --export-json "$OUTPUT_DIR/$base_name.json" \ -n "Cairo-vm (Rust, Cairo 1)" "$CAIRO_RUN --available-gas 18446744073709551615 -s $base_path.cairo" \ -n "cairo-native (embedded AOT)" "$JIT_CLI --run-mode=aot -s $base_path.cairo --opt-level 3 --available-gas 18446744073709551615 " \ -n "cairo-native (embedded JIT using LLVM's ORC Engine)" "$JIT_CLI --run-mode=jit -s $base_path.cairo --opt-level 3 --available-gas 18446744073709551615 " \ - -n "cairo-native (standalone AOT with -march=native)" "$OUTPUT_DIR/$base_name-march-native" \ >> /dev/stderr } diff --git a/src/executor.rs b/src/executor.rs index 8aaf2d9fe..39ed4ddc9 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -67,7 +67,6 @@ extern "C" { fn invoke_dynamic( registry: &ProgramRegistry, function_ptr: *const c_void, - set_builtin_costs_fnptr: extern "C" fn(*const u64) -> *const u64, function_signature: &FunctionSignature, args: &[Value], gas: u64, @@ -156,7 +155,8 @@ fn invoke_dynamic( // deref it, it will be a copy on the stack, so you will get the ptr of the value in the stack. let builtin_costs: *mut [u64; 7] = Box::into_raw(Box::new(builtin_costs_stack)); // We may be inside a recursive contract, save the possible saved builtin costs to restore it after our call. - let old_builtincosts_ptr = set_builtin_costs_fnptr(builtin_costs.cast()); + let old_builtincosts_ptr = + cairo_native_runtime::cairo_native__set_costs_builtin(builtin_costs.cast()); // Generate argument list. let mut iter = args.iter(); @@ -338,7 +338,8 @@ fn invoke_dynamic( }); // Restore the old ptr and get back our builtincost box and free it. - let our_builtincosts_ptr = set_builtin_costs_fnptr(old_builtincosts_ptr); + let our_builtincosts_ptr = + cairo_native_runtime::cairo_native__set_costs_builtin(old_builtincosts_ptr); if !our_builtincosts_ptr.is_null() && old_builtincosts_ptr.is_aligned() { unsafe { diff --git a/src/executor/aot.rs b/src/executor/aot.rs index 257bb775a..134aaa71b 100644 --- a/src/executor/aot.rs +++ b/src/executor/aot.rs @@ -1,7 +1,9 @@ use crate::{ error::Error, execution_result::{ContractExecutionResult, ExecutionResult}, - metadata::{felt252_dict::Felt252DictOverrides, gas::GasMetadata}, + metadata::{ + felt252_dict::Felt252DictOverrides, gas::GasMetadata, runtime_bindings::setup_runtime, + }, module::NativeModule, starknet::{DummySyscallHandler, StarknetSyscallHandler}, utils::generate_function_name, @@ -37,18 +39,22 @@ unsafe impl Send for AotNativeExecutor {} unsafe impl Sync for AotNativeExecutor {} impl AotNativeExecutor { - pub const fn new( + pub fn new( library: Library, registry: ProgramRegistry, gas_metadata: GasMetadata, dict_overrides: Felt252DictOverrides, ) -> Self { - Self { + let executor = Self { library, registry, gas_metadata, dict_overrides, - } + }; + + setup_runtime(|name| executor.find_symbol_ptr(name)); + + executor } /// Utility to convert a [`NativeModule`] into an [`AotNativeExecutor`]. @@ -67,12 +73,12 @@ impl AotNativeExecutor { let object_data = crate::module_to_object(&module, opt_level)?; crate::object_to_shared_lib(&object_data, &library_path)?; - Ok(Self { - library: unsafe { Library::new(&library_path)? }, + Ok(Self::new( + unsafe { Library::new(&library_path)? }, registry, - gas_metadata: metadata.remove().ok_or(Error::MissingMetadata)?, - dict_overrides: metadata.remove().unwrap_or_default(), - }) + metadata.remove().ok_or(Error::MissingMetadata)?, + metadata.remove().unwrap_or_default(), + )) } pub fn invoke_dynamic( @@ -86,21 +92,9 @@ impl AotNativeExecutor { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_costs_builtin: extern "C" fn(*const u64) -> *const u64 = unsafe { - std::mem::transmute( - self.library - .get:: *const u64>( - b"cairo_native__set_costs_builtin", - )? - .into_raw() - .into_raw(), - ) - }; - super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id)?, - set_costs_builtin, self.extract_signature(function_id)?, args, available_gas, @@ -121,21 +115,9 @@ impl AotNativeExecutor { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_costs_builtin: extern "C" fn(*const u64) -> *const u64 = unsafe { - std::mem::transmute( - self.library - .get:: *const u64>( - b"cairo_native__set_costs_builtin", - )? - .into_raw() - .into_raw(), - ) - }; - super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id)?, - set_costs_builtin, self.extract_signature(function_id)?, args, available_gas, @@ -156,21 +138,9 @@ impl AotNativeExecutor { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_costs_builtin: extern "C" fn(*const u64) -> *const u64 = unsafe { - std::mem::transmute( - self.library - .get:: *const u64>( - b"cairo_native__set_costs_builtin", - )? - .into_raw() - .into_raw(), - ) - }; - ContractExecutionResult::from_execution_result(super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id)?, - set_costs_builtin, self.extract_signature(function_id)?, &[Value::Struct { fields: vec![Value::Array( diff --git a/src/executor/contract.rs b/src/executor/contract.rs index f0a9c17a8..bb6b825d1 100644 --- a/src/executor/contract.rs +++ b/src/executor/contract.rs @@ -37,7 +37,7 @@ use crate::{ error::{panic::ToNativeAssertError, Error, Result}, execution_result::{BuiltinStats, ContractExecutionResult}, executor::invoke_trampoline, - metadata::gas::MetadataComputationConfig, + metadata::{gas::MetadataComputationConfig, runtime_bindings::setup_runtime}, module::NativeModule, native_panic, starknet::{handler::StarknetSyscallHandlerCallbacks, StarknetSyscallHandler}, @@ -235,7 +235,7 @@ impl AotContractExecutor { let object_data = crate::module_to_object(&module, opt_level)?; crate::object_to_shared_lib(&object_data, &library_path)?; - Ok(Self { + let executor = Self { library: Arc::new(unsafe { Library::new(&library_path)? }), path: library_path, is_temp_path: true, @@ -244,7 +244,11 @@ impl AotContractExecutor { entry_points_info: infos, entry_point_selector_to_id, }, - }) + }; + + setup_runtime(|name| executor.find_symbol_ptr(name)); + + Ok(executor) } /// Save the library to the desired path, alongside it is saved also a json file with additional info. @@ -268,27 +272,14 @@ impl AotContractExecutor { let contract_info: NativeContractInfo = serde_json::from_str(&info_str)?; let library = Arc::new(unsafe { Library::new(library_path)? }); - unsafe { - let get_version = library - .get:: usize>(b"cairo_native__get_version")?; - - let mut version_buffer = [0u8; 16]; - let version_len = get_version(version_buffer.as_mut_ptr(), version_buffer.len()); - - let target_version = env!("CARGO_PKG_VERSION"); - assert_eq!( - &version_buffer[..version_len], - target_version.as_bytes(), - "aot-compiled contract version mismatch" - ); - }; - - Ok(Self { + let executor = Self { library, path: library_path.to_path_buf(), is_temp_path: false, contract_info, - }) + }; + setup_runtime(|name| executor.find_symbol_ptr(name)); + Ok(executor) } /// Runs the entry point by the given selector. @@ -322,14 +313,10 @@ impl AotContractExecutor { let function_ptr = self.find_function_ptr(&function_id, true)?; let builtin_costs: [u64; 7] = builtin_costs.unwrap_or_default().into(); - let set_costs_builtin = unsafe { - self.library - .get:: *const u64>( - b"cairo_native__set_costs_builtin", - )? - }; + // We may be inside a recursive contract, save the possible saved builtin costs to restore it after our call. - let old_builtincosts_ptr = set_costs_builtin(builtin_costs.as_ptr()); + let old_builtincosts_ptr = + cairo_native_runtime::cairo_native__set_costs_builtin(builtin_costs.as_ptr()); // it can vary from contract to contract thats why we need to store/ load it. let builtins_size: usize = self.contract_info.entry_points_info[&function_id.id] @@ -571,7 +558,7 @@ impl AotContractExecutor { }; // Restore the original builtin costs pointer. - set_costs_builtin(old_builtincosts_ptr); + cairo_native_runtime::cairo_native__set_costs_builtin(old_builtincosts_ptr); #[cfg(feature = "with-mem-tracing")] crate::utils::mem_tracing::report_stats(); diff --git a/src/executor/jit.rs b/src/executor/jit.rs index 6697e7f5e..4c95a1bb0 100644 --- a/src/executor/jit.rs +++ b/src/executor/jit.rs @@ -1,7 +1,9 @@ use crate::{ error::Error, execution_result::{ContractExecutionResult, ExecutionResult}, - metadata::{felt252_dict::Felt252DictOverrides, gas::GasMetadata}, + metadata::{ + felt252_dict::Felt252DictOverrides, gas::GasMetadata, runtime_bindings::setup_runtime, + }, module::NativeModule, starknet::{DummySyscallHandler, StarknetSyscallHandler}, utils::{create_engine, generate_function_name}, @@ -53,13 +55,17 @@ impl<'m> JitNativeExecutor<'m> { mut metadata, } = native_module; - Ok(Self { + let executor = Self { engine: create_engine(&module, &metadata, opt_level), module, registry, gas_metadata: metadata.remove().ok_or(Error::MissingMetadata)?, dict_overrides: metadata.remove().unwrap_or_default(), - }) + }; + + setup_runtime(|name| executor.find_symbol_ptr(name)); + + Ok(executor) } pub const fn program_registry(&self) -> &ProgramRegistry { @@ -82,13 +88,9 @@ impl<'m> JitNativeExecutor<'m> { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_builtin_costs_fnptr: extern "C" fn(*const u64) -> *const u64 = - unsafe { std::mem::transmute(self.engine.lookup("cairo_native__set_costs_builtin")) }; - super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id), - set_builtin_costs_fnptr, self.extract_signature(function_id)?, args, available_gas, @@ -110,13 +112,9 @@ impl<'m> JitNativeExecutor<'m> { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_builtin_costs_fnptr: extern "C" fn(*const u64) -> *const u64 = - unsafe { std::mem::transmute(self.engine.lookup("cairo_native__set_costs_builtin")) }; - super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id), - set_builtin_costs_fnptr, self.extract_signature(function_id)?, args, available_gas, @@ -137,13 +135,9 @@ impl<'m> JitNativeExecutor<'m> { .get_initial_available_gas(function_id, gas) .map_err(crate::error::Error::GasMetadataError)?; - let set_builtin_costs_fnptr: extern "C" fn(*const u64) -> *const u64 = - unsafe { std::mem::transmute(self.engine.lookup("cairo_native__set_costs_builtin")) }; - ContractExecutionResult::from_execution_result(super::invoke_dynamic( &self.registry, self.find_function_ptr(function_id), - set_builtin_costs_fnptr, self.extract_signature(function_id)?, &[Value::Struct { fields: vec![Value::Array( diff --git a/src/ffi.rs b/src/ffi.rs index 02a3da739..ead1d033b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -29,7 +29,6 @@ use melior::ir::{Module, Type, TypeLike}; use mlir_sys::{mlirLLVMStructTypeGetElementType, mlirTranslateModuleToLLVMIR}; use std::{ borrow::Cow, - env, ffi::{CStr, CString}, io::Write, mem::MaybeUninit, @@ -243,22 +242,6 @@ pub fn object_to_shared_lib(object: &[u8], output_filename: &Path) -> Result<()> } } - let runtime_library_path = if let Ok(extra_dir) = std::env::var("CAIRO_NATIVE_RUNTIME_LIBRARY") - { - let path = Path::new(&extra_dir); - if path.is_absolute() { - extra_dir - } else { - let absolute_path = env::current_dir()?.join(path).canonicalize()?; - absolute_path - .to_str() - .to_native_assert_error("absolute path should not contain non-utf8 characters")? - .to_string() - } - } else { - String::from("libcairo_native_runtime.a") - }; - let args: Vec> = { #[cfg(target_os = "macos")] { @@ -276,8 +259,6 @@ pub fn object_to_shared_lib(object: &[u8], output_filename: &Path) -> Result<()> "-o".into(), Cow::from(output_path), "-lSystem".into(), - "-force_load".into(), // needed so `cairo_native__set_costs_builtin` is always available - Cow::from(runtime_library_path), ]); args @@ -296,8 +277,6 @@ pub fn object_to_shared_lib(object: &[u8], output_filename: &Path) -> Result<()> Cow::from(output_path), "-lc".into(), Cow::from(file_path), - "--whole-archive".into(), // needed so `cairo_native__set_costs_builtin` is always available - Cow::from(runtime_library_path), ]); args diff --git a/src/metadata/runtime_bindings.rs b/src/metadata/runtime_bindings.rs index 300e61be0..e81e2427d 100644 --- a/src/metadata/runtime_bindings.rs +++ b/src/metadata/runtime_bindings.rs @@ -9,15 +9,20 @@ use crate::{ utils::BlockExt, }; use melior::{ - dialect::{func, llvm}, + dialect::{llvm, ods}, ir::{ attribute::{FlatSymbolRefAttribute, StringAttribute, TypeAttribute}, - r#type::{FunctionType, IntegerType}, - Attribute, Block, BlockLike, Identifier, Location, Module, OperationRef, Region, Value, + operation::OperationBuilder, + r#type::IntegerType, + Attribute, Block, BlockLike, Location, Module, OperationRef, Region, Value, }, Context, }; -use std::{alloc::Layout, collections::HashSet, ffi::c_int, marker::PhantomData}; +use std::{ + alloc::Layout, + collections::HashSet, + ffi::{c_int, c_void}, +}; #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] enum RuntimeBinding { @@ -40,14 +45,131 @@ enum RuntimeBinding { VtableCheatcode, } +impl RuntimeBinding { + const fn symbol(self) -> &'static str { + match self { + RuntimeBinding::DebugPrint => "cairo_native__libfunc__debug__print", + RuntimeBinding::Pedersen => "cairo_native__libfunc__pedersen", + RuntimeBinding::HadesPermutation => "cairo_native__libfunc__hades_permutation", + RuntimeBinding::EcStateTryFinalizeNz => { + "cairo_native__libfunc__ec__ec_state_try_finalize_nz" + } + RuntimeBinding::EcStateAddMul => "cairo_native__libfunc__ec__ec_state_add_mul", + RuntimeBinding::EcStateInit => "cairo_native__libfunc__ec__ec_state_init", + RuntimeBinding::EcStateAdd => "cairo_native__libfunc__ec__ec_state_add", + RuntimeBinding::EcPointTryNewNz => "cairo_native__libfunc__ec__ec_point_try_new_nz", + RuntimeBinding::EcPointFromXNz => "cairo_native__libfunc__ec__ec_point_from_x_nz", + RuntimeBinding::DictNew => "cairo_native__dict_new", + RuntimeBinding::DictGet => "cairo_native__dict_get", + RuntimeBinding::DictGasRefund => "cairo_native__dict_gas_refund", + RuntimeBinding::DictDrop => "cairo_native__dict_drop", + RuntimeBinding::DictDup => "cairo_native__dict_dup", + RuntimeBinding::GetGasBuiltin => "cairo_native__get_costs_builtin", + #[cfg(feature = "with-cheatcode")] + RuntimeBinding::VtableCheatcode => "cairo_native__vtable_cheatcode", + } + } + + const fn function_ptr(self) -> *const () { + match self { + RuntimeBinding::DebugPrint => { + cairo_native_runtime::cairo_native__libfunc__debug__print as *const () + } + RuntimeBinding::Pedersen => { + cairo_native_runtime::cairo_native__libfunc__pedersen as *const () + } + RuntimeBinding::HadesPermutation => { + cairo_native_runtime::cairo_native__libfunc__hades_permutation as *const () + } + RuntimeBinding::EcStateTryFinalizeNz => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_state_try_finalize_nz + as *const () + } + RuntimeBinding::EcStateAddMul => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_state_add_mul as *const () + } + RuntimeBinding::EcStateInit => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_state_init as *const () + } + RuntimeBinding::EcStateAdd => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_state_add as *const () + } + RuntimeBinding::EcPointTryNewNz => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_point_try_new_nz as *const () + } + RuntimeBinding::EcPointFromXNz => { + cairo_native_runtime::cairo_native__libfunc__ec__ec_point_from_x_nz as *const () + } + RuntimeBinding::DictNew => cairo_native_runtime::cairo_native__dict_new as *const (), + RuntimeBinding::DictGet => cairo_native_runtime::cairo_native__dict_get as *const (), + RuntimeBinding::DictGasRefund => { + cairo_native_runtime::cairo_native__dict_gas_refund as *const () + } + RuntimeBinding::DictDrop => cairo_native_runtime::cairo_native__dict_drop as *const (), + RuntimeBinding::DictDup => cairo_native_runtime::cairo_native__dict_dup as *const (), + RuntimeBinding::GetGasBuiltin => { + cairo_native_runtime::cairo_native__get_costs_builtin as *const () + } + #[cfg(feature = "with-cheatcode")] + RuntimeBinding::VtableCheatcode => { + crate::starknet::cairo_native__vtable_cheatcode as *const () + } + } + } +} + /// Runtime library bindings metadata. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct RuntimeBindingsMeta { active_map: HashSet, - phantom: PhantomData<()>, } impl RuntimeBindingsMeta { + /// Register the global for the given binding, if not yet registered, and return + /// a pointer to the stored function. + /// + /// For the function to be available, `setup_runtime` must be called before running the module + fn build_function<'c, 'a>( + &mut self, + context: &'c Context, + module: &Module, + block: &'a Block<'c>, + location: Location<'c>, + binding: RuntimeBinding, + ) -> Result> { + if self.active_map.insert(binding) { + module.body().append_operation( + ods::llvm::mlir_global( + context, + Region::new(), + TypeAttribute::new(llvm::r#type::pointer(context, 0)), + StringAttribute::new(context, binding.symbol()), + Attribute::parse(context, "#llvm.linkage") + .ok_or(Error::ParseAttributeError)?, + location, + ) + .into(), + ); + } + + let global_address = block.append_op_result( + ods::llvm::mlir_addressof( + context, + llvm::r#type::pointer(context, 0), + FlatSymbolRefAttribute::new(context, binding.symbol()), + location, + ) + .into(), + )?; + + block.load( + context, + location, + global_address, + llvm::r#type::pointer(context, 0), + ) + } + /// Register if necessary, then invoke the `debug::print()` function. #[allow(clippy::too_many_arguments)] pub fn libfunc_debug_print<'c, 'a>( @@ -63,46 +185,17 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::DebugPrint) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__debug__print"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - IntegerType::new(context, 32).into(), - llvm::r#type::pointer(context, 0), - IntegerType::new(context, 32).into(), - ], - &[IntegerType::new(context, 32).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } + let function = + self.build_function(context, module, block, location, RuntimeBinding::DebugPrint)?; Ok(block - .append_operation(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__debug__print"), - &[target_fd, values_ptr, values_len], - &[IntegerType::new(context, 32).into()], - location, - )) + .append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[target_fd, values_ptr, values_len]) + .add_results(&[IntegerType::new(context, 32).into()]) + .build()?, + ) .result(0)? .into()) } @@ -122,45 +215,15 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::Pedersen) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__pedersen"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__pedersen"), - &[dst_ptr, lhs_ptr, rhs_ptr], - &[], - location, - ))) + let function = + self.build_function(context, module, block, location, RuntimeBinding::Pedersen)?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[dst_ptr, lhs_ptr, rhs_ptr]) + .build()?, + )) } /// Register if necessary, then invoke the `poseidon()` function. @@ -179,45 +242,20 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::HadesPermutation) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__hades_permutation"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__hades_permutation"), - &[op0_ptr, op1_ptr, op2_ptr], - &[], + module, + block, location, - ))) + RuntimeBinding::HadesPermutation, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[op0_ptr, op1_ptr, op2_ptr]) + .build()?, + )) } /// Register if necessary, then invoke the `ec_point_from_x_nz()` function. @@ -232,41 +270,21 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcPointFromXNz) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__ec__ec_point_from_x_nz"), - TypeAttribute::new( - FunctionType::new( - context, - &[llvm::r#type::pointer(context, 0)], - &[IntegerType::new(context, 1).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_point_from_x_nz"), - &[point_ptr], - &[IntegerType::new(context, 1).into()], + module, + block, location, - ))) + RuntimeBinding::EcPointFromXNz, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[point_ptr]) + .add_results(&[IntegerType::new(context, 1).into()]) + .build()?, + )) } /// Register if necessary, then invoke the `ec_point_try_new_nz()` function. @@ -281,41 +299,21 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcPointTryNewNz) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__ec__ec_point_try_new_nz"), - TypeAttribute::new( - FunctionType::new( - context, - &[llvm::r#type::pointer(context, 0)], - &[IntegerType::new(context, 1).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_point_try_new_nz"), - &[point_ptr], - &[IntegerType::new(context, 1).into()], + module, + block, location, - ))) + RuntimeBinding::EcPointTryNewNz, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[point_ptr]) + .add_results(&[IntegerType::new(context, 1).into()]) + .build()?, + )) } /// Register if necessary, then invoke the `ec_state_init()` function. @@ -330,36 +328,20 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcStateInit) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__ec__ec_state_init"), - TypeAttribute::new( - FunctionType::new(context, &[llvm::r#type::pointer(context, 0)], &[]).into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_state_init"), - &[state_ptr], - &[], + module, + block, location, - ))) + RuntimeBinding::EcStateInit, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[state_ptr]) + .build()?, + )) } /// Register if necessary, then invoke the `ec_state_add()` function. @@ -375,44 +357,15 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcStateAdd) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__ec__ec_state_add"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_state_add"), - &[state_ptr, point_ptr], - &[], - location, - ))) + let function = + self.build_function(context, module, block, location, RuntimeBinding::EcStateAdd)?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[state_ptr, point_ptr]) + .build()?, + )) } /// Register if necessary, then invoke the `ec_state_add_mul()` function. @@ -430,45 +383,20 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcStateAddMul) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__libfunc__ec__ec_state_add_mul"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_state_add_mul"), - &[state_ptr, scalar_ptr, point_ptr], - &[], + module, + block, location, - ))) + RuntimeBinding::EcStateAddMul, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[state_ptr, scalar_ptr, point_ptr]) + .build()?, + )) } pub fn libfunc_ec_state_try_finalize_nz<'c, 'a>( @@ -483,50 +411,21 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::EcStateTryFinalizeNz) { - module.body().append_operation(func::func( - context, - StringAttribute::new( - context, - "cairo_native__libfunc__ec__ec_state_try_finalize_nz", - ), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[IntegerType::new(context, 1).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - location, - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new( - context, - "cairo_native__libfunc__ec__ec_state_try_finalize_nz", - ), - &[point_ptr, state_ptr], - &[IntegerType::new(context, 1).into()], + module, + block, location, - ))) + RuntimeBinding::EcStateTryFinalizeNz, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[point_ptr, state_ptr]) + .add_results(&[IntegerType::new(context, 1).into()]) + .build()?, + )) } /// Register if necessary, then invoke the `dict_alloc_new()` function. @@ -546,41 +445,10 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - let i64_ty = IntegerType::new(context, 64).into(); - - if self.active_map.insert(RuntimeBinding::DictNew) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__dict_new"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - i64_ty, - i64_ty, - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[llvm::r#type::pointer(context, 0)], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } + let function = + self.build_function(context, module, block, location, RuntimeBinding::DictNew)?; + let i64_ty = IntegerType::new(context, 64).into(); let size = block.const_int_from_type(context, location, layout.size(), i64_ty)?; let align = block.const_int_from_type(context, location, layout.align(), i64_ty)?; @@ -597,13 +465,13 @@ impl RuntimeBindingsMeta { } }; - block.append_op_result(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__dict_new"), - &[size, align, dup_fn, drop_fn], - &[llvm::r#type::pointer(context, 0)], - location, - )) + block.append_op_result( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[size, align, dup_fn, drop_fn]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + ) } /// Register if necessary, then invoke the `dict_alloc_new()` function. @@ -621,36 +489,15 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::DictDrop) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__dict_drop"), - TypeAttribute::new( - FunctionType::new(context, &[llvm::r#type::pointer(context, 0)], &[]).into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__dict_drop"), - &[ptr], - &[], - location, - ))) + let function = + self.build_function(context, module, block, location, RuntimeBinding::DictDrop)?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[ptr]) + .build()?, + )) } /// Register if necessary, then invoke the `dict_alloc_new()` function. @@ -668,41 +515,16 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::DictDup) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__dict_dup"), - TypeAttribute::new( - FunctionType::new( - context, - &[llvm::r#type::pointer(context, 0)], - &[llvm::r#type::pointer(context, 0)], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - block.append_op_result(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__dict_dup"), - &[ptr], - &[llvm::r#type::pointer(context, 0)], - location, - )) + let function = + self.build_function(context, module, block, location, RuntimeBinding::DictDup)?; + + block.append_op_result( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[ptr]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + ) } /// Register if necessary, then invoke the `dict_get()` function. @@ -723,37 +545,8 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::DictGet) { - helper.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__dict_get"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[IntegerType::new(context, c_int::BITS).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } + let function = + self.build_function(context, helper, block, location, RuntimeBinding::DictGet)?; let value_ptr = helper.init_block().alloca1( context, @@ -762,13 +555,13 @@ impl RuntimeBindingsMeta { align_of::<*mut ()>(), )?; - let is_present = block.append_op_result(func::call( - context, - FlatSymbolRefAttribute::new(context, "cairo_native__dict_get"), - &[dict_ptr, key_ptr, value_ptr], - &[IntegerType::new(context, c_int::BITS).into()], - location, - ))?; + let is_present = block.append_op_result( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[dict_ptr, key_ptr, value_ptr]) + .add_results(&[IntegerType::new(context, c_int::BITS).into()]) + .build()?, + )?; let value_ptr = block.load( context, @@ -797,41 +590,21 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::DictGasRefund) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__dict_gas_refund"), - TypeAttribute::new( - FunctionType::new( - context, - &[llvm::r#type::pointer(context, 0)], - &[IntegerType::new(context, 64).into()], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__dict_gas_refund"), - &[dict_ptr], - &[IntegerType::new(context, 64).into()], + module, + block, location, - ))) + RuntimeBinding::DictGasRefund, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[dict_ptr]) + .add_results(&[IntegerType::new(context, 64).into()]) + .build()?, + )) } // Register if necessary, then invoke the `set_gas_builtin()` function. @@ -846,36 +619,20 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::GetGasBuiltin) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__get_costs_builtin"), - TypeAttribute::new( - FunctionType::new(context, &[], &[llvm::r#type::pointer(context, 0)]).into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__get_costs_builtin"), - &[], - &[llvm::r#type::pointer(context, 0)], + module, + block, location, - ))) + RuntimeBinding::GetGasBuiltin, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + )) } /// Register if necessary, then invoke the `vtable_cheatcode()` runtime function. @@ -898,53 +655,47 @@ impl RuntimeBindingsMeta { where 'c: 'a, { - if self.active_map.insert(RuntimeBinding::VtableCheatcode) { - module.body().append_operation(func::func( - context, - StringAttribute::new(context, "cairo_native__vtable_cheatcode"), - TypeAttribute::new( - FunctionType::new( - context, - &[ - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - llvm::r#type::pointer(context, 0), - ], - &[], - ) - .into(), - ), - Region::new(), - &[ - ( - Identifier::new(context, "sym_visibility"), - StringAttribute::new(context, "private").into(), - ), - ( - Identifier::new(context, "llvm.linkage"), - Attribute::parse(context, "#llvm.linkage") - .ok_or(Error::ParseAttributeError)?, - ), - ], - Location::unknown(context), - )); - } - - Ok(block.append_operation(func::call( + let function = self.build_function( context, - FlatSymbolRefAttribute::new(context, "cairo_native__vtable_cheatcode"), - &[result_ptr, selector_ptr, args], - &[], + module, + block, location, - ))) + RuntimeBinding::VtableCheatcode, + )?; + + Ok(block.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[function]) + .add_operands(&[result_ptr, selector_ptr, args]) + .build()?, + )) } } -impl Default for RuntimeBindingsMeta { - fn default() -> Self { - Self { - active_map: HashSet::new(), - phantom: PhantomData, +pub fn setup_runtime(find_symbol_ptr: impl Fn(&str) -> Option<*mut c_void>) { + for binding in [ + RuntimeBinding::DebugPrint, + RuntimeBinding::Pedersen, + RuntimeBinding::HadesPermutation, + RuntimeBinding::EcStateTryFinalizeNz, + RuntimeBinding::EcStateAddMul, + RuntimeBinding::EcStateInit, + RuntimeBinding::EcStateAdd, + RuntimeBinding::EcPointTryNewNz, + RuntimeBinding::EcPointFromXNz, + RuntimeBinding::DictNew, + RuntimeBinding::DictGet, + RuntimeBinding::DictGasRefund, + RuntimeBinding::DictDrop, + RuntimeBinding::DictDup, + RuntimeBinding::GetGasBuiltin, + RuntimeBinding::DebugPrint, + #[cfg(feature = "with-cheatcode")] + RuntimeBinding::VtableCheatcode, + ] { + if let Some(global) = find_symbol_ptr(binding.symbol()) { + let global = global.cast::<*const ()>(); + unsafe { *global = binding.function_ptr() }; } } } diff --git a/src/utils.rs b/src/utils.rs index 6ac8733c2..bcdb68a16 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -271,10 +271,6 @@ pub fn create_engine( ) -> ExecutionEngine { // Create the JIT engine. let engine = ExecutionEngine::new(module, opt_level.into(), &[], false); - - #[cfg(feature = "with-runtime")] - register_runtime_symbols(&engine); - #[cfg(feature = "with-debug-utils")] _metadata .get::() @@ -296,124 +292,6 @@ pub fn run_pass_manager(context: &Context, module: &mut Module) -> Result<(), Er pass_manager.run(module) } -#[cfg(feature = "with-runtime")] -pub fn register_runtime_symbols(engine: &ExecutionEngine) { - use cairo_native_runtime::FeltDict; - - unsafe { - engine.register_symbol( - "cairo_native__libfunc__debug__print", - cairo_native_runtime::cairo_native__libfunc__debug__print - as *const fn(i32, *const [u8; 32], usize) -> i32 as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__pedersen", - cairo_native_runtime::cairo_native__libfunc__pedersen - as *const fn(*mut u8, *mut u8, *mut u8) -> () as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__hades_permutation", - cairo_native_runtime::cairo_native__libfunc__hades_permutation - as *const fn(*mut u8, *mut u8, *mut u8) -> () as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_point_from_x_nz", - cairo_native_runtime::cairo_native__libfunc__ec__ec_point_from_x_nz - as *const fn(*mut [[u8; 32]; 2]) -> bool as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_state_add", - cairo_native_runtime::cairo_native__libfunc__ec__ec_state_add - as *const fn(*mut [[u8; 32]; 4], *const [[u8; 32]; 2]) -> bool - as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_state_init", - cairo_native_runtime::cairo_native__libfunc__ec__ec_state_init - as *const fn(*mut [[u8; 32]; 4]) as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_state_add_mul", - cairo_native_runtime::cairo_native__libfunc__ec__ec_state_add_mul - as *const fn(*mut [[u8; 32]; 4], *const [u8; 32], *const [[u8; 32]; 2]) -> bool - as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_state_try_finalize_nz", - cairo_native_runtime::cairo_native__libfunc__ec__ec_state_try_finalize_nz - as *const fn(*const [[u8; 32]; 2], *mut [[u8; 32]; 4]) -> bool - as *mut (), - ); - - engine.register_symbol( - "cairo_native__libfunc__ec__ec_point_try_new_nz", - cairo_native_runtime::cairo_native__libfunc__ec__ec_point_try_new_nz - as *const fn(*const [[u8; 32]; 2]) -> bool as *mut (), - ); - - engine.register_symbol( - "cairo_native__dict_new", - cairo_native_runtime::cairo_native__dict_new as *const fn() -> *mut FeltDict as *mut (), - ); - - engine.register_symbol( - "cairo_native__dict_drop", - cairo_native_runtime::cairo_native__dict_drop - as *const fn(*mut FeltDict, Option) -> () - as *mut (), - ); - - engine.register_symbol( - "cairo_native__dict_dup", - cairo_native_runtime::cairo_native__dict_dup - as *const fn( - *mut FeltDict, - extern "C" fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void, - ) -> *mut FeltDict as *mut (), - ); - - engine.register_symbol( - "cairo_native__dict_get", - cairo_native_runtime::cairo_native__dict_get - as *const fn(*mut FeltDict, &[u8; 32]) -> *mut std::ffi::c_void - as *mut (), - ); - - engine.register_symbol( - "cairo_native__dict_gas_refund", - cairo_native_runtime::cairo_native__dict_gas_refund as *const fn(*const FeltDict) -> u64 - as *mut (), - ); - - engine.register_symbol( - "cairo_native__set_costs_builtin", - cairo_native_runtime::cairo_native__set_costs_builtin as *const fn(*const u64) -> () - as *mut (), - ); - - engine.register_symbol( - "cairo_native__get_costs_builtin", - cairo_native_runtime::cairo_native__get_costs_builtin as *const fn() -> *const u64 - as *mut (), - ); - - #[cfg(feature = "with-cheatcode")] - { - engine.register_symbol( - "cairo_native__vtable_cheatcode", - crate::starknet::cairo_native__vtable_cheatcode as *mut (), - ); - } - } -} - /// Return a type that calls a closure when formatted using [Debug](std::fmt::Debug). pub fn debug_with(fmt: F) -> impl fmt::Debug where