Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement error-context #1

Merged
merged 3 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,9 @@ io-extras = "0.18.1"
rustix = "0.38.43"
# wit-bindgen:
# TODO: switch to crates.io once https://github.com/bytecodealliance/wit-bindgen/pull/1124 has been released
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", default-features = false }
wit-bindgen-rt = { git = "https://github.com/bytecodealliance/wit-bindgen", default-features = false }
wit-bindgen-rust-macro = { git = "https://github.com/bytecodealliance/wit-bindgen", default-features = false }
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "341c47375d44bb82dc726d34e94bbb2e92b4b595", default-features = false }
wit-bindgen-rt = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "341c47375d44bb82dc726d34e94bbb2e92b4b595", default-features = false }
wit-bindgen-rust-macro = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "341c47375d44bb82dc726d34e94bbb2e92b4b595", default-features = false }

# wasm-tools family:
wasmparser = { version = "0.223.0", default-features = false, features = ['simd'] }
Expand Down
11 changes: 11 additions & 0 deletions cranelift/entity/src/primary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ where
self.elems.get_mut(k.index())
}

/// Get the element at `k` if it exists, mutable version.
pub fn get_mut_or_insert_with(&mut self, k: K, f: impl FnOnce() -> V) -> &mut V {
if self.elems.get(k.index()).is_none() {
self.elems.insert(k.index(), f());
}

self.elems
.get_mut(k.index())
.expect("missing existing element")
}

