wasmer_compiler/translator/
module.rs1use std::sync::atomic::{AtomicBool, Ordering};
7
8use crate::{FunctionBinaryReader, MiddlewareBinaryReader};
9
10use super::environ::ModuleEnvironment;
11use super::error::from_binaryreadererror_wasmerror;
12use super::sections::{
13 parse_data_section, parse_element_section, parse_export_section, parse_function_section,
14 parse_global_section, parse_import_section, parse_memory_section, parse_name_section,
15 parse_start_section, parse_table_section, parse_tag_section, parse_type_section,
16};
17use super::state::ModuleTranslationState;
18use itertools::Itertools;
19use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
20use wasmer_types::entity::PrimaryMap;
21use wasmer_types::{
22 InitExpr, InitExprOp, LocalFunctionIndex, ModuleInfo, TableIndex, WasmError, WasmResult,
23};
24use wasmparser::{BinaryReader, NameSectionReader, Parser, Payload};
25
26fn analyze_function_readonly_table(
27 function_body: &super::environ::FunctionBodyData<'_>,
28 table_index: TableIndex,
29) -> WasmResult<bool> {
30 let mut reader =
31 MiddlewareBinaryReader::new_with_offset(function_body.data, function_body.module_offset);
32
33 let local_count = reader.read_local_count()?;
34 for _ in 0..local_count {
35 reader.read_local_decl()?;
36 }
37
38 while !reader.eof() {
39 match reader.read_operator()? {
40 wasmparser::Operator::TableSet { table }
41 | wasmparser::Operator::TableFill { table }
42 | wasmparser::Operator::TableGrow { table }
43 if TableIndex::from_u32(table) == table_index =>
44 {
45 return Ok(false);
46 }
47 wasmparser::Operator::TableCopy { dst_table, .. }
48 if TableIndex::from_u32(dst_table) == table_index =>
49 {
50 return Ok(false);
51 }
52 wasmparser::Operator::TableInit { table, .. }
53 if TableIndex::from_u32(table) == table_index =>
54 {
55 return Ok(false);
56 }
57 wasmparser::Operator::ElemDrop { .. } => return Ok(false),
58 _ => {}
59 }
60 }
61
62 Ok(true)
63}
64
65pub(crate) fn analyze_readonly_funcref_table(
66 module: &ModuleInfo,
67 function_body_inputs: &PrimaryMap<LocalFunctionIndex, super::environ::FunctionBodyData<'_>>,
68) -> WasmResult<Option<TableIndex>> {
69 let Ok(table_index) = module
70 .tables
71 .iter()
72 .filter_map(|(index, table)| {
73 if module.local_table_index(index).is_some() && table.is_fixed_funcref_table() {
74 Some(index)
75 } else {
76 None
77 }
78 })
79 .exactly_one()
80 else {
81 return Ok(None);
82 };
83
84 let table = module.tables[table_index];
85 let Ok(table_initializer) = module
86 .table_initializers
87 .iter()
88 .filter(|initializer| initializer.table_index == table_index)
89 .exactly_one()
90 else {
91 return Ok(None);
92 };
93
94 if table_initializer.offset_expr != InitExpr::new([InitExprOp::I32Const(1)])
96 || table_initializer.elements.len() as u32 != table.minimum.saturating_sub(1)
97 {
98 return Ok(None);
99 }
100
101 if table_initializer
103 .elements
104 .iter()
105 .any(|func_index| module.is_imported_function(*func_index))
106 {
107 return Ok(None);
108 }
109
110 let readonly = AtomicBool::new(true);
111 function_body_inputs
112 .iter()
113 .collect_vec()
114 .par_iter()
115 .map(|(_local_func_index, function_body)| {
116 if !readonly.load(Ordering::Relaxed) {
117 return Ok(());
118 }
119
120 if !analyze_function_readonly_table(function_body, table_index)? {
121 readonly.store(false, Ordering::Relaxed);
122 }
123
124 Ok(())
125 })
126 .collect::<WasmResult<Vec<_>>>()?;
127
128 if !readonly.load(Ordering::Relaxed) {
129 return Ok(None);
130 }
131
132 Ok(Some(table_index))
133}
134
135pub fn translate_module<'data>(
138 data: &'data [u8],
139 environ: &mut ModuleEnvironment<'data>,
140) -> WasmResult<ModuleTranslationState> {
141 let mut module_translation_state = ModuleTranslationState::new();
142
143 for payload in Parser::new(0).parse_all(data) {
144 match payload.map_err(from_binaryreadererror_wasmerror)? {
145 Payload::Version { .. } | Payload::End { .. } => {}
146
147 Payload::TypeSection(types) => {
148 parse_type_section(types, &mut module_translation_state, environ)?;
149 }
150
151 Payload::ImportSection(imports) => {
152 parse_import_section(imports, environ)?;
153 }
154
155 Payload::FunctionSection(functions) => {
156 parse_function_section(functions, environ)?;
157 }
158
159 Payload::TableSection(tables) => {
160 parse_table_section(tables, environ)?;
161 }
162
163 Payload::MemorySection(memories) => {
164 parse_memory_section(memories, environ)?;
165 }
166
167 Payload::GlobalSection(globals) => {
168 parse_global_section(globals, environ)?;
169 }
170
171 Payload::ExportSection(exports) => {
172 parse_export_section(exports, environ)?;
173 }
174
175 Payload::StartSection { func, .. } => {
176 parse_start_section(func, environ)?;
177 }
178
179 Payload::ElementSection(elements) => {
180 parse_element_section(elements, environ)?;
181 }
182
183 Payload::CodeSectionStart { .. } => {}
184 Payload::CodeSectionEntry(code) => {
185 let mut code = code.get_binary_reader();
186 let size = code.bytes_remaining();
187 let offset = code.original_position();
188 environ.define_function_body(
189 &module_translation_state,
190 code.read_bytes(size)
191 .map_err(from_binaryreadererror_wasmerror)?,
192 offset,
193 )?;
194 }
195
196 Payload::DataSection(data) => {
197 parse_data_section(data, environ)?;
198 }
199
200 Payload::DataCountSection { count, .. } => {
201 environ.reserve_passive_data(count)?;
202 }
203
204 Payload::TagSection(t) => parse_tag_section(t, environ)?,
205
206 Payload::CustomSection(sectionreader) => {
207 let name = sectionreader.name();
209 environ.custom_section(name, sectionreader.data())?;
210 if name == "name" {
211 parse_name_section(
212 NameSectionReader::new(BinaryReader::new(
213 sectionreader.data(),
214 sectionreader.data_offset(),
215 )),
216 environ,
217 )?;
218 }
219 }
220
221 Payload::UnknownSection { .. } => unreachable!(),
222 k => {
223 return Err(WasmError::Unsupported(format!(
224 "Unsupported paylod kind: {k:?}"
225 )));
226 }
227 }
228 }
229
230 Ok(module_translation_state)
231}