diff --git a/crates/test-util/src/wast.rs b/crates/test-util/src/wast.rs index a40f95cfbf64..f6b1b7d955e3 100644 --- a/crates/test-util/src/wast.rs +++ b/crates/test-util/src/wast.rs @@ -53,16 +53,13 @@ pub fn find_tests(root: &Path) -> Result> { ) .with_context(|| format!("failed to add tests from `{}`", cm_tests.display()))?; - // Temporarily work around upstream tests that loop forever. - // - // Now that `thread.yield` and `CALLBACK_CODE_YIELD` are both no-ops in - // non-blocking contexts, these tests need to be updated; meanwhile, we skip - // them. - // - // TODO: remove this once - // https://github.com/WebAssembly/component-model/pull/578 has been merged: + // Temporarily work around upstream tests that fail in unexpected ways (e.g. + // panics, loops, etc). { - let skip_list = &["drop-subtask.wast", "async-calls-sync.wast"]; + let skip_list = &[ + // FIXME(#12510) + "drop-cross-task-borrow.wast", + ]; tests.retain(|test| { test.path .file_name() diff --git a/crates/wasmtime/src/runtime/component/concurrent.rs b/crates/wasmtime/src/runtime/component/concurrent.rs index bd198d19ba79..4b07832129f5 100644 --- a/crates/wasmtime/src/runtime/component/concurrent.rs +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -57,7 +57,7 @@ use crate::component::{ use crate::fiber::{self, StoreFiber, StoreFiberYield}; use crate::prelude::*; use crate::store::{Store, StoreId, StoreInner, StoreOpaque, StoreToken}; -use crate::vm::component::{CallContext, ComponentInstance, HandleTable, ResourceTables}; +use crate::vm::component::{CallContext, ComponentInstance, InstanceState, ResourceTables}; use crate::vm::{AlwaysMut, SendSyncPtr, VMFuncRef, VMMemoryDefinition, VMStore}; use crate::{ AsContext, AsContextMut, FuncType, Result, StoreContext, StoreContextMut, ValRaw, ValType, @@ -655,7 +655,7 @@ impl GuestCall { .concurrent_state_mut() .get_mut(self.thread.task)? .instance; - let state = store.instance_state(instance); + let state = store.instance_state(instance).concurrent_state(); let ready = match &self.kind { GuestCallKind::DeliverEvent { .. } => !state.do_not_enter, @@ -1325,6 +1325,7 @@ impl StoreContextMut<'_, T> { let instance = state.get_mut(call.thread.task)?.instance; self.0 .instance_state(instance) + .concurrent_state() .pending .insert(call.thread, call.kind); } @@ -1561,20 +1562,11 @@ impl StoreOpaque { } } - /// Helper function to retrieve the `ConcurrentInstanceState` for the + /// Helper function to retrieve the `InstanceState` for the /// specified instance. - fn instance_state(&mut self, instance: RuntimeInstance) -> &mut ConcurrentInstanceState { + fn instance_state(&mut self, instance: RuntimeInstance) -> &mut InstanceState { self.component_instance_mut(instance.instance) .instance_state(instance.index) - .concurrent_state() - } - - /// Helper function to retrieve the `HandleTable` for the specified - /// instance. - fn handle_table(&mut self, instance: RuntimeInstance) -> &mut HandleTable { - self.component_instance_mut(instance.instance) - .instance_state(instance.index) - .handle_table() } fn set_thread(&mut self, thread: Option) -> Option { @@ -1633,7 +1625,9 @@ impl StoreOpaque { /// cannot be entered again until the next call returns. fn enter_instance(&mut self, instance: RuntimeInstance) { log::trace!("enter {instance:?}"); - self.instance_state(instance).do_not_enter = true; + self.instance_state(instance) + .concurrent_state() + .do_not_enter = true; } /// Record that we've exited a (sub-)component instance previously entered @@ -1641,7 +1635,9 @@ impl StoreOpaque { /// See the documentation for the latter for details. fn exit_instance(&mut self, instance: RuntimeInstance) -> Result<()> { log::trace!("exit {instance:?}"); - self.instance_state(instance).do_not_enter = false; + self.instance_state(instance) + .concurrent_state() + .do_not_enter = false; self.partition_pending(instance) } @@ -1650,13 +1646,16 @@ impl StoreOpaque { /// /// See `GuestCall::is_ready` for details. fn partition_pending(&mut self, instance: RuntimeInstance) -> Result<()> { - for (thread, kind) in mem::take(&mut self.instance_state(instance).pending).into_iter() { + for (thread, kind) in + mem::take(&mut self.instance_state(instance).concurrent_state().pending).into_iter() + { let call = GuestCall { thread, kind }; if call.is_ready(self)? { self.concurrent_state_mut() .push_high_priority(WorkItem::GuestCall(call)); } else { self.instance_state(instance) + .concurrent_state() .pending .insert(call.thread, call.kind); } @@ -1671,7 +1670,7 @@ impl StoreOpaque { caller_instance: RuntimeInstance, modify: impl FnOnce(u16) -> Option, ) -> Result<()> { - let state = self.instance_state(caller_instance); + let state = self.instance_state(caller_instance).concurrent_state(); let old = state.backpressure; let new = modify(old).ok_or_else(|| format_err!("backpressure counter overflow"))?; state.backpressure = new; @@ -1918,10 +1917,11 @@ impl Instance { } let set = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: runtime_instance, }) + .handle_table() .waitable_set_rep(handle)?; Ok(TableId::::new(set)) @@ -2034,10 +2034,11 @@ impl Instance { .get_mut(guest_thread.thread)? .instance_rep; store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: runtime_instance, }) + .thread_handle_table() .guest_thread_remove(guest_id.unwrap())?; store.concurrent_state_mut().delete(guest_thread.thread)?; @@ -2665,7 +2666,8 @@ impl Instance { // waitable and return the status. let handle = store .0 - .handle_table(caller_instance) + .instance_state(caller_instance) + .handle_table() .subtask_insert_guest(guest_thread.task.rep())?; store .0 @@ -2847,10 +2849,11 @@ impl Instance { store.0.concurrent_state_mut().push_future(future); let handle = store .0 - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .subtask_insert_host(task.rep())?; store.0.concurrent_state_mut().get_mut(task)?.common.handle = Some(handle); log::trace!( @@ -2981,10 +2984,11 @@ impl Instance { ) -> Result { let set = store.concurrent_state_mut().push(WaitableSet::default())?; let handle = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .waitable_set_insert(set.rep())?; log::trace!("new waitable set {set:?} (handle {handle})"); Ok(handle) @@ -2998,10 +3002,11 @@ impl Instance { set: u32, ) -> Result<()> { let rep = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .waitable_set_remove(set)?; log::trace!("drop waitable set {rep} (handle {set})"); @@ -3056,10 +3061,11 @@ impl Instance { self.waitable_join(store, caller_instance, task_id, 0)?; let (rep, is_host) = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .subtask_remove(task_id)?; let concurrent_state = store.concurrent_state_mut(); @@ -3132,10 +3138,11 @@ impl Instance { .. } = &self.id().get(store).component().env_component().options[options]; let rep = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .waitable_set_rep(set)?; self.waitable_check( @@ -3164,10 +3171,11 @@ impl Instance { .. } = &self.id().get(store).component().env_component().options[options]; let rep = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .waitable_set_rep(set)?; self.waitable_check( @@ -3315,10 +3323,11 @@ impl Instance { runtime_instance: RuntimeComponentInstanceIndex, ) -> Result { let guest_id = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: runtime_instance, }) + .thread_handle_table() .guest_thread_insert(thread_id.rep())?; store .concurrent_state_mut() @@ -3494,10 +3503,11 @@ impl Instance { } let (rep, is_host) = store - .handle_table(RuntimeInstance { + .instance_state(RuntimeInstance { instance: self.id().instance(), index: caller_instance, }) + .handle_table() .subtask_rep(task_id)?; let (waitable, expected_caller_instance) = if is_host { let id = TableId::::new(rep); @@ -3556,7 +3566,7 @@ impl Instance { assert!(concurrent_state.get_mut(guest_task)?.ready_to_delete()); // Not yet started; cancel and remove from pending - let pending = &mut store.instance_state(instance).pending; + let pending = &mut store.instance_state(instance).concurrent_state().pending; let pending_count = pending.len(); pending.retain(|thread, _| thread.task != guest_task); // If there were no pending threads for this task, we're in an error state @@ -4252,7 +4262,7 @@ impl GuestThread { guest_thread: u32, ) -> Result> { let rep = state.instance_states().0[caller_instance] - .handle_table() + .thread_handle_table() .guest_thread_rep(guest_thread)?; Ok(TableId::new(rep)) } diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index 065666e36ce7..9850b28366bb 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -43,7 +43,7 @@ mod resources; pub use self::handle_table::{HandleTable, RemovedResource}; #[cfg(feature = "component-model-async")] -pub use self::handle_table::{TransmitLocalState, Waitable}; +pub use self::handle_table::{ThreadHandleTable, TransmitLocalState, Waitable}; #[cfg(feature = "component-model-async")] pub use self::resources::CallContext; pub use self::resources::{CallContexts, ResourceTables, TypedResource, TypedResourceIndex}; @@ -62,6 +62,11 @@ pub struct InstanceState { /// is used directly to translate guest handles to host representations and /// vice-versa. handle_table: HandleTable, + + /// Dedicated table for threads that is separate from `handle_table`. Part + /// of the component-model-threading proposal. + #[cfg(feature = "component-model-async")] + thread_handle_table: ThreadHandleTable, } impl InstanceState { @@ -75,6 +80,12 @@ impl InstanceState { pub fn handle_table(&mut self) -> &mut HandleTable { &mut self.handle_table } + + /// State of thread handles. + #[cfg(feature = "component-model-async")] + pub fn thread_handle_table(&mut self) -> &mut ThreadHandleTable { + &mut self.thread_handle_table + } } /// Runtime representation of a component instance and all state necessary for diff --git a/crates/wasmtime/src/runtime/vm/component/handle_table.rs b/crates/wasmtime/src/runtime/vm/component/handle_table.rs index 7f451f4ed354..0fc19800b0be 100644 --- a/crates/wasmtime/src/runtime/vm/component/handle_table.rs +++ b/crates/wasmtime/src/runtime/vm/component/handle_table.rs @@ -82,6 +82,7 @@ enum Slot { }, /// Represents a guest thread handle. + #[cfg(feature = "component-model-async")] GuestThread { rep: u32, }, @@ -571,16 +572,23 @@ impl HandleTable { _ => bail!("handle is not a waitable"), } } +} + +#[derive(Default)] +#[cfg(feature = "component-model-async")] +pub struct ThreadHandleTable(HandleTable); +#[cfg(feature = "component-model-async")] +impl ThreadHandleTable { /// Inserts the guest thread `rep` into this table, returning the index it /// now resides at. pub fn guest_thread_insert(&mut self, rep: u32) -> Result { - self.insert(Slot::GuestThread { rep }) + self.0.insert(Slot::GuestThread { rep }) } /// Returns the `rep` of a guest thread pointed to by `idx`. pub fn guest_thread_rep(&mut self, idx: u32) -> Result { - match self.get_mut(idx)? { + match self.0.get_mut(idx)? { Slot::GuestThread { rep } => Ok(*rep), _ => bail!("handle is not a guest thread"), } @@ -590,11 +598,11 @@ impl HandleTable { /// /// Returns the internal `rep`. pub fn guest_thread_remove(&mut self, idx: u32) -> Result { - let rep = match self.get_mut(idx)? { + let rep = match self.0.get_mut(idx)? { Slot::GuestThread { rep } => *rep, _ => bail!("handle is not a guest thread"), }; - self.remove(idx)?; + self.0.remove(idx)?; Ok(rep) } } diff --git a/tests/all/component_model/resources.rs b/tests/all/component_model/resources.rs index 000ee2689c45..80fce005d6c2 100644 --- a/tests/all/component_model/resources.rs +++ b/tests/all/component_model/resources.rs @@ -222,7 +222,7 @@ fn mismatch_intrinsics() -> Result<()> { let ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "ctor")?; assert_eq!( ctor.call(&mut store, (100,)).unwrap_err().to_string(), - "handle index 2 used with the wrong type, expected guest-defined \ + "handle index 1 used with the wrong type, expected guest-defined \ resource but found a different guest-defined resource", ); @@ -1372,8 +1372,8 @@ fn guest_different_host_same() -> Result<()> { (func (export "f") (param i32 i32) ;; different types, but everything goes into the same ;; handle index namespace - (if (i32.ne (local.get 0) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get 0) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) ;; host should end up getting the same resource (call $f (local.get 0) (local.get 1)) diff --git a/tests/component-model b/tests/component-model index 85ef74272310..dac78059d47d 160000 --- a/tests/component-model +++ b/tests/component-model @@ -1 +1 @@ -Subproject commit 85ef7427231093b26eb636eba3d775f9a2f4adc0 +Subproject commit dac78059d47dadf3221a71548463fadb294412e3 diff --git a/tests/misc_testsuite/component-model/async/futures-must-write.wast b/tests/misc_testsuite/component-model/async/futures-must-write.wast index 3855558356dd..2158c888a8fe 100644 --- a/tests/misc_testsuite/component-model/async/futures-must-write.wast +++ b/tests/misc_testsuite/component-model/async/futures-must-write.wast @@ -79,7 +79,7 @@ ;; call 'start-future' to get the future we'll be working with (local $fr i32) (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 2) (local.get $fr)) + (if (i32.ne (i32.const 1) (local.get $fr)) (then unreachable)) ;; ok to immediately drop the readable end @@ -92,7 +92,7 @@ ;; call 'start-future' to get the future we'll be working with (local $fr i32) (local.set $fr (call $start-future)) - (if (i32.ne (i32.const 2) (local.get $fr)) + (if (i32.ne (i32.const 1) (local.get $fr)) (then unreachable)) ;; boom diff --git a/tests/misc_testsuite/component-model/async/partial-stream-copies.wast b/tests/misc_testsuite/component-model/async/partial-stream-copies.wast index e8a2caadd778..8632a8ea9286 100644 --- a/tests/misc_testsuite/component-model/async/partial-stream-copies.wast +++ b/tests/misc_testsuite/component-model/async/partial-stream-copies.wast @@ -43,16 +43,16 @@ ;; check the incoming readable stream end (global.set $insr (local.get 0)) - (if (i32.ne (i32.const 3) (global.get $insr)) + (if (i32.ne (i32.const 2) (global.get $insr)) (then unreachable)) ;; create a new stream r/w pair $outsr/$outsw (local.set $ret64 (call $stream.new)) (local.set $outsr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 4) (local.get $outsr)) + (if (i32.ne (i32.const 3) (local.get $outsr)) (then unreachable)) (global.set $outsw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 5) (global.get $outsw)) + (if (i32.ne (i32.const 4) (global.get $outsw)) (then unreachable)) ;; start async read on $insr which will block @@ -161,10 +161,10 @@ ;; create a new stream r/w pair $insr/$insw (local.set $ret64 (call $stream.new)) (local.set $insr (i32.wrap_i64 (local.get $ret64))) - (if (i32.ne (i32.const 2) (local.get $insr)) + (if (i32.ne (i32.const 1) (local.get $insr)) (then unreachable)) (local.set $insw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32)))) - (if (i32.ne (i32.const 3) (local.get $insw)) + (if (i32.ne (i32.const 2) (local.get $insw)) (then unreachable)) ;; call 'transform' which will return a readable stream $outsr eagerly @@ -173,7 +173,7 @@ (if (i32.ne (i32.const 2 (; RETURNED=2 | (0<<4) ;)) (local.get $ret)) (then unreachable)) (local.set $outsr (i32.load (local.get $retp))) - (if (i32.ne (i32.const 2) (local.get $outsr)) + (if (i32.ne (i32.const 1) (local.get $outsr)) (then unreachable)) ;; multiple write calls succeed until 12-byte buffer is filled diff --git a/tests/misc_testsuite/component-model/async/yield-when-cancelled.wast b/tests/misc_testsuite/component-model/async/yield-when-cancelled.wast index ed5643de24ff..bc2e679c0135 100644 --- a/tests/misc_testsuite/component-model/async/yield-when-cancelled.wast +++ b/tests/misc_testsuite/component-model/async/yield-when-cancelled.wast @@ -20,7 +20,7 @@ (i32.ne (i32.const 10) (local.get $i)) br_if $loop ) - + i32.const 1 ;; CALLBACK_CODE_YIELD ) @@ -56,7 +56,7 @@ (import "a" (instance $a (export "f" (func async)) )) - + (core module $m (import "" "f" (func $f (result i32))) (import "" "subtask.cancel" (func $subtask-cancel (param i32) (result i32))) @@ -64,9 +64,9 @@ (func (export "f") (local $status i32) (local $subtask i32) - + (local.set $status (call $f)) - (local.set $subtask (i32.shr_u (i32.const 4) (local.get $status))) + (local.set $subtask (i32.shr_u (local.get $status) (i32.const 4))) (local.set $status (i32.and (i32.const 0xF) (local.get $status))) (i32.ne (i32.const 1 (; STATUS_STARTED ;)) (local.get $status)) if unreachable end diff --git a/tests/misc_testsuite/component-model/resources.wast b/tests/misc_testsuite/component-model/resources.wast index baa633e8580a..de3e1c68998d 100644 --- a/tests/misc_testsuite/component-model/resources.wast +++ b/tests/misc_testsuite/component-model/resources.wast @@ -16,7 +16,7 @@ (local $r i32) (local.set $r (call $new (i32.const 100))) - (if (i32.ne (local.get $r) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) (call $drop (local.get $r)) @@ -97,13 +97,13 @@ ;; resources assigned sequentially (local.set $r1 (call $new (i32.const 100))) - (if (i32.ne (local.get $r1) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) (local.set $r2 (call $new (i32.const 200))) - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) (local.set $r3 (call $new (i32.const 300))) - (if (i32.ne (local.get $r3) (i32.const 4)) (then (unreachable))) + (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) ;; representations all look good (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) @@ -115,7 +115,7 @@ (local.set $r2 (call $new (i32.const 400))) ;; should have reused index 3 - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) ;; representations all look good (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) @@ -137,13 +137,13 @@ (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) ;; indices should be lifo - (if (i32.ne (local.get $r1) (i32.const 4)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) - (if (i32.ne (local.get $r3) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) ;; bump one more time (local.set $r4 (call $new (i32.const 800))) - (if (i32.ne (local.get $r4) (i32.const 5)) (then (unreachable))) + (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) ;; deallocate everything (call $drop (local.get $r1)) @@ -243,13 +243,13 @@ (local.set $r2 (call $ctor (i32.const 200))) ;; assert r1/r2 are sequential - (if (i32.ne (local.get $r1) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) ;; reallocate r1 and it should be reassigned the same index (call $drop (local.get $r1)) (local.set $r1 (call $ctor (i32.const 300))) - (if (i32.ne (local.get $r1) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) ;; internal values should match (call $assert (local.get $r1) (i32.const 300)) @@ -445,7 +445,7 @@ (import "" "ctor" (func $ctor (param i32) (result i32))) (func $start - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) ) (start $start) ) @@ -494,10 +494,10 @@ (import "" "drop" (func $drop (param i32))) (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) ) (func (export "dealloc") - (call $drop (i32.const 2)) + (call $drop (i32.const 1)) ) ) (core instance $i (instantiate $m @@ -554,10 +554,10 @@ (import "" "drop" (func $drop (param i32))) (func (export "alloc") - (if (i32.ne (call $ctor (i32.const 100)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) ) (func (export "dealloc") - (call $drop (i32.const 2)) + (call $drop (i32.const 1)) ) ) (core instance $i (instantiate $m @@ -619,12 +619,12 @@ (call $drop2 (call $new2 (i32.const 104))) ;; should be referencing the same namespace - (if (i32.ne (call $new1 (i32.const 105)) (i32.const 2)) (then (unreachable))) - (if (i32.ne (call $new2 (i32.const 105)) (i32.const 3)) (then (unreachable))) + (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) ;; use different drops out of order - (call $drop2 (i32.const 2)) - (call $drop1 (i32.const 3)) + (call $drop2 (i32.const 1)) + (call $drop1 (i32.const 2)) ) (start $start) @@ -704,8 +704,8 @@ ;; indexes start at 1 and while they have distinct types they should be ;; within the same table. - (if (i32.ne (local.get $r1) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) ;; nothing should be dropped yet (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) @@ -869,7 +869,7 @@ ;; table should be empty at this point, so a fresh allocation should get ;; index 2 - (if (i32.ne (call $ctor (i32.const 600)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) ) (start $start) @@ -1027,8 +1027,8 @@ (local.set $r1 (call $ctor (i32.const 100))) (local.set $r2 (call $ctor (i32.const 200))) - (if (i32.ne (local.get $r1) (i32.const 2)) (then (unreachable))) - (if (i32.ne (local.get $r2) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) (call $assert-borrow (local.get $r2) (i32.const 200)) (call $assert-borrow (local.get $r1) (i32.const 100)) @@ -1088,9 +1088,9 @@ ) (component instance $C1 $C) -(assert_trap (invoke "drop-r1-as-r2") "handle index 2 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") +(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") (component instance $C1 $C) -(assert_trap (invoke "return-r1-as-r2") "handle index 2 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") +(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") ;; Test that `resource.rep` is exempt from may-leave checks (component