diff --git a/api/examples/echo.rs b/api/examples/echo.rs index 9a40341..94c7303 100644 --- a/api/examples/echo.rs +++ b/api/examples/echo.rs @@ -55,11 +55,11 @@ impl Deserialize for Value { // special case to exercise string interning and get_obj_prop let raw_value = match key.as_str() { "foo" => { - let interned_string_id = FOO_INTERNED_STRING_ID.load_from_value(value); + let interned_string_id = FOO_INTERNED_STRING_ID.load(); value.get_interned_obj_prop(interned_string_id) } "bar" => { - let interned_string_id = BAR_INTERNED_STRING_ID.load_from_value(value); + let interned_string_id = BAR_INTERNED_STRING_ID.load(); value.get_interned_obj_prop(interned_string_id) } "abc" | "def" => value.get_obj_prop(key.as_str()), @@ -94,13 +94,11 @@ impl Serialize for Value { for (key, value) in object { match key.as_str() { "foo" => { - let interned_string_id = - FOO_INTERNED_STRING_ID.load_from_context(ctx); + let interned_string_id = FOO_INTERNED_STRING_ID.load(); ctx.write_interned_utf8_str(interned_string_id)?; } "bar" => { - let interned_string_id = - BAR_INTERNED_STRING_ID.load_from_context(ctx); + let interned_string_id = BAR_INTERNED_STRING_ID.load(); ctx.write_interned_utf8_str(interned_string_id)?; } _ => ctx.write_utf8_str(key)?, @@ -138,20 +136,4 @@ mod tests { assert_eq!(result, Value::Object(Vec::new())); } - - #[test] - fn test_echo_multiple_contexts_with_interned_string_cache() { - // tests the cached interned string logic by having multiple contexts that - // hit the interned string cache - let input = serde_json::json!({ "foo": "bar"}); - let context = Context::new_with_input(input.clone()); - let api_value = context.input_get().unwrap(); - let input_value: Value = Deserialize::deserialize(&api_value).unwrap(); - let result = echo(input_value); - let context2 = Context::new_with_input(input); - let api_value2 = context2.input_get().unwrap(); - let input_value2: Value = Deserialize::deserialize(&api_value2).unwrap(); - let result2 = echo(input_value2); - assert_eq!(result, result2); - } } diff --git a/api/src/lib.rs b/api/src/lib.rs index 699d76b..d5e6f0e 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -20,15 +20,8 @@ #![warn(missing_docs)] -use shopify_function_wasm_api_core::{ - read::{ErrorCode, NanBox, Val, ValueRef}, - ContextPtr, -}; -use std::ptr::NonNull; -#[cfg(target_pointer_width = "32")] -use std::sync::atomic::{AtomicU64, Ordering}; -#[cfg(target_pointer_width = "64")] -use std::sync::Mutex; +use shopify_function_wasm_api_core::read::{ErrorCode, NanBox, Val, ValueRef}; +use std::sync::atomic::{AtomicUsize, Ordering}; pub mod read; pub mod write; @@ -40,145 +33,103 @@ pub use write::Serialize; #[link(wasm_import_module = "shopify_function_v1")] extern "C" { // Common API. - fn shopify_function_context_new() -> ContextPtr; + fn shopify_function_context_new(); // Read API. - fn shopify_function_input_get(context: ContextPtr) -> Val; - fn shopify_function_input_get_val_len(context: ContextPtr, scope: Val) -> usize; - fn shopify_function_input_read_utf8_str( - context: ContextPtr, - src: usize, - out: *mut u8, - len: usize, - ); - fn shopify_function_input_get_obj_prop( - context: ContextPtr, - scope: Val, - ptr: *const u8, - len: usize, - ) -> Val; + fn shopify_function_input_get() -> Val; + fn shopify_function_input_get_val_len(scope: Val) -> usize; + fn shopify_function_input_read_utf8_str(src: usize, out: *mut u8, len: usize); + fn shopify_function_input_get_obj_prop(scope: Val, ptr: *const u8, len: usize) -> Val; fn shopify_function_input_get_interned_obj_prop( - context: ContextPtr, scope: Val, interned_string_id: shopify_function_wasm_api_core::InternedStringId, ) -> Val; - fn shopify_function_input_get_at_index(context: ContextPtr, scope: Val, index: usize) -> Val; - fn shopify_function_input_get_obj_key_at_index( - context: ContextPtr, - scope: Val, - index: usize, - ) -> Val; + fn shopify_function_input_get_at_index(scope: Val, index: usize) -> Val; + fn shopify_function_input_get_obj_key_at_index(scope: Val, index: usize) -> Val; // Write API. - fn shopify_function_output_new_bool(context: ContextPtr, bool: u32) -> usize; - fn shopify_function_output_new_null(context: ContextPtr) -> usize; - fn shopify_function_output_finalize(context: ContextPtr) -> usize; - fn shopify_function_output_new_i32(context: ContextPtr, int: i32) -> usize; - fn shopify_function_output_new_f64(context: ContextPtr, float: f64) -> usize; - fn shopify_function_output_new_utf8_str( - context: ContextPtr, - ptr: *const u8, - len: usize, - ) -> usize; + fn shopify_function_output_new_bool(bool: u32) -> usize; + fn shopify_function_output_new_null() -> usize; + fn shopify_function_output_finalize() -> usize; + fn shopify_function_output_new_i32(int: i32) -> usize; + fn shopify_function_output_new_f64(float: f64) -> usize; + fn shopify_function_output_new_utf8_str(ptr: *const u8, len: usize) -> usize; fn shopify_function_output_new_interned_utf8_str( - context: ContextPtr, id: shopify_function_wasm_api_core::InternedStringId, ) -> usize; - fn shopify_function_output_new_object(context: ContextPtr, len: usize) -> usize; - fn shopify_function_output_finish_object(context: ContextPtr) -> usize; - fn shopify_function_output_new_array(context: ContextPtr, len: usize) -> usize; - fn shopify_function_output_finish_array(context: ContextPtr) -> usize; + fn shopify_function_output_new_object(len: usize) -> usize; + fn shopify_function_output_finish_object() -> usize; + fn shopify_function_output_new_array(len: usize) -> usize; + fn shopify_function_output_finish_array() -> usize; // Other. - fn shopify_function_intern_utf8_str(context: ContextPtr, ptr: *const u8, len: usize) -> usize; + fn shopify_function_intern_utf8_str(ptr: *const u8, len: usize) -> usize; } #[cfg(not(target_family = "wasm"))] mod provider_fallback { - use super::{ContextPtr, Val}; + use super::Val; use shopify_function_wasm_api_core::write::WriteResult; // Read API. - pub(crate) unsafe fn shopify_function_input_get(context: ContextPtr) -> Val { - shopify_function_provider::read::shopify_function_input_get(context) + pub(crate) unsafe fn shopify_function_input_get() -> Val { + shopify_function_provider::read::shopify_function_input_get() } - pub(crate) unsafe fn shopify_function_input_get_val_len( - context: ContextPtr, - scope: Val, - ) -> usize { - shopify_function_provider::read::shopify_function_input_get_val_len(context, scope) + pub(crate) unsafe fn shopify_function_input_get_val_len(scope: Val) -> usize { + shopify_function_provider::read::shopify_function_input_get_val_len(scope) } pub(crate) unsafe fn shopify_function_input_read_utf8_str( - context: ContextPtr, src: usize, out: *mut u8, len: usize, ) { - let src = - shopify_function_provider::read::shopify_function_input_get_utf8_str_addr(context, src); + let src = shopify_function_provider::read::shopify_function_input_get_utf8_str_addr(src); std::ptr::copy(src as _, out, len); } pub(crate) unsafe fn shopify_function_input_get_obj_prop( - context: ContextPtr, scope: Val, ptr: *const u8, len: usize, ) -> Val { - shopify_function_provider::read::shopify_function_input_get_obj_prop( - context, scope, ptr as _, len, - ) + shopify_function_provider::read::shopify_function_input_get_obj_prop(scope, ptr as _, len) } pub(crate) unsafe fn shopify_function_input_get_interned_obj_prop( - context: ContextPtr, scope: Val, interned_string_id: shopify_function_wasm_api_core::InternedStringId, ) -> Val { shopify_function_provider::read::shopify_function_input_get_interned_obj_prop( - context, scope, interned_string_id, ) } - pub(crate) unsafe fn shopify_function_input_get_at_index( - context: ContextPtr, - scope: Val, - index: usize, - ) -> Val { - shopify_function_provider::read::shopify_function_input_get_at_index(context, scope, index) + pub(crate) unsafe fn shopify_function_input_get_at_index(scope: Val, index: usize) -> Val { + shopify_function_provider::read::shopify_function_input_get_at_index(scope, index) } pub(crate) unsafe fn shopify_function_input_get_obj_key_at_index( - context: ContextPtr, scope: Val, index: usize, ) -> Val { - shopify_function_provider::read::shopify_function_input_get_obj_key_at_index( - context, scope, index, - ) + shopify_function_provider::read::shopify_function_input_get_obj_key_at_index(scope, index) } // Write API. - pub(crate) unsafe fn shopify_function_output_new_bool(context: ContextPtr, bool: u32) -> usize { - shopify_function_provider::write::shopify_function_output_new_bool(context, bool) as usize + pub(crate) unsafe fn shopify_function_output_new_bool(bool: u32) -> usize { + shopify_function_provider::write::shopify_function_output_new_bool(bool) as usize } - pub(crate) unsafe fn shopify_function_output_new_null(context: ContextPtr) -> usize { - shopify_function_provider::write::shopify_function_output_new_null(context) as usize + pub(crate) unsafe fn shopify_function_output_new_null() -> usize { + shopify_function_provider::write::shopify_function_output_new_null() as usize } - pub(crate) unsafe fn shopify_function_output_finalize(context: ContextPtr) -> usize { - shopify_function_provider::write::shopify_function_output_finalize(context) as usize + pub(crate) unsafe fn shopify_function_output_finalize() -> usize { + shopify_function_provider::write::shopify_function_output_finalize() as usize } - pub(crate) unsafe fn shopify_function_output_new_i32(context: ContextPtr, int: i32) -> usize { - shopify_function_provider::write::shopify_function_output_new_i32(context, int) as usize + pub(crate) unsafe fn shopify_function_output_new_i32(int: i32) -> usize { + shopify_function_provider::write::shopify_function_output_new_i32(int) as usize } - pub(crate) unsafe fn shopify_function_output_new_f64(context: ContextPtr, float: f64) -> usize { - shopify_function_provider::write::shopify_function_output_new_f64(context, float) as usize + pub(crate) unsafe fn shopify_function_output_new_f64(float: f64) -> usize { + shopify_function_provider::write::shopify_function_output_new_f64(float) as usize } - pub(crate) unsafe fn shopify_function_output_new_utf8_str( - context: ContextPtr, - ptr: *const u8, - len: usize, - ) -> usize { - let result = - shopify_function_provider::write::shopify_function_output_new_utf8_str(context, len); + pub(crate) unsafe fn shopify_function_output_new_utf8_str(ptr: *const u8, len: usize) -> usize { + let result = shopify_function_provider::write::shopify_function_output_new_utf8_str(len); let write_result = (result >> usize::BITS) as usize; let dst = result as usize; if write_result == WriteResult::Ok as usize { @@ -187,38 +138,26 @@ mod provider_fallback { write_result } pub(crate) unsafe fn shopify_function_output_new_interned_utf8_str( - context: ContextPtr, id: shopify_function_wasm_api_core::InternedStringId, ) -> usize { - shopify_function_provider::write::shopify_function_output_new_interned_utf8_str(context, id) - as usize + shopify_function_provider::write::shopify_function_output_new_interned_utf8_str(id) as usize } - pub(crate) unsafe fn shopify_function_output_new_object( - context: ContextPtr, - len: usize, - ) -> usize { - shopify_function_provider::write::shopify_function_output_new_object(context, len) as usize + pub(crate) unsafe fn shopify_function_output_new_object(len: usize) -> usize { + shopify_function_provider::write::shopify_function_output_new_object(len) as usize } - pub(crate) unsafe fn shopify_function_output_finish_object(context: ContextPtr) -> usize { - shopify_function_provider::write::shopify_function_output_finish_object(context) as usize + pub(crate) unsafe fn shopify_function_output_finish_object() -> usize { + shopify_function_provider::write::shopify_function_output_finish_object() as usize } - pub(crate) unsafe fn shopify_function_output_new_array( - context: ContextPtr, - len: usize, - ) -> usize { - shopify_function_provider::write::shopify_function_output_new_array(context, len) as usize + pub(crate) unsafe fn shopify_function_output_new_array(len: usize) -> usize { + shopify_function_provider::write::shopify_function_output_new_array(len) as usize } - pub(crate) unsafe fn shopify_function_output_finish_array(context: ContextPtr) -> usize { - shopify_function_provider::write::shopify_function_output_finish_array(context) as usize + pub(crate) unsafe fn shopify_function_output_finish_array() -> usize { + shopify_function_provider::write::shopify_function_output_finish_array() as usize } // Other. - pub(crate) unsafe fn shopify_function_intern_utf8_str( - context: ContextPtr, - ptr: *const u8, - len: usize, - ) -> usize { - let result = shopify_function_provider::shopify_function_intern_utf8_str(context, len); + pub(crate) unsafe fn shopify_function_intern_utf8_str(ptr: *const u8, len: usize) -> usize { + let result = shopify_function_provider::shopify_function_intern_utf8_str(len); let id = (result >> usize::BITS) as usize; let dst = result as usize; std::ptr::copy(ptr as _, dst as _, len); @@ -243,63 +182,31 @@ impl InternedStringId { /// A mechanism for caching interned string IDs. pub struct CachedInternedStringId { value: &'static str, - #[cfg(target_pointer_width = "32")] - interned_string_id_and_context: AtomicU64, - #[cfg(target_pointer_width = "64")] - interned_string_id_and_context: Mutex<(usize, usize)>, + interned_string_id: AtomicUsize, } +const INITIAL_INTERN_STRING_ID: usize = usize::MAX; + impl CachedInternedStringId { /// Create a new cached interned string ID. pub const fn new(value: &'static str) -> Self { Self { value, - #[cfg(target_pointer_width = "32")] - interned_string_id_and_context: AtomicU64::new(u64::MAX), - #[cfg(target_pointer_width = "64")] - interned_string_id_and_context: Mutex::new((usize::MAX, usize::MAX)), + interned_string_id: AtomicUsize::new(INITIAL_INTERN_STRING_ID), } } - /// Load the interned string ID from a context. - pub fn load_from_context(&self, context: &Context) -> InternedStringId { - self.load_from_context_ptr(context.0) - } - - /// Load the interned string ID from a value. - pub fn load_from_value(&self, value: &Value) -> InternedStringId { - self.load_from_context_ptr(value.context.as_ptr() as _) - } - - #[cfg(target_pointer_width = "32")] - fn load_from_context_ptr(&self, context: ContextPtr) -> InternedStringId { - let interned_string_id_and_context = - self.interned_string_id_and_context.load(Ordering::Relaxed); - if interned_string_id_and_context & (u32::MAX as u64) == context as u64 { - InternedStringId((interned_string_id_and_context >> 32) as usize) + /// Load the interned string ID. + pub fn load(&self) -> InternedStringId { + let interned_string_id = self.interned_string_id.load(Ordering::Relaxed); + if interned_string_id == INITIAL_INTERN_STRING_ID { + let id = + unsafe { shopify_function_intern_utf8_str(self.value.as_ptr(), self.value.len()) }; + self.interned_string_id.store(id, Ordering::Relaxed); + InternedStringId(id) } else { - let id = unsafe { - shopify_function_intern_utf8_str(context, self.value.as_ptr(), self.value.len()) - }; - let interned_string_id_and_context = ((id as u64) << 32) | (context as u64); - self.interned_string_id_and_context - .store(interned_string_id_and_context, Ordering::Relaxed); - InternedStringId(id as usize) - } - } - - #[cfg(target_pointer_width = "64")] - fn load_from_context_ptr(&self, context: ContextPtr) -> InternedStringId { - let mut interned_string_id_and_context = - self.interned_string_id_and_context.lock().unwrap(); - if interned_string_id_and_context.1 != context as usize { - let id = unsafe { - shopify_function_intern_utf8_str(context, self.value.as_ptr(), self.value.len()) - }; - interned_string_id_and_context.0 = id; - interned_string_id_and_context.1 = context as usize; + InternedStringId(interned_string_id) } - InternedStringId(interned_string_id_and_context.0) } } @@ -315,23 +222,19 @@ impl CachedInternedStringId { /// - error #[derive(Copy, Clone)] pub struct Value { - context: NonNull, nan_box: NanBox, } impl Value { fn new_child(&self, nan_box: NanBox) -> Self { - Self { - context: self.context, - nan_box, - } + Self { nan_box } } /// Intern a string. This is just a convenience method equivalent to calling [`Context::intern_utf8_str`], if you don't have a [`Context`] easily accessible. pub fn intern_utf8_str(&self, s: &str) -> InternedStringId { let len = s.len(); let ptr = s.as_ptr(); - let id = unsafe { shopify_function_intern_utf8_str(self.context.as_ptr() as _, ptr, len) }; + let id = unsafe { shopify_function_intern_utf8_str(ptr, len) }; InternedStringId(id) } @@ -361,24 +264,12 @@ impl Value { match self.nan_box.try_decode() { Ok(ValueRef::String { ptr, len }) => { let len = if len == NanBox::MAX_VALUE_LENGTH { - unsafe { - shopify_function_input_get_val_len( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - ) - } + unsafe { shopify_function_input_get_val_len(self.nan_box.to_bits()) } } else { len }; let mut buf = vec![0; len]; - unsafe { - shopify_function_input_read_utf8_str( - self.context.as_ptr() as _, - ptr as _, - buf.as_mut_ptr(), - len, - ) - }; + unsafe { shopify_function_input_read_utf8_str(ptr as _, buf.as_mut_ptr(), len) }; Some(unsafe { String::from_utf8_unchecked(buf) }) } _ => None, @@ -393,12 +284,7 @@ impl Value { /// Get a property from the object. pub fn get_obj_prop(&self, prop: &str) -> Self { let scope = unsafe { - shopify_function_input_get_obj_prop( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - prop.as_ptr(), - prop.len(), - ) + shopify_function_input_get_obj_prop(self.nan_box.to_bits(), prop.as_ptr(), prop.len()) }; self.new_child(NanBox::from_bits(scope)) } @@ -407,7 +293,6 @@ impl Value { pub fn get_interned_obj_prop(&self, interned_string_id: InternedStringId) -> Self { let scope = unsafe { shopify_function_input_get_interned_obj_prop( - self.context.as_ptr() as _, self.nan_box.to_bits(), interned_string_id.as_usize(), ) @@ -425,12 +310,7 @@ impl Value { match self.nan_box.try_decode() { Ok(ValueRef::Array { len, .. }) => { let len = if len == NanBox::MAX_VALUE_LENGTH { - unsafe { - shopify_function_input_get_val_len( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - ) - } + unsafe { shopify_function_input_get_val_len(self.nan_box.to_bits()) } } else { len }; @@ -449,12 +329,7 @@ impl Value { match self.nan_box.try_decode() { Ok(ValueRef::Object { len, .. }) => { let len = if len == NanBox::MAX_VALUE_LENGTH { - unsafe { - shopify_function_input_get_val_len( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - ) - } + unsafe { shopify_function_input_get_val_len(self.nan_box.to_bits()) } } else { len }; @@ -470,13 +345,7 @@ impl Value { /// Get an element from the array or object by its index. pub fn get_at_index(&self, index: usize) -> Self { - let scope = unsafe { - shopify_function_input_get_at_index( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - index, - ) - }; + let scope = unsafe { shopify_function_input_get_at_index(self.nan_box.to_bits(), index) }; self.new_child(NanBox::from_bits(scope)) } @@ -485,11 +354,7 @@ impl Value { match self.nan_box.try_decode() { Ok(ValueRef::Object { .. }) => { let scope = unsafe { - shopify_function_input_get_obj_key_at_index( - self.context.as_ptr() as _, - self.nan_box.to_bits(), - index, - ) + shopify_function_input_get_obj_key_at_index(self.nan_box.to_bits(), index) }; let value = self.new_child(NanBox::from_bits(scope)); value.as_string() @@ -510,7 +375,7 @@ impl Value { /// A context for reading and writing values. /// /// This is created by calling [`Context::new`], and is used to read values from the input and write values to the output. -pub struct Context(ContextPtr); +pub struct Context; /// An error that can occur when creating a [`Context`]. #[derive(Debug)] @@ -542,7 +407,10 @@ impl Context { panic!("Cannot run in non-WASM environment; use `new_with_input` instead"); #[cfg(target_family = "wasm")] - Self(unsafe { shopify_function_context_new() }) + { + unsafe { shopify_function_context_new() }; + Self + } } /// Create a new context from a JSON value, which will be the top-level value of the input. @@ -551,18 +419,16 @@ impl Context { #[cfg(not(target_family = "wasm"))] pub fn new_with_input(input: serde_json::Value) -> Self { let bytes = rmp_serde::to_vec(&input).unwrap(); - Self(shopify_function_provider::shopify_function_context_new_from_msgpack_bytes(bytes)) + shopify_function_provider::shopify_function_context_new_from_msgpack_bytes(bytes); + Self } /// Get the top-level value of the input. pub fn input_get(&self) -> Result { - let val = unsafe { shopify_function_input_get(self.0) }; - NonNull::new(self.0 as _) - .ok_or(ContextError::NullPointer) - .map(|context| Value { - context, - nan_box: NanBox::from_bits(val), - }) + let val = unsafe { shopify_function_input_get() }; + Ok(Value { + nan_box: NanBox::from_bits(val), + }) } /// Intern a string. This can lead to performance gains if you are using the same string multiple times, @@ -571,7 +437,7 @@ impl Context { pub fn intern_utf8_str(&self, s: &str) -> InternedStringId { let len = s.len(); let ptr = s.as_ptr(); - let id = unsafe { shopify_function_intern_utf8_str(self.0 as _, ptr, len) }; + let id = unsafe { shopify_function_intern_utf8_str(ptr, len) }; InternedStringId(id) } } @@ -589,25 +455,16 @@ mod tests { #[test] fn test_interned_string_id_cache() { let cached_interned_string_id = CachedInternedStringId::new("test"); - - let context = Context::new_with_input(serde_json::json!({})); - let id = cached_interned_string_id.load_from_context(&context); - let id2 = cached_interned_string_id.load_from_context(&context); + Context::new_with_input(serde_json::json!({})); + let id = cached_interned_string_id.load(); + let id2 = cached_interned_string_id.load(); assert_eq!(id, id2); - - let context2 = Context::new_with_input(serde_json::json!({})); - // the first interned string ID from a new context is always 0, - // so we need to mix up the order of interning to make this test work - context2.intern_utf8_str("test"); - let id3 = cached_interned_string_id.load_from_context(&context2); - assert_ne!(id, id3); } #[test] fn test_array_len_with_null_ptr() { - let context = Context::new_with_input(serde_json::json!({})); + Context::new_with_input(serde_json::json!({})); let value = Value { - context: NonNull::new(context.0 as _).unwrap(), nan_box: NanBox::array(0, NanBox::MAX_VALUE_LENGTH), }; let len = value.array_len(); @@ -616,9 +473,8 @@ mod tests { #[test] fn test_array_len_with_non_length_eligible_nan_box() { - let context = Context::new_with_input(serde_json::json!({})); + Context::new_with_input(serde_json::json!({})); let value = Value { - context: NonNull::new(context.0 as _).unwrap(), nan_box: NanBox::null(), }; let len = value.array_len(); @@ -627,9 +483,8 @@ mod tests { #[test] fn test_obj_len_with_null_ptr() { - let context = Context::new_with_input(serde_json::json!({})); + Context::new_with_input(serde_json::json!({})); let value = Value { - context: NonNull::new(context.0 as _).unwrap(), nan_box: NanBox::obj(0, NanBox::MAX_VALUE_LENGTH), }; let len = value.obj_len(); @@ -638,9 +493,8 @@ mod tests { #[test] fn test_obj_len_with_non_length_eligible_nan_box() { - let context = Context::new_with_input(serde_json::json!({})); + Context::new_with_input(serde_json::json!({})); let value = Value { - context: NonNull::new(context.0 as _).unwrap(), nan_box: NanBox::null(), }; let len = value.obj_len(); diff --git a/api/src/shopify_function.h b/api/src/shopify_function.h index 8903d01..1159c73 100644 --- a/api/src/shopify_function.h +++ b/api/src/shopify_function.h @@ -5,7 +5,6 @@ #include // Type definitions -typedef int32_t ContextPtr; typedef int64_t Val; typedef int32_t WriteResult; typedef size_t InternedStringId; @@ -20,46 +19,41 @@ typedef size_t InternedStringId; // Common API /** * Creates a new context for the Shopify Function execution - * @return A new context pointer */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_context_new"))) -extern ContextPtr shopify_function_context_new(void); +extern void shopify_function_context_new(void); // Read API /** * Gets the input value from the context - * @param context The context pointer * @return The input value */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get"))) -extern Val shopify_function_input_get(ContextPtr context); +extern Val shopify_function_input_get(); /** * Gets the length of a value (for arrays, objects, or strings) - * @param context The context pointer * @param scope The value to get the length of * @return The length of the value */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get_val_len"))) -extern size_t shopify_function_input_get_val_len(ContextPtr context, Val scope); +extern size_t shopify_function_input_get_val_len(Val scope); /** * Reads a UTF-8 encoded string from the input into the provided buffer - * @param context The context pointer * @param src The source address of the string * @param out The output buffer to write the string to * @param len The length of the string */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_read_utf8_str"))) -extern void shopify_function_input_read_utf8_str(ContextPtr context, size_t src, uint8_t* out, size_t len); +extern void shopify_function_input_read_utf8_str(size_t src, uint8_t* out, size_t len); /** * Gets an object property by name - * @param context The context pointer * @param scope The object to get the property from * @param ptr The property name (as a UTF-8 string) * @param len The length of the property name @@ -67,159 +61,144 @@ extern void shopify_function_input_read_utf8_str(ContextPtr context, size_t src, */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get_obj_prop"))) -extern Val shopify_function_input_get_obj_prop(ContextPtr context, Val scope, const uint8_t* ptr, size_t len); +extern Val shopify_function_input_get_obj_prop(Val scope, const uint8_t* ptr, size_t len); /** * Gets an object property by interned string ID - * @param context The context pointer * @param scope The object to get the property from * @param interned_string_id The interned string ID of the property name * @return The property value */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get_interned_obj_prop"))) -extern Val shopify_function_input_get_interned_obj_prop(ContextPtr context, Val scope, InternedStringId interned_string_id); +extern Val shopify_function_input_get_interned_obj_prop(Val scope, InternedStringId interned_string_id); /** * Gets an element from an array by index - * @param context The context pointer * @param scope The array to get the element from * @param index The index of the element * @return The element value */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get_at_index"))) -extern Val shopify_function_input_get_at_index(ContextPtr context, Val scope, size_t index); +extern Val shopify_function_input_get_at_index(Val scope, size_t index); /** * Gets an object key at the specified index - * @param context The context pointer * @param scope The object to get the key from * @param index The index of the key * @return The key value (as a string) */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_input_get_obj_key_at_index"))) -extern Val shopify_function_input_get_obj_key_at_index(ContextPtr context, Val scope, size_t index); +extern Val shopify_function_input_get_obj_key_at_index(Val scope, size_t index); // Write API /** * Creates a new boolean output value - * @param context The context pointer * @param value The boolean value (0 for false, non-zero for true) * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_bool"))) -extern WriteResult shopify_function_output_new_bool(ContextPtr context, uint32_t value); +extern WriteResult shopify_function_output_new_bool(uint32_t value); /** * Creates a new null output value - * @param context The context pointer * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_null"))) -extern WriteResult shopify_function_output_new_null(ContextPtr context); +extern WriteResult shopify_function_output_new_null(); /** * Finalizes the output and returns the result - * @param context The context pointer * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_finalize"))) -extern WriteResult shopify_function_output_finalize(ContextPtr context); +extern WriteResult shopify_function_output_finalize(); /** * Creates a new 32-bit integer output value - * @param context The context pointer * @param value The integer value * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_i32"))) -extern WriteResult shopify_function_output_new_i32(ContextPtr context, int32_t value); +extern WriteResult shopify_function_output_new_i32(int32_t value); /** * Creates a new 64-bit float output value - * @param context The context pointer * @param value The float value * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_f64"))) -extern WriteResult shopify_function_output_new_f64(ContextPtr context, double value); +extern WriteResult shopify_function_output_new_f64(double value); /** * Creates a new UTF-8 string output value - * @param context The context pointer * @param ptr The string data * @param len The length of the string * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_utf8_str"))) -extern WriteResult shopify_function_output_new_utf8_str(ContextPtr context, const uint8_t* ptr, size_t len); +extern WriteResult shopify_function_output_new_utf8_str(const uint8_t* ptr, size_t len); /** * Creates a new UTF-8 string output value from an interned string ID - * @param context The context pointer * @param id The interned string ID * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_interned_utf8_str"))) -extern WriteResult shopify_function_output_new_interned_utf8_str(ContextPtr context, InternedStringId id); +extern WriteResult shopify_function_output_new_interned_utf8_str(InternedStringId id); /** * Creates a new object output value with the specified number of properties - * @param context The context pointer * @param len The number of properties * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_object"))) -extern WriteResult shopify_function_output_new_object(ContextPtr context, size_t len); +extern WriteResult shopify_function_output_new_object(size_t len); /** * Finalizes an object output value - * @param context The context pointer * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_finish_object"))) -extern WriteResult shopify_function_output_finish_object(ContextPtr context); +extern WriteResult shopify_function_output_finish_object(); /** * Creates a new array output value with the specified length - * @param context The context pointer * @param len The length of the array * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_new_array"))) -extern WriteResult shopify_function_output_new_array(ContextPtr context, size_t len); +extern WriteResult shopify_function_output_new_array(size_t len); /** * Finalizes an array output value - * @param context The context pointer * @return WriteResult indicating success or failure */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_output_finish_array"))) -extern WriteResult shopify_function_output_finish_array(ContextPtr context); +extern WriteResult shopify_function_output_finish_array(); // Other /** * Interns a UTF-8 string and returns its ID for efficient reuse - * @param context The context pointer * @param ptr The string data * @param len The length of the string * @return The interned string ID */ __attribute__((import_module(SHOPIFY_FUNCTION_IMPORT_MODULE))) __attribute__((import_name("shopify_function_intern_utf8_str"))) -extern InternedStringId shopify_function_intern_utf8_str(ContextPtr context, const uint8_t* ptr, size_t len); +extern InternedStringId shopify_function_intern_utf8_str(const uint8_t* ptr, size_t len); #endif // SHOPIFY_FUNCTION_H diff --git a/api/src/shopify_function.wat b/api/src/shopify_function.wat index 0fb7d9f..62c6308 100644 --- a/api/src/shopify_function.wat +++ b/api/src/shopify_function.wat @@ -11,16 +11,9 @@ ;; ;; The context represents an isolated scope in which values and state ;; are bound. Every API call operates within this context, ensuring - ;; that the execution environment remains distinct and independent - ;; The returned context handle is used in all subsequent function - ;; calls. - ;; - ;; Returns - ;; - i32 representing the handdle to the new Context. - ;; Errors - ;; - Returns 0 if the Context creation fails. + ;; that the execution environment remains distinct and independent. (import "shopify_function_v1" "shopify_function_context_new" - (func (result i32)) + (func) ) ;; Read API Functions - Used to access input data. @@ -29,12 +22,10 @@ ;; This is the main entry point for accessing input data. ;; Returns a NanBox representing a complex object structure. ;; The resulting value can be traversed using the other input API functions. - ;; Parameters: - ;; - context: i32 pointer to the context. ;; Returns: ;; - NanBox value representing the root input value. (import "shopify_function_v1" "shopify_function_input_get" - (func (param $context i32) (result i64)) + (func (result i64)) ) ;; Retrieve the length of a string, array, or object value. @@ -50,12 +41,11 @@ ;; representation. ;; ;; Parameters - ;; - context: Context handle. ;; - scope: NaNBox encoded value. ;; Returns ;; - The value length. (import "shopify_function_v1" "shopify_function_input_get_val_len" - (func (param $context i32) (param $scope i64) (result i32)) + (func (param $scope i64) (result i32)) ) ;; Reads a UTF-8 encoded string from source memory into destination buffer. @@ -63,26 +53,24 @@ ;; The caller must allocate a buffer of sufficient size. ;; No return value - the string is copied directly into the provided buffer. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - src: i32 memory address of the string. ;; - out: i32 pointer to the destination buffer. ;; - len: i32 length of the string in bytes. (import "shopify_function_v1" "shopify_function_input_read_utf8_str" - (func (param $context i32) (param $src i32) (param $out i32) (param $len i32)) + (func (param $src i32) (param $out i32) (param $len i32)) ) ;; Gets a property from an object by name. ;; If property doesn't exist, returns a NanBox null value. ;; See `shopify_function_input_get_interned_obj_prop` for more efficient lookups involving the same property name. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - scope: i64 NanBox value of the object. ;; - ptr: i32 pointer to the property name string. ;; - len: i32 length of the property name in bytes. ;; Returns: ;; - i64 NanBox value of the property. (import "shopify_function_v1" "shopify_function_input_get_obj_prop" - (func (param $context i32) (param $scope i64) (param $ptr i32) (param $len i32) (result i64)) + (func (param $scope i64) (param $ptr i32) (param $len i32) (result i64)) ) ;; Gets a property from an object using a pre-interned string ID. @@ -90,18 +78,16 @@ ;; Uses string interning to reduce overhead of property name lookups. ;; Recommended when accessing the same property on multiple objects. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - scope: i64 NanBox value of the object. ;; - interned_string_id: i32 ID of the interned string. ;; Returns: ;; - i64 NanBox value of the property. (import "shopify_function_v1" "shopify_function_input_get_interned_obj_prop" - (func (param $context i32) (param $scope i64) (param $interned_string_id i32) (result i64)) + (func (param $scope i64) (param $interned_string_id i32) (result i64)) ) ;; Gets a value at specified index from an array or object. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - scope: i64 NanBox value of the array. ;; - index: i32 index to retrieve (zero-based). ;; Returns: @@ -109,13 +95,12 @@ ;; Errors: ;; - If index is out of bounds, returns a NanBox with ErrorCode::IndexOutOfBounds. (import "shopify_function_v1" "shopify_function_input_get_at_index" - (func (param $context i32) (param $scope i64) (param $index i32) (result i64)) + (func (param $scope i64) (param $index i32) (result i64)) ) ;; Gets a key name at specified index from an object. ;; Used for dynamic iteration of object keys by index. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - scope: i64 NanBox value of the object. ;; - index: i32 index of the key to retrieve (zero-based). ;; Returns: @@ -123,7 +108,7 @@ ;; Errors: ;; - If index is out of bounds, returns a NanBox with ErrorCode::IndexOutOfBounds. (import "shopify_function_v1" "shopify_function_input_get_obj_key_at_index" - (func (param $context i32) (param $scope i64) (param $index i32) (result i64)) + (func (param $scope i64) (param $index i32) (result i64)) ) ;; Write API Functions - Used to build response data to return from the function. @@ -132,84 +117,75 @@ ;; Used to add boolean values to the output object/array being constructed. ;; Part of building structured output data. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - value: i32 boolean value (0 = false, 1 = true). ;; Returns: ;; - i32 status code indicating success or failure (import "shopify_function_v1" "shopify_function_output_new_bool" - (func (param $context i32) (param $value i32) (result i32)) + (func (param $value i32) (result i32)) ) ;; Writes a new null output value. ;; Used to explicitly indicate null/absence of value in response. ;; Different from omitting a property. - ;; Parameters: - ;; - context: i32 pointer to the context. ;; Returns: ;; - i32 status code indicating success or failure (import "shopify_function_v1" "shopify_function_output_new_null" - (func (param $context i32) (result i32)) + (func (result i32)) ) ;; Finalizes the output, making it available to the host. ;; Must be called after output construction is complete. ;; This is typically the last API call made before function returns. ;; Signals that the response is complete and ready to be used. - ;; Parameters: - ;; - context: i32 pointer to the context. ;; Returns: ;; - i32 status code indicating success or failure (import "shopify_function_v1" "shopify_function_output_finalize" - (func (param $context i32) (result i32)) + (func (result i32)) ) ;; Writes a new integer output value. ;; Used for numeric values that fit within 32 bits. ;; More efficient than f64 for integral values. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - value: i32 integer value. ;; Returns: ;; - i32 status code indicating success or failure (import "shopify_function_v1" "shopify_function_output_new_i32" - (func (param $context i32) (param $value i32) (result i32)) + (func (param $value i32) (result i32)) ) ;; Writes a new floating point output value. ;; Used for decimal or large numeric values. ;; Provides full IEEE 754 double precision. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - value: f64 floating point value. ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_new_f64" - (func (param $context i32) (param $value f64) (result i32)) + (func (param $value f64) (result i32)) ) ;; Writes a new string output value. ;; Used for text values in the response. ;; The string data is copied from WebAssembly memory. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - ptr: i32 pointer to string data in WebAssembly memory. ;; - len: i32 length of string in bytes. ;; Returns: ;; - i32 status code indicating success or failure (import "shopify_function_v1" "shopify_function_output_new_utf8_str" - (func (param $context i32) (param $ptr i32) (param $len i32) (result i32)) + (func (param $ptr i32) (param $len i32) (result i32)) ) ;; Writes a new string output value from an interned string. ;; More efficient than direct string when reusing string values. ;; Especially useful for repetitive property names. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - id: i32 ID of the interned string from shopify_function_intern_utf8_str. ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_new_interned_utf8_str" - (func (param $context i32) (param $id i32) (result i32)) + (func (param $id i32) (result i32)) ) ;; Initializes a new object output value. @@ -217,23 +193,20 @@ ;; Properties are added using alternating key/value calls to write API functions. ;; Object construction follows a builder pattern. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - len: i32 number of properties in the object (key-value pairs). ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_new_object" - (func (param $context i32) (param $len i32) (result i32)) + (func (param $len i32) (result i32)) ) ;; Finalizes an object output value. ;; Must be called after adding all properties to the object. ;; Validates that the correct number of properties were added. - ;; Parameters: - ;; - context: i32 pointer to the context. ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_finish_object" - (func (param $context i32) (result i32)) + (func (result i32)) ) ;; Initializes a new array output value. @@ -241,23 +214,20 @@ ;; Elements are added using sequential calls to write API functions. ;; Array construction follows a builder pattern. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - len: i32 number of elements in the array. ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_new_array" - (func (param $context i32) (param $len i32) (result i32)) + (func (param $len i32) (result i32)) ) ;; Finalizes an array output value. ;; Must be called after adding all elements to the array. ;; Validates that the correct number of elements were added. - ;; Parameters: - ;; - context: i32 pointer to the context. ;; Returns: ;; - i32 status code indicating success or failure. (import "shopify_function_v1" "shopify_function_output_finish_array" - (func (param $context i32) (result i32)) + (func (result i32)) ) ;; Other Functions @@ -269,12 +239,11 @@ ;; Note: Each call to this function is going to return a new interned string ID even if the same string is passed in. ;; Its the caller's responsibility to ensure that the same string is interned only once. ;; Parameters: - ;; - context: i32 pointer to the context. ;; - ptr: i32 pointer to string data in WebAssembly memory. ;; - len: i32 length of string in bytes. ;; Returns: ;; - i32 ID of the interned string (to be used in other API calls). (import "shopify_function_v1" "shopify_function_intern_utf8_str" - (func (param $context i32) (param $ptr i32) (param $len i32) (result i32)) + (func (param $ptr i32) (param $len i32) (result i32)) ) ) diff --git a/api/src/test_data/header_test.wasm b/api/src/test_data/header_test.wasm index 09e601c..057e77e 100755 Binary files a/api/src/test_data/header_test.wasm and b/api/src/test_data/header_test.wasm differ diff --git a/api/src/write.rs b/api/src/write.rs index 73ca593..147cf25 100644 --- a/api/src/write.rs +++ b/api/src/write.rs @@ -61,36 +61,34 @@ fn map_result(result: usize) -> Result<(), Error> { impl Context { /// Write a boolean value. pub fn write_bool(&mut self, value: bool) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_bool(self.0 as _, value as u32) }) + map_result(unsafe { crate::shopify_function_output_new_bool(value as u32) }) } /// Write a null value. pub fn write_null(&mut self) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_null(self.0 as _) }) + map_result(unsafe { crate::shopify_function_output_new_null() }) } /// Write an i32 value. pub fn write_i32(&mut self, value: i32) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_i32(self.0 as _, value) }) + map_result(unsafe { crate::shopify_function_output_new_i32(value) }) } /// Write a f64 value. pub fn write_f64(&mut self, value: f64) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_f64(self.0 as _, value) }) + map_result(unsafe { crate::shopify_function_output_new_f64(value) }) } /// Write a UTF-8 string value. pub fn write_utf8_str(&mut self, value: &str) -> Result<(), Error> { map_result(unsafe { - crate::shopify_function_output_new_utf8_str(self.0 as _, value.as_ptr(), value.len()) + crate::shopify_function_output_new_utf8_str(value.as_ptr(), value.len()) }) } /// Write an interned UTF-8 string value. pub fn write_interned_utf8_str(&mut self, id: InternedStringId) -> Result<(), Error> { - map_result(unsafe { - crate::shopify_function_output_new_interned_utf8_str(self.0 as _, id.as_usize()) - }) + map_result(unsafe { crate::shopify_function_output_new_interned_utf8_str(id.as_usize()) }) } /// Write an object. You must provide the exact number of key-value pairs you will write. @@ -99,9 +97,9 @@ impl Context { f: F, len: usize, ) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_object(self.0 as _, len) })?; + map_result(unsafe { crate::shopify_function_output_new_object(len) })?; f(self)?; - map_result(unsafe { crate::shopify_function_output_finish_object(self.0 as _) }) + map_result(unsafe { crate::shopify_function_output_finish_object() }) } /// Write an array. You must provide the exact number of values you will write. @@ -110,21 +108,21 @@ impl Context { f: F, len: usize, ) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_new_array(self.0 as _, len) })?; + map_result(unsafe { crate::shopify_function_output_new_array(len) })?; f(self)?; - map_result(unsafe { crate::shopify_function_output_finish_array(self.0 as _) }) + map_result(unsafe { crate::shopify_function_output_finish_array() }) } /// Finalize the output. This must be called exactly once, and must be called after all other writes. pub fn finalize_output(self) -> Result<(), Error> { - map_result(unsafe { crate::shopify_function_output_finalize(self.0 as _) }) + map_result(unsafe { crate::shopify_function_output_finalize() }) } #[cfg(not(target_family = "wasm"))] /// Finalize the output and return the serialized value as a `serde_json::Value`. /// This is only available in non-Wasm targets, and therefore only recommended for use in tests. pub fn finalize_output_and_return(self) -> Result { - let (result, bytes) = shopify_function_provider::write::shopify_function_output_finalize_and_return_msgpack_bytes(self.0 as _); + let (result, bytes) = shopify_function_provider::write::shopify_function_output_finalize_and_return_msgpack_bytes(); map_result(result as usize) .and_then(|_| rmp_serde::from_slice(&bytes).map_err(|_| Error::IoError)) } diff --git a/integration_tests/tests/integration_test.rs b/integration_tests/tests/integration_test.rs index cf93a95..4183cd9 100644 --- a/integration_tests/tests/integration_test.rs +++ b/integration_tests/tests/integration_test.rs @@ -344,7 +344,7 @@ fn test_fuel_consumption_within_threshold() -> Result<()> { let (_, wasm_api_fuel) = run_example("cart-checkout-validation-wasm-api", wasm_api_input)?; eprintln!("WASM API fuel: {}", wasm_api_fuel); // Using a target fuel value as reference similar to the Javy example - assert_fuel_consumed_within_threshold(15880, wasm_api_fuel); + assert_fuel_consumed_within_threshold(14828, wasm_api_fuel); Ok(()) } @@ -384,7 +384,7 @@ fn test_benchmark_comparison_with_input() -> Result<()> { wasm_api_fuel, non_wasm_api_fuel, improvement ); - assert_fuel_consumed_within_threshold(15880, wasm_api_fuel); + assert_fuel_consumed_within_threshold(14828, wasm_api_fuel); assert_fuel_consumed_within_threshold(23858, non_wasm_api_fuel); Ok(()) @@ -427,7 +427,7 @@ fn test_benchmark_comparison_with_input_early_exit() -> Result<()> { ); // Add fuel consumption threshold checks for both implementations - assert_fuel_consumed_within_threshold(17826, wasm_api_fuel); + assert_fuel_consumed_within_threshold(16880, wasm_api_fuel); assert_fuel_consumed_within_threshold(736695, non_wasm_api_fuel); Ok(()) diff --git a/provider/src/lib.rs b/provider/src/lib.rs index 54b3b6f..be55bb0 100644 --- a/provider/src/lib.rs +++ b/provider/src/lib.rs @@ -3,9 +3,9 @@ pub mod read; mod string_interner; pub mod write; +use bumpalo::Bump; use rmp::encode::ByteBuf; -use shopify_function_wasm_api_core::ContextPtr; -use std::ptr::NonNull; +use std::cell::RefCell; use string_interner::StringInterner; use write::State; @@ -26,9 +26,21 @@ struct Context { string_interner: StringInterner, } -#[derive(Debug)] -enum ContextError { - NullPointer, +thread_local! { + static CONTEXT: RefCell = RefCell::new(Context::default()) +} + +impl Default for Context { + fn default() -> Self { + Self { + bump_allocator: Bump::new(), + input_bytes: Vec::new(), + output_bytes: ByteBuf::new(), + write_state: State::Start, + write_parent_state_stack: Vec::new(), + string_interner: StringInterner::new(), + } + } } impl Context { @@ -57,16 +69,18 @@ impl Context { Self::new(input_bytes) } - fn ref_from_raw<'a>(raw: ContextPtr) -> Result<&'a Self, ContextError> { - NonNull::new(raw as _) - .ok_or(ContextError::NullPointer) - .map(|ptr| unsafe { ptr.as_ref() }) + fn with(f: F) -> T + where + F: FnOnce(&Context) -> T, + { + CONTEXT.with_borrow(f) } - fn mut_from_raw<'a>(raw: ContextPtr) -> Result<&'a mut Self, ContextError> { - NonNull::new(raw as _) - .ok_or(ContextError::NullPointer) - .map(|mut ptr| unsafe { ptr.as_mut() }) + fn with_mut(f: F) -> T + where + F: FnOnce(&mut Context) -> T, + { + CONTEXT.with_borrow_mut(f) } } @@ -92,23 +106,20 @@ pub(crate) use decorate_for_target; #[cfg(target_family = "wasm")] #[export_name = "_shopify_function_context_new"] -extern "C" fn shopify_function_context_new() -> ContextPtr { - Box::into_raw(Box::new(Context::new_from_stdin())) as _ +extern "C" fn shopify_function_context_new() { + CONTEXT.with_borrow_mut(|context| *context = Context::new_from_stdin()) } #[cfg(not(target_family = "wasm"))] -pub fn shopify_function_context_new_from_msgpack_bytes(bytes: Vec) -> ContextPtr { - Box::into_raw(Box::new(Context::new(bytes))) as _ +pub fn shopify_function_context_new_from_msgpack_bytes(bytes: Vec) { + CONTEXT.with_borrow_mut(|context| *context = Context::new(bytes)) } decorate_for_target! { - fn shopify_function_intern_utf8_str(context: ContextPtr, len: usize) -> DoubleUsize { - match Context::mut_from_raw(context) { - Ok(context) => { + fn shopify_function_intern_utf8_str(len: usize) -> DoubleUsize { + Context::with_mut(|context| { let (id, ptr) = context.string_interner.preallocate(len); - ((id as DoubleUsize) << usize::BITS) | (ptr as DoubleUsize) - } - Err(_) => 0, - } + ((id as DoubleUsize) << usize::BITS) | (ptr as DoubleUsize) + }) } } diff --git a/provider/src/read.rs b/provider/src/read.rs index 82f6bd2..503dc17 100644 --- a/provider/src/read.rs +++ b/provider/src/read.rs @@ -1,5 +1,4 @@ use crate::{decorate_for_target, Context}; -use shopify_function_wasm_api_core::ContextPtr; use shopify_function_wasm_api_core::{ read::{ErrorCode, NanBox, Val, ValueRef as NanBoxValueRef}, InternedStringId, @@ -10,193 +9,164 @@ mod lazy_value_ref; pub(crate) use lazy_value_ref::LazyValueRef; decorate_for_target! { - fn shopify_function_input_get(context: ContextPtr) -> Val { - match Context::ref_from_raw(context) { - Ok(context) => { - match context.bump_allocator.alloc_try_with(|| { - LazyValueRef::new(&context.input_bytes, 0, &context.bump_allocator) - .map(|(value, _)| value) - }) { - Ok(input_ref) => input_ref.encode().to_bits(), - Err(e) => NanBox::error(e).to_bits(), - } - } - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), - } + fn shopify_function_input_get() -> Val { + Context::with_mut(|context| { + match context.bump_allocator.alloc_try_with(|| { + LazyValueRef::new(&context.input_bytes, 0, &context.bump_allocator) + .map(|(value, _)| value) + }) { + Ok(input_ref) => input_ref.encode().to_bits(), + Err(e) => NanBox::error(e).to_bits(), + } + }) } } decorate_for_target! { fn shopify_function_input_get_obj_prop( - context: ContextPtr, scope: Val, ptr: usize, len: usize, ) -> Val { - match Context::ref_from_raw(context) { - Ok(context) => { - let v = NanBox::from_bits(scope); - match v.try_decode() { - Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => { - let query = unsafe { std::slice::from_raw_parts(ptr as *const u8, len) }; - let value = match LazyValueRef::mut_from_raw(obj_ptr as _) { - Ok(value) => value, - Err(e) => return NanBox::error(e).to_bits(), - }; - match value.get_object_property( - query, - &context.input_bytes, - &context.bump_allocator, - ) { - Ok(Some(value)) => value.encode().to_bits(), - Ok(None) => NanBox::null().to_bits(), - Err(e) => NanBox::error(e).to_bits(), - } + Context::with(|context| { + let v = NanBox::from_bits(scope); + match v.try_decode() { + Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => { + let query = unsafe { std::slice::from_raw_parts(ptr as *const u8, len) }; + let value = match LazyValueRef::mut_from_raw(obj_ptr as _) { + Ok(value) => value, + Err(e) => return NanBox::error(e).to_bits(), + }; + match value.get_object_property( + query, + &context.input_bytes, + &context.bump_allocator, + ) { + Ok(Some(value)) => value.encode().to_bits(), + Ok(None) => NanBox::null().to_bits(), + Err(e) => NanBox::error(e).to_bits(), } - Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), - Err(_) => NanBox::error(ErrorCode::DecodeError).to_bits(), } + Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), + Err(_) => NanBox::error(ErrorCode::DecodeError).to_bits(), } - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), - } + }) } } decorate_for_target! { fn shopify_function_input_get_interned_obj_prop( - context: ContextPtr, scope: Val, interned_string_id: InternedStringId, ) -> Val { - match Context::ref_from_raw(context) { - Ok(context) => { - let v = NanBox::from_bits(scope); - match v.try_decode() { - Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => { - let query = context.string_interner.get(interned_string_id); - let value = match LazyValueRef::mut_from_raw(obj_ptr as _) { - Ok(value) => value, - Err(e) => return NanBox::error(e).to_bits(), - }; - match value.get_object_property( - query, - &context.input_bytes, - &context.bump_allocator, - ) { - Ok(Some(value)) => value.encode().to_bits(), - Ok(None) => NanBox::null().to_bits(), - Err(e) => NanBox::error(e).to_bits(), - } + Context::with(|context| { + let v = NanBox::from_bits(scope); + match v.try_decode() { + Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => { + let query = context.string_interner.get(interned_string_id); + let value = match LazyValueRef::mut_from_raw(obj_ptr as _) { + Ok(value) => value, + Err(e) => return NanBox::error(e).to_bits(), + }; + match value.get_object_property( + query, + &context.input_bytes, + &context.bump_allocator, + ) { + Ok(Some(value)) => value.encode().to_bits(), + Ok(None) => NanBox::null().to_bits(), + Err(e) => NanBox::error(e).to_bits(), } - Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), - Err(_) => NanBox::error(ErrorCode::DecodeError).to_bits(), } + Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), + Err(_) => NanBox::error(ErrorCode::DecodeError).to_bits(), } - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), - } + }) } } decorate_for_target! { fn shopify_function_input_get_at_index( - context: ContextPtr, scope: Val, index: usize, ) -> Val { - match Context::ref_from_raw(context) { - Ok(context) => { - let v = NanBox::from_bits(scope); - match v.try_decode() { - Ok(NanBoxValueRef::Array { ptr, len: _ } | NanBoxValueRef::Object { ptr, len: _ }) => { - let value = match LazyValueRef::mut_from_raw(ptr as _) { - Ok(value) => value, - Err(e) => return NanBox::error(e).to_bits(), - }; - match value.get_at_index( - index, - &context.input_bytes, - &context.bump_allocator, - ) { - Ok(value) => value.encode().to_bits(), - Err(e) => NanBox::error(e).to_bits(), - } + Context::with(|context| { + let v = NanBox::from_bits(scope); + match v.try_decode() { + Ok(NanBoxValueRef::Array { ptr, len: _ } | NanBoxValueRef::Object { ptr, len: _ }) => { + let value = match LazyValueRef::mut_from_raw(ptr as _) { + Ok(value) => value, + Err(e) => return NanBox::error(e).to_bits(), + }; + match value.get_at_index( + index, + &context.input_bytes, + &context.bump_allocator, + ) { + Ok(value) => value.encode().to_bits(), + Err(e) => NanBox::error(e).to_bits(), } - Ok(_) => NanBox::error(ErrorCode::NotIndexable).to_bits(), - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), } + Ok(_) => NanBox::error(ErrorCode::NotIndexable).to_bits(), + Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), } - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), - } + }) } } decorate_for_target! { fn shopify_function_input_get_obj_key_at_index( - context: ContextPtr, scope: Val, index: usize, ) -> Val { - match Context::ref_from_raw(context) { - Ok(context) => { - let v = NanBox::from_bits(scope); - match v.try_decode() { - Ok(NanBoxValueRef::Object { ptr, .. }) => { - let value = match LazyValueRef::mut_from_raw(ptr as _) { - Ok(value) => value, - Err(e) => return NanBox::error(e).to_bits(), - }; - match value.get_key_at_index( - index, - &context.input_bytes, - &context.bump_allocator, - ) { - Ok(value) => value.encode().to_bits(), - Err(e) => NanBox::error(e).to_bits(), - } + Context::with(|context| { + let v = NanBox::from_bits(scope); + match v.try_decode() { + Ok(NanBoxValueRef::Object { ptr, .. }) => { + let value = match LazyValueRef::mut_from_raw(ptr as _) { + Ok(value) => value, + Err(e) => return NanBox::error(e).to_bits(), + }; + match value.get_key_at_index( + index, + &context.input_bytes, + &context.bump_allocator, + ) { + Ok(value) => value.encode().to_bits(), + Err(e) => NanBox::error(e).to_bits(), } - Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), } + Ok(_) => NanBox::error(ErrorCode::NotAnObject).to_bits(), + Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), } - Err(_) => NanBox::error(ErrorCode::ReadError).to_bits(), - } + }) } } decorate_for_target! { - fn shopify_function_input_get_val_len(context: ContextPtr, scope: Val) -> usize { - match Context::ref_from_raw(context) { - Ok(_) => { - // don't actually need the context, but keeping it for consistency and to make it possible to use in the future if needed - let v = NanBox::from_bits(scope); - match v.try_decode() { - Ok(NanBoxValueRef::String { ptr, .. } | NanBoxValueRef::Array { ptr, .. } | NanBoxValueRef::Object { ptr, .. }) => { - let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else { - return usize::MAX; - }; - value.get_value_length() - } - _ => usize::MAX, - } + fn shopify_function_input_get_val_len(scope: Val) -> usize { + let v = NanBox::from_bits(scope); + match v.try_decode() { + Ok(NanBoxValueRef::String { ptr, .. } | NanBoxValueRef::Array { ptr, .. } | NanBoxValueRef::Object { ptr, .. }) => { + let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else { + return usize::MAX; + }; + value.get_value_length() } - Err(_) => usize::MAX, + _ => usize::MAX, } } } decorate_for_target! { fn shopify_function_input_get_utf8_str_addr( - context: ContextPtr, ptr: usize, ) -> usize { - match Context::ref_from_raw(context) { - Ok(context) => { - let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else { - return 0; - }; - value.get_utf8_str_addr(&context.input_bytes) - } - Err(_) => 0, - } + Context::with(|context| { + let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else { + return 0; + }; + value.get_utf8_str_addr(&context.input_bytes) + }) } } diff --git a/provider/src/write.rs b/provider/src/write.rs index a7ea595..9e262ec 100644 --- a/provider/src/write.rs +++ b/provider/src/write.rs @@ -1,6 +1,6 @@ use crate::{decorate_for_target, Context, DoubleUsize}; use rmp::encode; -use shopify_function_wasm_api_core::{write::WriteResult, ContextPtr}; +use shopify_function_wasm_api_core::write::WriteResult; use std::io::Write; mod state; @@ -118,157 +118,132 @@ impl Context { } decorate_for_target! { - fn shopify_function_output_new_bool(context: ContextPtr, bool: u32) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.write_bool(bool != 0), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_new_bool(bool: u32) -> WriteResult { + Context::with_mut(|context| { + context.write_bool(bool != 0) + }) } } decorate_for_target! { - fn shopify_function_output_new_null(context: ContextPtr) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.write_nil(), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_new_null() -> WriteResult { + Context::with_mut(|context| { + context.write_nil() + }) } } decorate_for_target! { - fn shopify_function_output_new_i32(context: ContextPtr, int: i32) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.write_i32(int), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_new_i32(int: i32) -> WriteResult { + Context::with_mut(|context| { + context.write_i32(int) + }) } } decorate_for_target! { - fn shopify_function_output_new_f64(context: ContextPtr, float: f64) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.write_f64(float), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_new_f64(float: f64) -> WriteResult { + Context::with_mut(|context| { + context.write_f64(float) + }) } } decorate_for_target! { /// The most significant 32 bits are the result, the least significant 32 bits are the pointer. - fn shopify_function_output_new_utf8_str(context: ContextPtr, len: usize) -> DoubleUsize { - match Context::mut_from_raw(context) { - Ok(context) => { - let (result, ptr) = context.allocate_utf8_str(len); - ((result as DoubleUsize) << usize::BITS) | ptr as DoubleUsize - } - Err(_) => (WriteResult::IoError as DoubleUsize) << usize::BITS, - } + fn shopify_function_output_new_utf8_str(len: usize) -> DoubleUsize { + Context::with_mut(|context| { + let (result, ptr) = context.allocate_utf8_str(len); + ((result as DoubleUsize) << usize::BITS) | ptr as DoubleUsize + }) } } decorate_for_target! { fn shopify_function_output_new_object( - context: ContextPtr, len: usize, ) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.start_object(len), - Err(_) => WriteResult::IoError, - } + Context::with_mut(|context| { + context.start_object(len) + }) } } decorate_for_target! { - fn shopify_function_output_finish_object(context: ContextPtr) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.finish_object(), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_finish_object() -> WriteResult { + Context::with_mut(|context| { + context.finish_object() + }) } } decorate_for_target! { fn shopify_function_output_new_array( - context: ContextPtr, len: usize, ) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.start_array(len), - Err(_) => WriteResult::IoError, - } + Context::with_mut(|context| { + context.start_array(len) + }) } } decorate_for_target! { - fn shopify_function_output_finish_array(context: ContextPtr) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.finish_array(), - Err(_) => WriteResult::IoError, - } + fn shopify_function_output_finish_array() -> WriteResult { + Context::with_mut(|context| { + context.finish_array() + }) } } decorate_for_target! { fn shopify_function_output_new_interned_utf8_str( - context: ContextPtr, id: shopify_function_wasm_api_core::InternedStringId, ) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => context.write_interned_utf8_str(id), - Err(_) => WriteResult::IoError, - } + Context::with_mut(|context| { + context.write_interned_utf8_str(id) + }) } } decorate_for_target! { - fn shopify_function_output_finalize(context: ContextPtr) -> WriteResult { - match Context::mut_from_raw(context) { - Ok(context) => { - let Context { - output_bytes, - write_state, - .. - } = &context; - if *write_state != State::End { - return WriteResult::ValueNotFinished; - } - let mut stdout = std::io::stdout(); - if stdout.write_all(output_bytes.as_slice()).is_err() { - return WriteResult::IoError; - } - if stdout.flush().is_err() { - return WriteResult::IoError; - } - let _ = unsafe { Box::from_raw(context as *mut Context) }; // drop the context - WriteResult::Ok - } - Err(_) => WriteResult::IoError, - } - } -} - -#[cfg(not(target_family = "wasm"))] -pub fn shopify_function_output_finalize_and_return_msgpack_bytes( - context: ContextPtr, -) -> (WriteResult, Vec) { - match Context::mut_from_raw(context) { - Ok(context) => { + fn shopify_function_output_finalize() -> WriteResult { + Context::with_mut(|context| { let Context { output_bytes, write_state, .. } = &context; if *write_state != State::End { - return (WriteResult::ValueNotFinished, Vec::new()); + return WriteResult::ValueNotFinished; } - let bytes = output_bytes.as_slice().to_vec(); - let _ = unsafe { Box::from_raw(context as *mut Context) }; // drop the context - (WriteResult::Ok, bytes) - } - Err(_) => (WriteResult::IoError, Vec::new()), + let mut stdout = std::io::stdout(); + if stdout.write_all(output_bytes.as_slice()).is_err() { + return WriteResult::IoError; + } + if stdout.flush().is_err() { + return WriteResult::IoError; + } + WriteResult::Ok + }) } } +#[cfg(not(target_family = "wasm"))] +pub fn shopify_function_output_finalize_and_return_msgpack_bytes() -> (WriteResult, Vec) { + Context::with_mut(|context| { + let Context { + output_bytes, + write_state, + .. + } = &context; + if *write_state != State::End { + return (WriteResult::ValueNotFinished, Vec::new()); + } + let bytes = output_bytes.as_slice().to_vec(); + (WriteResult::Ok, bytes) + }) +} + #[cfg(test)] mod tests { use super::*; diff --git a/trampoline/src/lib.rs b/trampoline/src/lib.rs index 627e493..3046182 100644 --- a/trampoline/src/lib.rs +++ b/trampoline/src/lib.rs @@ -270,10 +270,8 @@ impl TrampolineCodegen { return Ok(()); }; - let shopify_function_input_get_utf8_str_addr = self - .module - .types - .add(&[ValType::I32, ValType::I32], &[ValType::I32]); + let shopify_function_input_get_utf8_str_addr = + self.module.types.add(&[ValType::I32], &[ValType::I32]); let (shopify_function_input_get_utf8_str_addr, _) = self.module.add_import_func( PROVIDER_MODULE_NAME, @@ -286,15 +284,13 @@ impl TrampolineCodegen { self.module.replace_imported_func( imported_shopify_function_input_read_utf8_str, |(builder, arg_locals)| { - let context = arg_locals[0]; - let dst_ptr = arg_locals[1]; - let src_ptr = arg_locals[2]; - let len = arg_locals[3]; + let dst_ptr = arg_locals[0]; + let src_ptr = arg_locals[1]; + let len = arg_locals[2]; builder .func_body() .local_get(src_ptr) - .local_get(context) .local_get(dst_ptr) .call(shopify_function_input_get_utf8_str_addr) .local_get(len) @@ -311,10 +307,10 @@ impl TrampolineCodegen { .imports .get_func(PROVIDER_MODULE_NAME, "shopify_function_input_get_obj_prop") { - let shopify_function_input_get_obj_prop_type = self.module.types.add( - &[ValType::I32, ValType::I64, ValType::I32, ValType::I32], - &[ValType::I64], - ); + let shopify_function_input_get_obj_prop_type = self + .module + .types + .add(&[ValType::I64, ValType::I32, ValType::I32], &[ValType::I64]); let (provider_shopify_function_input_get_obj_prop, _) = self.module.add_import_func( PROVIDER_MODULE_NAME, @@ -330,10 +326,9 @@ impl TrampolineCodegen { self.module.replace_imported_func( imported_shopify_function_input_get_obj_prop, |(builder, arg_locals)| { - let context = arg_locals[0]; - let scope = arg_locals[1]; - let src_ptr = arg_locals[2]; - let len = arg_locals[3]; + let scope = arg_locals[0]; + let src_ptr = arg_locals[1]; + let len = arg_locals[2]; builder .func_body() @@ -343,7 +338,6 @@ impl TrampolineCodegen { .local_get(src_ptr) .local_get(len) .call(memcpy_to_provider) - .local_get(context) .local_get(scope) .local_get(dst_ptr) .local_get(len) @@ -364,10 +358,8 @@ impl TrampolineCodegen { return Ok(()); }; - let shopify_function_output_new_utf8_str_type = self - .module - .types - .add(&[ValType::I32, ValType::I32], &[ValType::I64]); + let shopify_function_output_new_utf8_str_type = + self.module.types.add(&[ValType::I32], &[ValType::I64]); let (provider_shopify_function_output_new_utf8_str, _) = self.module.add_import_func( PROVIDER_MODULE_NAME, @@ -382,13 +374,11 @@ impl TrampolineCodegen { self.module.replace_imported_func( imported_shopify_function_output_new_utf8_str, |(builder, arg_locals)| { - let context = arg_locals[0]; - let src_ptr = arg_locals[1]; - let len = arg_locals[2]; + let src_ptr = arg_locals[0]; + let len = arg_locals[1]; builder .func_body() - .local_get(context) .local_get(len) // most significant 32 bits are the result, least significant 32 bits are the pointer .call(provider_shopify_function_output_new_utf8_str) @@ -418,10 +408,8 @@ impl TrampolineCodegen { return Ok(()); }; - let shopify_function_intern_utf8_str_type = self - .module - .types - .add(&[ValType::I32, ValType::I32], &[ValType::I64]); + let shopify_function_intern_utf8_str_type = + self.module.types.add(&[ValType::I32], &[ValType::I64]); let (provider_shopify_function_intern_utf8_str, _) = self.module.add_import_func( PROVIDER_MODULE_NAME, @@ -436,13 +424,11 @@ impl TrampolineCodegen { self.module.replace_imported_func( imported_shopify_function_intern_utf8_str, |(builder, arg_locals)| { - let context = arg_locals[0]; - let src_ptr = arg_locals[1]; - let len = arg_locals[2]; + let src_ptr = arg_locals[0]; + let len = arg_locals[1]; builder .func_body() - .local_get(context) .local_get(len) // most significant 32 bits are the ID, least significant 32 bits are the pointer .call(provider_shopify_function_intern_utf8_str) diff --git a/trampoline/src/snapshots/shopify_function_trampoline__test__disassemble_trampoline@consumer.wat.snap b/trampoline/src/snapshots/shopify_function_trampoline__test__disassemble_trampoline@consumer.wat.snap index ba1cfc0..78d19a1 100644 --- a/trampoline/src/snapshots/shopify_function_trampoline__test__disassemble_trampoline@consumer.wat.snap +++ b/trampoline/src/snapshots/shopify_function_trampoline__test__disassemble_trampoline@consumer.wat.snap @@ -4,29 +4,28 @@ expression: actual input_file: trampoline/src/test_data/consumer.wat --- (module - (type (;0;) (func (result i32))) - (type (;1;) (func (param i32) (result i32))) - (type (;2;) (func (param i32) (result i64))) - (type (;3;) (func (param i32 i32) (result i32))) - (type (;4;) (func (param i32 i32) (result i64))) - (type (;5;) (func (param i32 i32 i32))) - (type (;6;) (func (param i32 i32 i32) (result i32))) - (type (;7;) (func (param i32 i32 i32 i32))) - (type (;8;) (func (param i32 i32 i32 i32) (result i32))) - (type (;9;) (func (param i32 i64) (result i32))) - (type (;10;) (func (param i32 i64 i32) (result i64))) - (type (;11;) (func (param i32 i64 i32 i32) (result i64))) - (type (;12;) (func (param i32 f64) (result i32))) + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result i64))) + (type (;3;) (func (param i32) (result i32))) + (type (;4;) (func (param i32) (result i64))) + (type (;5;) (func (param i32 i32) (result i32))) + (type (;6;) (func (param i32 i32 i32))) + (type (;7;) (func (param i32 i32 i32 i32) (result i32))) + (type (;8;) (func (param i64) (result i32))) + (type (;9;) (func (param i64 i32) (result i64))) + (type (;10;) (func (param i64 i32 i32) (result i64))) + (type (;11;) (func (param f64) (result i32))) (import "shopify_function_v1" "_shopify_function_context_new" (func (;0;) (type 0))) (import "shopify_function_v1" "_shopify_function_input_get" (func (;1;) (type 2))) - (import "shopify_function_v1" "_shopify_function_input_get_interned_obj_prop" (func (;2;) (type 10))) - (import "shopify_function_v1" "_shopify_function_input_get_at_index" (func (;3;) (type 10))) - (import "shopify_function_v1" "_shopify_function_input_get_obj_key_at_index" (func (;4;) (type 10))) - (import "shopify_function_v1" "_shopify_function_input_get_val_len" (func (;5;) (type 9))) + (import "shopify_function_v1" "_shopify_function_input_get_interned_obj_prop" (func (;2;) (type 9))) + (import "shopify_function_v1" "_shopify_function_input_get_at_index" (func (;3;) (type 9))) + (import "shopify_function_v1" "_shopify_function_input_get_obj_key_at_index" (func (;4;) (type 9))) + (import "shopify_function_v1" "_shopify_function_input_get_val_len" (func (;5;) (type 8))) (import "shopify_function_v1" "_shopify_function_output_new_bool" (func (;6;) (type 3))) (import "shopify_function_v1" "_shopify_function_output_new_null" (func (;7;) (type 1))) - (import "shopify_function_v1" "_shopify_function_output_new_i32" (func (;8;) (type 1))) - (import "shopify_function_v1" "_shopify_function_output_new_f64" (func (;9;) (type 12))) + (import "shopify_function_v1" "_shopify_function_output_new_i32" (func (;8;) (type 3))) + (import "shopify_function_v1" "_shopify_function_output_new_f64" (func (;9;) (type 11))) (import "shopify_function_v1" "_shopify_function_output_new_object" (func (;10;) (type 3))) (import "shopify_function_v1" "_shopify_function_output_finish_object" (func (;11;) (type 1))) (import "shopify_function_v1" "_shopify_function_output_new_array" (func (;12;) (type 3))) @@ -35,78 +34,74 @@ input_file: trampoline/src/test_data/consumer.wat (import "shopify_function_v1" "_shopify_function_output_finalize" (func (;15;) (type 1))) (import "shopify_function_v1" "_shopify_function_input_get_utf8_str_addr" (func (;16;) (type 3))) (import "shopify_function_v1" "memory" (memory (;0;) 1)) - (import "shopify_function_v1" "_shopify_function_input_get_obj_prop" (func (;17;) (type 11))) - (import "shopify_function_v1" "shopify_function_realloc" (func (;18;) (type 8))) + (import "shopify_function_v1" "_shopify_function_input_get_obj_prop" (func (;17;) (type 10))) + (import "shopify_function_v1" "shopify_function_realloc" (func (;18;) (type 7))) (import "shopify_function_v1" "_shopify_function_output_new_utf8_str" (func (;19;) (type 4))) (import "shopify_function_v1" "_shopify_function_intern_utf8_str" (func (;20;) (type 4))) (memory (;1;) 1) (export "memory" (memory 1)) - (func (;21;) (type 6) (param i32 i32 i32) (result i32) + (func (;21;) (type 5) (param i32 i32) (result i32) (local i64) - local.get 0 - local.get 2 + local.get 1 call 20 - local.tee 3 + local.tee 2 i64.const 32 i64.shr_u i32.wrap_i64 - local.get 3 + local.get 2 i32.wrap_i64 + local.get 0 local.get 1 - local.get 2 call 27 ) - (func (;22;) (type 6) (param i32 i32 i32) (result i32) + (func (;22;) (type 5) (param i32 i32) (result i32) (local i64) - local.get 0 - local.get 2 + local.get 1 call 19 - local.tee 3 + local.tee 2 i64.const 32 i64.shr_u i32.wrap_i64 - local.get 3 + local.get 2 i32.wrap_i64 + local.get 0 local.get 1 - local.get 2 call 27 ) - (func (;23;) (type 11) (param i32 i64 i32 i32) (result i64) + (func (;23;) (type 10) (param i64 i32 i32) (result i64) (local i32) - local.get 3 + local.get 2 call 25 - local.tee 4 + local.tee 3 + local.get 1 local.get 2 - local.get 3 call 27 local.get 0 - local.get 1 - local.get 4 local.get 3 + local.get 2 call 17 ) - (func (;24;) (type 7) (param i32 i32 i32 i32) - local.get 2 - local.get 0 + (func (;24;) (type 6) (param i32 i32 i32) local.get 1 + local.get 0 call 16 - local.get 3 + local.get 2 call 26 ) - (func (;25;) (type 1) (param i32) (result i32) + (func (;25;) (type 3) (param i32) (result i32) i32.const 0 i32.const 0 i32.const 1 local.get 0 call 18 ) - (func (;26;) (type 5) (param i32 i32 i32) + (func (;26;) (type 6) (param i32 i32 i32) local.get 0 local.get 1 local.get 2 memory.copy 1 0 ) - (func (;27;) (type 5) (param i32 i32 i32) + (func (;27;) (type 6) (param i32 i32 i32) local.get 0 local.get 1 local.get 2 diff --git a/trampoline/src/test_data/consumer.wat b/trampoline/src/test_data/consumer.wat index 2613ede..7ff48e6 100644 --- a/trampoline/src/test_data/consumer.wat +++ b/trampoline/src/test_data/consumer.wat @@ -1,29 +1,29 @@ (module ;; General - (import "shopify_function_v1" "shopify_function_context_new" (func (result i32))) - (import "shopify_function_v1" "shopify_function_intern_utf8_str" (func (param i32 i32 i32) (result i32))) + (import "shopify_function_v1" "shopify_function_context_new" (func)) + (import "shopify_function_v1" "shopify_function_intern_utf8_str" (func (param i32 i32) (result i32))) ;; Read. - (import "shopify_function_v1" "shopify_function_input_get" (func (param i32) (result i64))) - (import "shopify_function_v1" "shopify_function_input_get_obj_prop" (func (param i32 i64 i32 i32) (result i64))) - (import "shopify_function_v1" "shopify_function_input_get_interned_obj_prop" (func (param i32 i64 i32) (result i64))) - (import "shopify_function_v1" "shopify_function_input_get_at_index" (func (param i32 i64 i32) (result i64))) - (import "shopify_function_v1" "shopify_function_input_get_obj_key_at_index" (func (param i32 i64 i32) (result i64))) - (import "shopify_function_v1" "shopify_function_input_get_val_len" (func (param i32 i64) (result i32))) - (import "shopify_function_v1" "shopify_function_input_read_utf8_str" (func (param i32 i32 i32 i32))) + (import "shopify_function_v1" "shopify_function_input_get" (func (result i64))) + (import "shopify_function_v1" "shopify_function_input_get_obj_prop" (func (param i64 i32 i32) (result i64))) + (import "shopify_function_v1" "shopify_function_input_get_interned_obj_prop" (func (param i64 i32) (result i64))) + (import "shopify_function_v1" "shopify_function_input_get_at_index" (func (param i64 i32) (result i64))) + (import "shopify_function_v1" "shopify_function_input_get_obj_key_at_index" (func (param i64 i32) (result i64))) + (import "shopify_function_v1" "shopify_function_input_get_val_len" (func (param i64) (result i32))) + (import "shopify_function_v1" "shopify_function_input_read_utf8_str" (func (param i32 i32 i32))) ;; Write. - (import "shopify_function_v1" "shopify_function_output_new_bool" (func (param i32 i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_null" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_bool" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_null" (func (result i32))) (import "shopify_function_v1" "shopify_function_output_new_i32" (func (param i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_f64" (func (param i32 f64) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_utf8_str" (func (param i32 i32 i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_object" (func (param i32 i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_finish_object" (func (param i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_array" (func (param i32 i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_finish_array" (func (param i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_new_interned_utf8_str" (func (param i32 i32) (result i32))) - (import "shopify_function_v1" "shopify_function_output_finalize" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_f64" (func (param f64) (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_utf8_str" (func (param i32 i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_object" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_finish_object" (func (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_array" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_finish_array" (func (result i32))) + (import "shopify_function_v1" "shopify_function_output_new_interned_utf8_str" (func (param i32) (result i32))) + (import "shopify_function_v1" "shopify_function_output_finalize" (func (result i32))) ;; Memory (memory 1)