/// Is this map completely empty?
pub fn is_empty(&self) -> bool {
self.elems.is_empty()
Expand Down
4 changes: 2 additions & 2 deletions crates/cranelift/src/compiler/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ impl<'a> TrampolineCompiler<'a> {

fn translate_error_context_call(
&mut self,
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
options: &CanonicalOptions,
offset: u32,
params: Vec<ir::AbiParam>,
Expand Down Expand Up @@ -1379,7 +1379,7 @@ impl<'a> TrampolineCompiler<'a> {
}
}

fn translate_error_context_drop_call(&mut self, ty: TypeErrorContextTableIndex) {
fn translate_error_context_drop_call(&mut self, ty: TypeComponentLocalErrorContextTableIndex) {
match self.abi {
Abi::Wasm => {}

Expand Down
6 changes: 3 additions & 3 deletions crates/environ/src/component/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,15 @@ pub enum Trampoline {
ty: TypeFutureTableIndex,
},
ErrorContextNew {
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
options: CanonicalOptions,
},
ErrorContextDebugMessage {
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
options: CanonicalOptions,
},
ErrorContextDrop {
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
},
ResourceTransferOwn,
ResourceTransferBorrow,
Expand Down
6 changes: 3 additions & 3 deletions crates/environ/src/component/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ pub enum Trampoline {
/// specified debug message.
ErrorContextNew {
/// The table index for the `error-context` type in the caller instance.
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
/// String encoding, memory, etc. to use when loading debug message.
options: CanonicalOptions,
},
Expand All @@ -861,15 +861,15 @@ pub enum Trampoline {
/// to `error.new`.
ErrorContextDebugMessage {
/// The table index for the `error-context` type in the caller instance.
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
/// String encoding, memory, etc. to use when storing debug message.
options: CanonicalOptions,
},

/// A `error-context.drop` intrinsic to drop a specified `error-context`.
ErrorContextDrop {
/// The table index for the `error-context` type in the caller instance.
ty: TypeErrorContextTableIndex,
ty: TypeComponentLocalErrorContextTableIndex,
},

/// An intrinsic used by FACT-generated modules which will transfer an owned
Expand Down
16 changes: 12 additions & 4 deletions crates/environ/src/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,19 @@ indices! {
/// This is analogous to `TypeResourceTableIndex` in that it tracks
/// ownership of stream within each (sub)component instance.
pub struct TypeStreamTableIndex(u32);

/// Index pointing to a error context table within a component.
///
/// This is analogous to `TypeResourceTableIndex` in that it tracks
/// ownership of error contexts within each (sub)component instance.
pub struct TypeErrorContextTableIndex(u32);
pub struct TypeComponentLocalErrorContextTableIndex(u32);

/// Index pointing to a (component) globally tracked error context table entry
///
/// Unlike [`TypeComponentLocalErrorContextTableIndex`], this index refers to
/// the global state table for error contexts at the level of the entire component,
/// not just a subcomponent.
pub struct TypeComponentGlobalErrorContextTableIndex(u32);

/// Index pointing to an interned `task.return` type within a component.
pub struct TypeTaskReturnIndex(u32);
Expand Down Expand Up @@ -267,7 +275,7 @@ pub struct ComponentTypes {
pub(super) future_tables: PrimaryMap<TypeFutureTableIndex, TypeFutureTable>,
pub(super) streams: PrimaryMap<TypeStreamIndex, TypeStream>,
pub(super) stream_tables: PrimaryMap<TypeStreamTableIndex, TypeStreamTable>,
pub(super) error_context_tables: PrimaryMap<TypeErrorContextTableIndex, TypeErrorContextTable>,
pub(super) error_context_tables: PrimaryMap<TypeComponentLocalErrorContextTableIndex, TypeErrorContextTable>,
pub(super) task_returns: PrimaryMap<TypeTaskReturnIndex, TypeTaskReturn>,
}

Expand Down Expand Up @@ -357,7 +365,7 @@ impl_index! {
impl Index<TypeStreamIndex> for ComponentTypes { TypeStream => streams }
impl Index<TypeFutureTableIndex> for ComponentTypes { TypeFutureTable => future_tables }
impl Index<TypeStreamTableIndex> for ComponentTypes { TypeStreamTable => stream_tables }
impl Index<TypeErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
impl Index<TypeComponentLocalErrorContextTableIndex> for ComponentTypes { TypeErrorContextTable => error_context_tables }
}

// Additionally forward anything that can index `ModuleTypes` to `ModuleTypes`
Expand Down Expand Up @@ -518,7 +526,7 @@ pub enum InterfaceType {
Borrow(TypeResourceTableIndex),
Future(TypeFutureTableIndex),
Stream(TypeStreamTableIndex),
ErrorContext(TypeErrorContextTableIndex),
ErrorContext(TypeComponentLocalErrorContextTableIndex),
}

impl From<&wasmparser::PrimitiveValType> for InterfaceType {
Expand Down
10 changes: 5 additions & 5 deletions crates/environ/src/component/types_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct ComponentTypesBuilder {
streams: HashMap<TypeStream, TypeStreamIndex>,
future_tables: HashMap<TypeFutureTable, TypeFutureTableIndex>,
stream_tables: HashMap<TypeStreamTable, TypeStreamTableIndex>,
error_context_tables: HashMap<TypeErrorContextTable, TypeErrorContextTableIndex>,
error_context_tables: HashMap<TypeErrorContextTable, TypeComponentLocalErrorContextTableIndex>,
task_returns: HashMap<TypeTaskReturn, TypeTaskReturnIndex>,

component_types: ComponentTypes,
Expand Down Expand Up @@ -210,7 +210,7 @@ impl ComponentTypesBuilder {
}

/// Returns the number of error-context tables allocated so far, or the maximum
/// `TypeErrorContextTableIndex`.
/// `TypeComponentLocalErrorContextTableIndex`.
pub fn num_error_context_tables(&self) -> usize {
self.component_types.error_context_tables.len()
}
Expand Down Expand Up @@ -444,7 +444,7 @@ impl ComponentTypesBuilder {
}

/// Retrieve Wasmtime's type representation of the `error-context` type.
pub fn error_context_type(&mut self) -> Result<TypeErrorContextTableIndex> {
pub fn error_context_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
self.error_context_table_type()
}

Expand Down Expand Up @@ -599,7 +599,7 @@ impl ComponentTypesBuilder {
}))
}

fn error_context_table_type(&mut self) -> Result<TypeErrorContextTableIndex> {
fn error_context_table_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
Ok(self.add_error_context_table_type(TypeErrorContextTable {
instance: self.resources.get_current_instance().unwrap(),
}))
Expand Down Expand Up @@ -694,7 +694,7 @@ impl ComponentTypesBuilder {
pub fn add_error_context_table_type(
&mut self,
ty: TypeErrorContextTable,
) -> TypeErrorContextTableIndex {
) -> TypeComponentLocalErrorContextTableIndex {
intern(
&mut self.error_context_tables,
&mut self.component_types.error_context_tables,
Expand Down
4 changes: 2 additions & 2 deletions crates/environ/src/fact/trampoline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use crate::component::{
CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType,
StringEncoding, Transcode, TypeEnumIndex, TypeErrorContextTableIndex, TypeFlagsIndex,
StringEncoding, Transcode, TypeEnumIndex, TypeComponentLocalErrorContextTableIndex, TypeFlagsIndex,
TypeFutureTableIndex, TypeListIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex,
TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo,
FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
Expand Down Expand Up @@ -2935,7 +2935,7 @@ impl Compiler<'_, '_> {

fn translate_error_context_context(
&mut self,
src_ty: TypeErrorContextTableIndex,
src_ty: TypeComponentLocalErrorContextTableIndex,
src: &Source<'_>,
dst_ty: &InterfaceType,
dst: &Destination,
Expand Down
22 changes: 22 additions & 0 deletions crates/misc/component-async-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ mod test {
Ok(())
}

/// Compose two components
///
/// a is the "root" component, and b is composed into it
async fn compose(a: &[u8], b: &[u8]) -> Result<Vec<u8>> {
let dir = tempfile::tempdir()?;

Expand Down Expand Up @@ -1289,4 +1292,23 @@ mod test {
&fs::read(test_programs_artifacts::ASYNC_HTTP_MIDDLEWARE_COMPONENT).await?;
test_http_echo(&compose(middleware, echo).await?, true).await
}

#[tokio::test]
async fn async_error_context() -> Result<()> {
test_run(&fs::read(test_programs_artifacts::ASYNC_ERROR_CONTEXT_COMPONENT).await?).await
}

#[tokio::test]
async fn async_error_context_callee() -> Result<()> {
test_run(&fs::read(test_programs_artifacts::ASYNC_ERROR_CONTEXT_COMPONENT).await?).await
}

#[tokio::test]
async fn async_error_context_caller() -> Result<()> {
let caller =
&fs::read(test_programs_artifacts::ASYNC_ERROR_CONTEXT_CALLER_COMPONENT).await?;
let callee =
&fs::read(test_programs_artifacts::ASYNC_ERROR_CONTEXT_CALLEE_COMPONENT).await?;
test_run(&compose(caller, callee).await?).await
}
}
21 changes: 20 additions & 1 deletion crates/misc/component-async-tests/wit/test.wit
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ interface transmit {
write-stream(string),
write-future(string),
}

exchange: func(control: stream<control>,
caller-stream: stream<string>,
caller-future1: future<string>,
Expand Down Expand Up @@ -63,6 +63,11 @@ interface run-bool {
run: func(v: bool);
}

interface run-result {
run-fail: func() -> result<_, error-context>;
run-pass: func() -> result<_, error-context>;
}

world yield-caller {
import continue;
import ready;
Expand Down Expand Up @@ -129,3 +134,17 @@ world borrowing-host {
import borrowing-types;
export run-bool;
}

world error-context-usage {
export run;
}

world error-context-callee {
export run-result;
export run;
}

world error-context-caller {
import run-result;
export run;
}
2 changes: 1 addition & 1 deletion crates/test-programs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ anyhow = { workspace = true, features = ['std'] }
wasi = "0.11.0"
wasi-nn = "0.6.0"
wit-bindgen = { workspace = true, features = ['default'] }
wit-bindgen-rt = { workspace = true }
wit-bindgen-rt = { workspace = true, features = ['async'] }
libc = { workspace = true }
getrandom = "0.2.9"
futures = { workspace = true, default-features = false, features = ['alloc'] }
Expand Down
29 changes: 29 additions & 0 deletions crates/test-programs/src/bin/async_error_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
mod bindings {
wit_bindgen::generate!({
path: "../misc/component-async-tests/wit",
world: "error-context-usage",
async: {
exports: [
"local:local/run#run",
],
}
});

use super::Component;
export!(Component);
}
use bindings::exports::local::local::run::Guest;

use wit_bindgen_rt::async_support::error_context_new;

struct Component;

impl Guest for Component {
async fn run() {
let err_ctx = error_context_new("error".into());
_ = err_ctx.debug_message();
}
}

// Unused function; required since this file is built as a `bin`:
fn main() {}
36 changes: 36 additions & 0 deletions crates/test-programs/src/bin/async_error_context_callee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
mod bindings {
wit_bindgen::generate!({
path: "../misc/component-async-tests/wit",
world: "error-context-callee",
async: {
exports: [
"local:local/run#run",
"local:local/run-result#run-pass",
"local:local/run-result#run-fail",
],
}
});

use super::Component;
export!(Component);
}
use wit_bindgen_rt::async_support::{error_context_new, ErrorContext};

struct Component;

impl bindings::exports::local::local::run_result::Guest for Component {
async fn run_fail() -> Result<(), ErrorContext> {
Err(error_context_new("error".into()))
}

async fn run_pass() -> Result<(), ErrorContext> {
Ok(())
}
}

impl bindings::exports::local::local::run::Guest for Component {
async fn run() {}
}

// Unused function; required since this file is built as a `bin`:
fn main() {}
Loading