Skip to content

Commit 568a83b

Browse files
committed
Fixed no_std support; disallow cm-async calls with rr; add CI tests for
no_std
1 parent 0e3d350 commit 568a83b

File tree

7 files changed

+139
-36
lines changed

7 files changed

+139
-36
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ jobs:
547547
test: >
548548
cargo check -p wasmtime --no-default-features --features runtime,component-model &&
549549
cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async,debug-builtins &&
550+
cargo check -p wasmtime --no-default-features --features runtime,rr,component-model &&
550551
cargo check -p cranelift-control --no-default-features &&
551552
cargo check -p pulley-interpreter --features encode,decode,disas,interp &&
552553
cargo check -p wasmtime-wasi-io --no-default-features

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,6 @@ tokio-util = "0.7.16"
425425
arbtest = "0.3.2"
426426
rayon = "1.5.3"
427427
regex = "1.9.1"
428-
sha2 = { version = "0.10.2", default-features = false }
429428

430429
# =============================================================================
431430
#

crates/environ/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ wasmprinter = { workspace = true, optional = true }
3737
wasmtime-component-util = { workspace = true, optional = true }
3838
semver = { workspace = true, optional = true, features = ['serde'] }
3939
smallvec = { workspace = true, features = ['serde'] }
40-
sha2 = { workspace = true }
40+
# NB: LLVM unable to compile sha2 with 'asm' in 'no_std' as of Rustc/Cargo version 1.91.1.
41+
# Currently uses 'force-soft' in 'no_std', but remove if fixed.
42+
sha2 = { version = "0.10.2", default-features = false, features = ['force-soft'] }
4143

