Skip to content

Commit 94deda1

Browse files
authored
Merge pull request #1 from tonystr/patch-1
fix: add missing code sections from decode data section
2 parents 7ddd9fe + 5b9aeea commit 94deda1

File tree

1 file changed

+210
-4
lines changed

1 file changed

+210
-4
lines changed

src/13_build_runtime_initialize_memory.md

Lines changed: 210 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,89 @@ Each field is as follows:
310310

311311
Next, implement the decoding process.
312312

313-
```diff
314313
src/binary/module.rs
314+
```diff
315+
diff --git a/src/binary/module.rs b/src/binary/module.rs
316+
index 3e59d35..46db8dc 100644
317+
--- a/src/binary/module.rs
318+
+++ b/src/binary/module.rs
319+
@@ -3,7 +3,8 @@ use super::{
320+
opcode::Opcode,
321+
section::{Function, SectionCode},
322+
types::{
323+
- Export, ExportDesc, FuncType, FunctionLocal, Import, ImportDesc, Limits, Memory, ValueType,
324+
+ Data, Export, ExportDesc, FuncType, FunctionLocal, Import, ImportDesc, Limits, Memory,
325+
+ ValueType,
326+
},
327+
};
328+
use nom::{
329+
@@ -21,6 +22,7 @@ pub struct Module {
330+
pub magic: String,
331+
pub version: u32,
332+
pub memory_section: Option<Vec<Memory>>,
333+
+ pub data_section: Option<Vec<Data>>,
334+
pub type_section: Option<Vec<FuncType>>,
335+
pub function_section: Option<Vec<u32>>,
336+
pub code_section: Option<Vec<Function>>,
337+
@@ -34,6 +36,7 @@ impl Default for Module {
338+
magic: "\0asm".to_string(),
339+
version: 1,
340+
memory_section: None,
341+
+ data_section: None,
342+
type_section: None,
343+
function_section: None,
344+
code_section: None,
345+
@@ -75,6 +78,10 @@ impl Module {
346+
let (_, memory) = decode_memory_section(section_contents)?;
347+
module.memory_section = Some(vec![memory]);
348+
}
349+
+ SectionCode::Data => {
350+
+ let (_, data) = deocde_data_section(section_contents)?;
351+
+ module.data_section = Some(data);
352+
+ }
353+
SectionCode::Type => {
354+
let (_, types) = decode_type_section(section_contents)?;
355+
module.type_section = Some(types);
356+
@@ -95,7 +102,6 @@ impl Module {
357+
let (_, imports) = decode_import_section(section_contents)?;
358+
module.import_section = Some(imports);
359+
}
360+
- _ => todo!(),
361+
};
362+
363+
remaining = rest;
364+
@@ -286,6 +292,31 @@ fn decode_limits(input: &[u8]) -> IResult<&[u8], Limits> {
365+
Ok((input, Limits { min, max }))
366+
}
367+
368+
+fn decode_expr(input: &[u8]) -> IResult<&[u8], u32> {
369+
+ let (input, _) = leb128_u32(input)?;
370+
+ let (input, offset) = leb128_u32(input)?;
371+
+ let (input, _) = leb128_u32(input)?;
372+
+ Ok((input, offset))
373+
+}
374+
+
375+
+fn deocde_data_section(input: &[u8]) -> IResult<&[u8], Vec<Data>> {
376+
+ let (mut input, count) = leb128_u32(input)?; // 1
377+
+ let mut data = vec![];
378+
+ for _ in 0..count {
379+
+ let (rest, memory_index) = leb128_u32(input)?;
380+
+ let (rest, offset) = decode_expr(rest)?; // 2
381+
+ let (rest, size) = leb128_u32(rest)?; // 3
382+
+ let (rest, init) = take(size)(rest)?; // 4
383+
+ data.push(Data {
384+
+ memory_index,
385+
+ offset,
386+
+ init: init.into(),
387+
+ });
388+
+ input = rest;
389+
+ }
390+
+ Ok((input, data))
391+
+}
392+
+
393+
fn decode_name(input: &[u8]) -> IResult<&[u8], String> {
394+
let (input, size) = leb128_u32(input)?;
395+
let (input, name) = take(size)(input)?;
315396
```
316397

317398
In the decoding process, the following steps are performed:
@@ -325,8 +406,70 @@ In the decoding process, the following steps are performed:
325406

326407
Next, add tests to ensure the implementation is correct.
327408

328-
```diff
329409
src/binary/module.rs
410+
```diff
411+
diff --git a/src/binary/module.rs b/src/binary/module.rs
412+
index c0c1aff..40f20fd 100644
413+
--- a/src/binary/module.rs
414+
+++ b/src/binary/module.rs
415+
@@ -333,7 +333,7 @@ mod tests {
416+
module::Module,
417+
section::Function,
418+
types::{
419+
- Export, ExportDesc, FuncType, FunctionLocal, Import, ImportDesc, Limits, Memory,
420+
+ Data, Export, ExportDesc, FuncType, FunctionLocal, Import, ImportDesc, Limits, Memory,
421+
ValueType,
422+
},
423+
};
424+
@@ -547,4 +547,48 @@ mod tests {
425+
}
426+
Ok(())
427+
}
428+
+
429+
+ #[test]
430+
+ fn decode_data() -> Result<()> {
431+
+ let tests = vec![
432+
+ (
433+
+ "(module (memory 1) (data (i32.const 0) \"hello\"))",
434+
+ vec![Data {
435+
+ memory_index: 0,
436+
+ offset: 0,
437+
+ init: "hello".as_bytes().to_vec(),
438+
+ }],
439+
+ ),
440+
+ (
441+
+ "(module (memory 1) (data (i32.const 0) \"hello\") (data (i32.const 5) \"world\"))",
442+
+ vec![
443+
+ Data {
444+
+ memory_index: 0,
445+
+ offset: 0,
446+
+ init: b"hello".into(),
447+
+ },
448+
+ Data {
449+
+ memory_index: 0,
450+
+ offset: 5,
451+
+ init: b"world".into(),
452+
+ },
453+
+ ],
454+
+ ),
455+
+ ];
456+
+
457+
+ for (wasm, data) in tests {
458+
+ let module = Module::new(&wat::parse_str(wasm)?)?;
459+
+ assert_eq!(
460+
+ module,
461+
+ Module {
462+
+ memory_section: Some(vec![Memory {
463+
+ limits: Limits { min: 1, max: None }
464+
+ }]),
465+
+ data_section: Some(data),
466+
+ ..Default::default()
467+
+ }
468+
+ );
469+
+ }
470+
+ Ok(())
471+
+ }
472+
}
330473
```
331474

332475
```sh
@@ -349,15 +492,78 @@ test execution::runtime::tests::not_found_imported_func ... ok
349492

350493
Now that we can retrieve memory data, we will proceed to place the data on the `Runtime` memory.
351494

352-
```diff
353495
src/execution/store.rs
496+
```diff
497+
diff --git a/src/execution/store.rs b/src/execution/store.rs
498+
index efadc19..cad96ca 100644
499+
--- a/src/execution/store.rs
500+
+++ b/src/execution/store.rs
501+
@@ -5,7 +5,7 @@ use crate::binary::{
502+
module::Module,
503+
types::{ExportDesc, FuncType, ImportDesc, ValueType},
504+
};
505+
-use anyhow::{bail, Result};
506+
+use anyhow::{anyhow, bail, Result};
507+
508+
pub const PAGE_SIZE: u32 = 65536; // 64Ki
509+
510+
@@ -146,6 +146,22 @@ impl Store {
511+
}
512+
}
513+
514+
+ if let Some(ref sections) = module.data_section {
515+
+ for data in sections {
516+
+ let memory = memories
517+
+ .get_mut(data.memory_index as usize)
518+
+ .ok_or(anyhow!("not found memory"))?;
519+
+
520+
+ let offset = data.offset as usize;
521+
+ let init = &data.init;
522+
+
523+
+ if offset + init.len() > memory.data.len() {
524+
+ bail!("data is too large to fit in memory");
525+
+ }
526+
+ memory.data[offset..offset + init.len()].copy_from_slice(init);
527+
+ }
528+
+ }
529+
+
530+
Ok(Self {
531+
funcs,
532+
memories,
354533
```
355534

356535
The process is simple, copying the data from the `Data Section` to the specified location in memory.
357536
Finally, add tests to ensure the implementation is correct.
358537

359-
```diff
360538
src/execution/store.rs
539+
```diff
540+
diff --git a/src/execution/store.rs b/src/execution/store.rs
541+
index cad96ca..1bb1192 100644
542+
--- a/src/execution/store.rs
543+
+++ b/src/execution/store.rs
544+
@@ -169,3 +169,32 @@ impl Store {
545+
})
546+
}
547+
}
548+
+
549+
+#[cfg(test)]
550+
+mod test {
551+
+ use super::Store;
552+
+ use crate::binary::module::Module;
553+
+ use anyhow::Result;
554+
+
555+
+ #[test]
556+
+ fn init_memory() -> Result<()> {
557+
+ let wasm = wat::parse_file("src/fixtures/memory.wat")?;
558+
+ let module = Module::new(&wasm)?;
559+
+ let store = Store::new(module)?;
560+
+ assert_eq!(store.memories.len(), 1);
561+
+ assert_eq!(store.memories[0].data.len(), 65536);
562+
+ assert_eq!(&store.memories[0].data[0..5], b"hello");
563+
+ assert_eq!(&store.memories[0].data[5..10], b"world");
564+
+ Ok(())
565+
+ }
566+
+}
361567
```
362568

363569
```sh

0 commit comments

Comments
 (0)