4244
[dev-dependencies]
4345
clap = { workspace = true, features = ['default'] }

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5022,6 +5022,11 @@ pub(crate) fn queue_call<T: 'static, R: Send + 'static>(
50225022
mut store: StoreContextMut<T>,
50235023
prepared: PreparedCall<R>,
50245024
) -> Result<impl Future<Output = Result<(R, oneshot::Receiver<()>)>> + Send + 'static + use<T, R>> {
5025+
#[cfg(feature = "rr")]
5026+
assert!(
5027+
!(store.engine().is_recording() || store.engine().is_replaying()),
5028+
"component model async ABI not supported during recording or replaying"
5029+
);
50255030
let PreparedCall {
50265031
handle,
50275032
thread,

crates/wasmtime/src/runtime/rr/core.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ impl Recorder for RecordBuffer {
434434
fn flush(&mut self) -> Result<()> {
435435
log::debug!("Flushing record buffer...");
436436
for e in self.buf.drain(..) {
437-
io::to_record_writer(&e, &mut self.writer)?;
437+
io::to_record_writer(&e, &mut *self.writer)?;
438438
}
439439
return Ok(());
440440
}
@@ -467,7 +467,7 @@ impl Iterator for ReplayBuffer {
467467
return None;
468468
}
469469
let ret = 'event_loop: loop {
470-
let result = io::from_replay_reader(&mut self.reader, &mut self.deser_buffer);
470+
let result = io::from_replay_reader(&mut *self.reader, &mut self.deser_buffer);
471471
match result {
472472
Err(e) => {
473473
break 'event_loop Some(Err(ReplayError::FailedRead(e)));

crates/wasmtime/src/runtime/rr/core/io.rs

Lines changed: 113 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,118 @@ cfg_if::cfg_if! {
1515
impl<T: Read + Seek + Send + Sync> ReplayReader for T {}
1616

1717
} else {
18-
use core::{convert::AsRef, iter::Extend};
18+
use core::iter::Extend;
19+
use postcard::{ser_flavors, de_flavors};
20+
21+
type PcError = postcard::Error;
22+
type PcResult<T> = postcard::Result<T>;
1923

2024
/// A writer for recording in RR.
21-
pub trait RecordWriter: Extend<u8> + Send + Sync + Any {}
22-
impl<T: Extend<u8> + Send + Sync + Any> RecordWriter for T {}
25+
///
26+
/// In `no_std`, types must provide explicit write capabilities.
27+
pub trait RecordWriter: Send + Sync + Any {
28+
/// Write all the bytes from `buf` to the writer
29+
fn write(&mut self, buf: &[u8]) -> Result<usize>;
30+
/// Flush the writer
31+
fn flush(&mut self) -> Result<()>;
32+
}
33+
impl <T: Send + Sync + Any + Extend<u8>> RecordWriter for T {
34+
fn write(&mut self, buf: &[u8]) -> Result<usize> {
35+
self.extend(buf.iter().copied());
36+
Ok(buf.len())
37+
}
38+
fn flush(&mut self) -> Result<()> {
39+
Ok(())
40+
}
41+
}
2342

2443
/// A reader for replaying in RR.
2544
///
26-
/// In `no_std`, types must provide explicit read/seek capabilities
27-
/// to a underlying byte slice through these methods.
28-
pub trait ReplayReader: AsRef<[u8]> + Send + Sync {
29-
/// Advance the reader's internal cursor by `cnt` bytes
30-
fn advance(&mut self, cnt: usize);
31-
/// Seek to an absolute position `pos` in the reader
45+
/// In `no_std`, types must provide explicit read/seek capabilities.
46+
pub trait ReplayReader: Send + Sync {
47+
/// Read bytes into `buf`, returning number of bytes read.
48+
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
49+
/// Seek to an absolute position `pos` in the reader.
3250
fn seek(&mut self, pos: usize);
3351
}
3452

53+
/// Resembles a `WriteFlavor` in postcard
54+
struct RecordWriterFlavor<'a, W: RecordWriter + ?Sized> {
55+
writer: &'a mut W,
56+
}
57+
58+
impl<'a, W: RecordWriter + ?Sized> ser_flavors::Flavor for RecordWriterFlavor<'a, W> {
59+
type Output = ();
60+
61+
#[inline]
62+
fn try_push(&mut self, data: u8) -> PcResult<()> {
63+
self.writer.write(&[data]).map_err(|_| PcError::SerializeBufferFull)?;
64+
Ok(())
65+
}
66+
#[inline]
67+
fn try_extend(&mut self, data: &[u8]) -> PcResult<()> {
68+
self.writer.write(data).map_err(|_| PcError::SerializeBufferFull)?;
69+
Ok(())
70+
}
71+
#[inline]
72+
fn finalize(self) -> PcResult<Self::Output> {
73+
self.writer.flush().map_err(|_| PcError::SerializeBufferFull)?;
74+
Ok(())
75+
}
76+
}
77+
78+
struct ReplayReaderFlavor<'a, 'b, R: ReplayReader + ?Sized> {
79+
reader: &'a mut R,
80+
scratch: &'b mut [u8],
81+
}
82+
83+
impl<'de, 'a, 'b, R: ReplayReader + ?Sized> de_flavors::Flavor<'de> for ReplayReaderFlavor<'a, 'b, R>
84+
where 'b: 'de, 'a: 'de
85+
{
86+
type Remainder = ();
87+
type Source = ();
88+
89+
#[inline]
90+
fn pop(&mut self) -> PcResult<u8> {
91+
let scratch = core::mem::replace(&mut self.scratch, &mut []);
92+
if scratch.is_empty() {
93+
return PcResult::Err(PcError::DeserializeUnexpectedEnd);
94+
}
95+
let (slice, rest) = scratch.split_at_mut(1);
96+
self.scratch = rest;
97+
98+
match self.reader.read(slice) {
99+
Ok(1) => Ok(slice[0]),
100+
_ => PcResult::Err(PcError::DeserializeUnexpectedEnd),
101+
}
102+
}
103+
104+
#[inline]
105+
fn try_take_n(&mut self, ct: usize) -> postcard::Result<&'de [u8]> {
106+
let scratch = core::mem::replace(&mut self.scratch, &mut []);
107+
if scratch.len() < ct {
108+
return PcResult::Err(PcError::DeserializeUnexpectedEnd);
109+
}
110+
let (slice, rest) = scratch.split_at_mut(ct);
111+
self.scratch = rest;
112+
113+
let mut total_read = 0;
114+
while total_read < ct {
115+
match self.reader.read(&mut slice[total_read..]) {
116+
Ok(0) => return PcResult::Err(PcError::DeserializeUnexpectedEnd),
117+
Ok(n) => total_read += n,
118+
Err(_) => return PcResult::Err(PcError::DeserializeUnexpectedEnd),
119+
}
120+
}
121+
122+
Ok(slice)
123+
}
124+
125+
#[inline]
126+
fn finalize(self) -> PcResult<Self::Remainder> {
127+
Ok(())
128+
}
129+
}
35130
}
36131
}
37132

@@ -41,15 +136,16 @@ cfg_if::cfg_if! {
41136
pub(super) fn to_record_writer<T, W>(value: &T, writer: &mut W) -> Result<()>
42137
where
43138
T: Serialize + ?Sized,
44-
W: RecordWriter,
139+
W: RecordWriter + ?Sized,
45140
{
46141
#[cfg(feature = "std")]
47142
{
48143
postcard::to_io(value, writer)?;
49144
}
50145
#[cfg(not(feature = "std"))]
51146
{
52-
postcard::to_extend(value, writer)?;
147+
let flavor = RecordWriterFlavor { writer };
148+
postcard::serialize_with_flavor(value, flavor)?;
53149
}
54150
Ok(())
55151
}
@@ -61,18 +157,18 @@ where
61157
pub(super) fn from_replay_reader<'a, T, R>(reader: &'a mut R, scratch: &'a mut [u8]) -> Result<T>
62158
where
63159
T: Deserialize<'a>,
64-
R: ReplayReader,
160+
R: ReplayReader + ?Sized,
65161
{
66162
#[cfg(feature = "std")]
67163
{
68164
Ok(postcard::from_io((reader, scratch))?.0)
69165
}
70166
#[cfg(not(feature = "std"))]
71167
{
72-
let bytes = reader.as_ref();
73-
let original_len = bytes.len();
74-
let (value, new) = postcard::take_from_bytes(bytes)?;
75-
reader.advance(new.len() - original_len);
76-
Ok(value)
168+
let flavor = ReplayReaderFlavor { reader, scratch };
169+
let mut deserializer = postcard::Deserializer::from_flavor(flavor);
170+
let t = T::deserialize(&mut deserializer)?;
171+
deserializer.finalize()?;
172+
Ok(t)
77173
}
78174
}

tests/all/rr.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use wasmtime::{
77
ReplaySettings, Store,
88
};
99

10-
#[cfg(feature = "component-model")]
10+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
1111
use wasmtime::component::{Component, HasSelf, Linker as ComponentLinker, bindgen};
1212

1313
struct TestState;
@@ -150,7 +150,7 @@ where
150150
}
151151

152152
/// Run a component test with recording and replay, testing both with and without validation
153-
#[cfg(feature = "component-model")]
153+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
154154
fn run_component_test<F, R>(component_wat: &str, setup_linker: F, test_fn: R) -> Result<()>
155155
where
156156
F: Fn(&mut ComponentLinker<TestState>) -> Result<()> + Clone,
@@ -190,7 +190,7 @@ where
190190
}
191191

192192
/// Run a component test with recording and replay with specified validation setting
193-
#[cfg(feature = "component-model")]
193+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
194194
async fn run_component_test_with_validation<F, R>(
195195
component_wat: &str,
196196
setup_linker: F,
@@ -436,7 +436,7 @@ fn test_recording_panics_for_core_module_memory_export() {
436436
// Few Parameters and Few Results (not exceeding MAX_FLAT_PARAMS=16 and
437437
// MAX_FLAT_RESULTS=1)
438438
#[test]
439-
#[cfg(feature = "component-model")]
439+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
440440
fn test_component_under_max_params_results() -> Result<()> {
441441
mod test {
442442
use super::*;
@@ -545,7 +545,7 @@ fn test_component_under_max_params_results() -> Result<()> {
545545

546546
// Large Record (exceeding MAX_FLAT_PARAMS=16 and MAX_FLAT_RESULTS=1)
547547
#[test]
548-
#[cfg(feature = "component-model")]
548+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
549549
fn test_component_over_max_params_results() -> Result<()> {
550550
mod test {
551551
use super::*;
@@ -709,7 +709,7 @@ fn test_component_over_max_params_results() -> Result<()> {
709709
}
710710

711711
#[test]
712-
#[cfg(feature = "component-model")]
712+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
713713
fn test_component_tuple() -> Result<()> {
714714
mod test {
715715
use super::*;
@@ -805,7 +805,7 @@ fn test_component_tuple() -> Result<()> {
805805
}
806806

807807
#[test]
808-
#[cfg(feature = "component-model")]
808+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
809809
fn test_component_string() -> Result<()> {
810810
mod test {
811811
use super::*;
@@ -904,7 +904,7 @@ fn test_component_string() -> Result<()> {
904904
}
905905

906906
#[test]
907-
#[cfg(feature = "component-model")]
907+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
908908
fn test_component_variant() -> Result<()> {
909909
mod test {
910910
use super::*;
@@ -1019,7 +1019,7 @@ fn test_component_variant() -> Result<()> {
10191019
}
10201020

10211021
#[test]
1022-
#[cfg(feature = "component-model")]
1022+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
10231023
fn test_component_result() -> Result<()> {
10241024
mod test {
10251025
use super::*;
@@ -1156,7 +1156,7 @@ fn test_component_result() -> Result<()> {
11561156
}
11571157

11581158
#[test]
1159-
#[cfg(feature = "component-model")]
1159+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
11601160
fn test_component_list() -> Result<()> {
11611161
mod test {
11621162
use super::*;
@@ -1286,7 +1286,7 @@ fn test_component_list() -> Result<()> {
12861286
}
12871287

12881288
#[test]
1289-
#[cfg(feature = "component-model")]
1289+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
12901290
fn test_component_option() -> Result<()> {
12911291
mod test {
12921292
use super::*;
@@ -1406,7 +1406,7 @@ fn test_component_option() -> Result<()> {
14061406
test::run()
14071407
}
14081408

1409-
#[cfg(feature = "component-model")]
1409+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
14101410
#[test]
14111411
fn test_component_builtins() -> Result<()> {
14121412
run_component_test(
@@ -1511,7 +1511,7 @@ fn test_component_builtins() -> Result<()> {
15111511
)
15121512
}
15131513

1514-
#[cfg(feature = "component-model")]
1514+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
15151515
fn cabi_realloc_wat() -> String {
15161516
r#"
15171517
(global $bump (mut i32) (i32.const 256))
@@ -1539,7 +1539,7 @@ fn cabi_realloc_wat() -> String {
15391539
"#.to_string()
15401540
}
15411541

1542-
#[cfg(feature = "component-model")]
1542+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
15431543
fn shims_wat(params: &str) -> String {
15441544
let count = params.split_whitespace().count();
15451545
let locals_get = (0..count)
@@ -1565,7 +1565,7 @@ fn shims_wat(params: &str) -> String {
15651565
)
15661566
}
15671567

1568-
#[cfg(feature = "component-model")]
1568+
#[cfg(all(feature = "component-model", feature = "component-model-async"))]
15691569
fn instantiation_wat(core_name: &str, lift_sig: &str) -> String {
15701570
format!(
15711571
r#"

0 commit comments

Comments
 (0)