1 //! Helper functions to gather information for each of the non-function sections of a
2 //! WebAssembly module.
3 //!
4 //! The code of these helper functions is straightforward since they only read metadata
5 //! about linear memories, tables, globals, etc. and store them for later use.
6 //!
7 //! The special case of the initialize expressions for table elements offsets or global variables
8 //! is handled, according to the semantics of WebAssembly, to only specific expressions that are
9 //! interpreted on the fly.
10 use crate::environ::{Alias, ModuleEnvironment, WasmError, WasmResult};
11 use crate::state::ModuleTranslationState;
12 use crate::translation_utils::{
13 tabletype_to_type, type_to_type, DataIndex, ElemIndex, EntityIndex, EntityType, Event,
14 EventIndex, FuncIndex, Global, GlobalIndex, GlobalInit, InstanceIndex, Memory, MemoryIndex,
15 ModuleIndex, Table, TableElementType, TableIndex, TypeIndex,
16 };
17 use crate::wasm_unsupported;
18 use core::convert::TryFrom;
19 use core::convert::TryInto;
20 use cranelift_codegen::ir::immediates::V128Imm;
21 use cranelift_entity::packed_option::ReservedValue;
22 use cranelift_entity::EntityRef;
23 use std::boxed::Box;
24 use std::vec::Vec;
25 use wasmparser::{
26 self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind,
27 ElementSectionReader, EventSectionReader, EventType, Export, ExportSectionReader, ExternalKind,
28 FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
29 ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator,
30 TableSectionReader, TableType, TypeDef, TypeSectionReader,
31 };
32
entity_type( ty: ImportSectionEntryType, environ: &mut dyn ModuleEnvironment<'_>, ) -> WasmResult<EntityType>33 fn entity_type(
34 ty: ImportSectionEntryType,
35 environ: &mut dyn ModuleEnvironment<'_>,
36 ) -> WasmResult<EntityType> {
37 Ok(match ty {
38 ImportSectionEntryType::Function(sig) => {
39 EntityType::Function(environ.type_to_signature(TypeIndex::from_u32(sig))?)
40 }
41 ImportSectionEntryType::Module(sig) => {
42 EntityType::Module(environ.type_to_module_type(TypeIndex::from_u32(sig))?)
43 }
44 ImportSectionEntryType::Instance(sig) => {
45 EntityType::Instance(environ.type_to_instance_type(TypeIndex::from_u32(sig))?)
46 }
47 ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)),
48 ImportSectionEntryType::Event(evt) => EntityType::Event(event(evt)),
49 ImportSectionEntryType::Global(ty) => {
50 EntityType::Global(global(ty, environ, GlobalInit::Import)?)
51 }
52 ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty, environ)?),
53 })
54 }
55
memory(ty: MemoryType) -> Memory56 fn memory(ty: MemoryType) -> Memory {
57 match ty {
58 MemoryType::M32 { limits, shared } => Memory {
59 minimum: limits.initial,
60 maximum: limits.maximum,
61 shared: shared,
62 },
63 // FIXME(#2361)
64 MemoryType::M64 { .. } => unimplemented!(),
65 }
66 }
67
event(e: EventType) -> Event68 fn event(e: EventType) -> Event {
69 Event {
70 ty: TypeIndex::from_u32(e.type_index),
71 }
72 }
73
table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult<Table>74 fn table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult<Table> {
75 Ok(Table {
76 wasm_ty: ty.element_type.try_into()?,
77 ty: match tabletype_to_type(ty.element_type, environ)? {
78 Some(t) => TableElementType::Val(t),
79 None => TableElementType::Func,
80 },
81 minimum: ty.limits.initial,
82 maximum: ty.limits.maximum,
83 })
84 }
85
global( ty: GlobalType, environ: &mut dyn ModuleEnvironment<'_>, initializer: GlobalInit, ) -> WasmResult<Global>86 fn global(
87 ty: GlobalType,
88 environ: &mut dyn ModuleEnvironment<'_>,
89 initializer: GlobalInit,
90 ) -> WasmResult<Global> {
91 Ok(Global {
92 wasm_ty: ty.content_type.try_into()?,
93 ty: type_to_type(ty.content_type, environ).unwrap(),
94 mutability: ty.mutable,
95 initializer,
96 })
97 }
98
99 /// Parses the Type section of the wasm module.
parse_type_section<'a>( types: TypeSectionReader<'a>, module_translation_state: &mut ModuleTranslationState, environ: &mut dyn ModuleEnvironment<'a>, ) -> WasmResult<()>100 pub fn parse_type_section<'a>(
101 types: TypeSectionReader<'a>,
102 module_translation_state: &mut ModuleTranslationState,
103 environ: &mut dyn ModuleEnvironment<'a>,
104 ) -> WasmResult<()> {
105 let count = types.get_count();
106 module_translation_state.wasm_types.reserve(count as usize);
107 environ.reserve_types(count)?;
108
109 for entry in types {
110 match entry? {
111 TypeDef::Func(wasm_func_ty) => {
112 environ.declare_type_func(wasm_func_ty.clone().try_into()?)?;
113 module_translation_state
114 .wasm_types
115 .push((wasm_func_ty.params, wasm_func_ty.returns));
116 }
117 TypeDef::Module(t) => {
118 let imports = t
119 .imports
120 .iter()
121 .map(|i| Ok((i.module, i.field, entity_type(i.ty, environ)?)))
122 .collect::<WasmResult<Vec<_>>>()?;
123 let exports = t
124 .exports
125 .iter()
126 .map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
127 .collect::<WasmResult<Vec<_>>>()?;
128 environ.declare_type_module(&imports, &exports)?;
129 }
130 TypeDef::Instance(t) => {
131 let exports = t
132 .exports
133 .iter()
134 .map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
135 .collect::<WasmResult<Vec<_>>>()?;
136 environ.declare_type_instance(&exports)?;
137 }
138 }
139 }
140 Ok(())
141 }
142
143 /// Parses the Import section of the wasm module.
parse_import_section<'data>( imports: ImportSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>144 pub fn parse_import_section<'data>(
145 imports: ImportSectionReader<'data>,
146 environ: &mut dyn ModuleEnvironment<'data>,
147 ) -> WasmResult<()> {
148 environ.reserve_imports(imports.get_count())?;
149
150 for entry in imports {
151 let import = entry?;
152 match import.ty {
153 ImportSectionEntryType::Function(sig) => {
154 environ.declare_func_import(
155 TypeIndex::from_u32(sig),
156 import.module,
157 import.field,
158 )?;
159 }
160 ImportSectionEntryType::Module(sig) => {
161 environ.declare_module_import(
162 TypeIndex::from_u32(sig),
163 import.module,
164 import.field,
165 )?;
166 }
167 ImportSectionEntryType::Instance(sig) => {
168 environ.declare_instance_import(
169 TypeIndex::from_u32(sig),
170 import.module,
171 import.field,
172 )?;
173 }
174 ImportSectionEntryType::Memory(ty) => {
175 environ.declare_memory_import(memory(ty), import.module, import.field)?;
176 }
177 ImportSectionEntryType::Event(e) => {
178 environ.declare_event_import(event(e), import.module, import.field)?;
179 }
180 ImportSectionEntryType::Global(ty) => {
181 let ty = global(ty, environ, GlobalInit::Import)?;
182 environ.declare_global_import(ty, import.module, import.field)?;
183 }
184 ImportSectionEntryType::Table(ty) => {
185 let ty = table(ty, environ)?;
186 environ.declare_table_import(ty, import.module, import.field)?;
187 }
188 }
189 }
190
191 environ.finish_imports()?;
192 Ok(())
193 }
194
195 /// Parses the Function section of the wasm module.
parse_function_section( functions: FunctionSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>196 pub fn parse_function_section(
197 functions: FunctionSectionReader,
198 environ: &mut dyn ModuleEnvironment,
199 ) -> WasmResult<()> {
200 let num_functions = functions.get_count();
201 if num_functions == std::u32::MAX {
202 // We reserve `u32::MAX` for our own use in cranelift-entity.
203 return Err(WasmError::ImplLimitExceeded);
204 }
205
206 environ.reserve_func_types(num_functions)?;
207
208 for entry in functions {
209 let sigindex = entry?;
210 environ.declare_func_type(TypeIndex::from_u32(sigindex))?;
211 }
212
213 Ok(())
214 }
215
216 /// Parses the Table section of the wasm module.
parse_table_section( tables: TableSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>217 pub fn parse_table_section(
218 tables: TableSectionReader,
219 environ: &mut dyn ModuleEnvironment,
220 ) -> WasmResult<()> {
221 environ.reserve_tables(tables.get_count())?;
222
223 for entry in tables {
224 let ty = table(entry?, environ)?;
225 environ.declare_table(ty)?;
226 }
227
228 Ok(())
229 }
230
231 /// Parses the Memory section of the wasm module.
parse_memory_section( memories: MemorySectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>232 pub fn parse_memory_section(
233 memories: MemorySectionReader,
234 environ: &mut dyn ModuleEnvironment,
235 ) -> WasmResult<()> {
236 environ.reserve_memories(memories.get_count())?;
237
238 for entry in memories {
239 let memory = memory(entry?);
240 environ.declare_memory(memory)?;
241 }
242
243 Ok(())
244 }
245
246 /// Parses the Event section of the wasm module.
parse_event_section( events: EventSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>247 pub fn parse_event_section(
248 events: EventSectionReader,
249 environ: &mut dyn ModuleEnvironment,
250 ) -> WasmResult<()> {
251 environ.reserve_events(events.get_count())?;
252
253 for entry in events {
254 let event = event(entry?);
255 environ.declare_event(event)?;
256 }
257
258 Ok(())
259 }
260
261 /// Parses the Global section of the wasm module.
parse_global_section( globals: GlobalSectionReader, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>262 pub fn parse_global_section(
263 globals: GlobalSectionReader,
264 environ: &mut dyn ModuleEnvironment,
265 ) -> WasmResult<()> {
266 environ.reserve_globals(globals.get_count())?;
267
268 for entry in globals {
269 let wasmparser::Global { ty, init_expr } = entry?;
270 let mut init_expr_reader = init_expr.get_binary_reader();
271 let initializer = match init_expr_reader.read_operator()? {
272 Operator::I32Const { value } => GlobalInit::I32Const(value),
273 Operator::I64Const { value } => GlobalInit::I64Const(value),
274 Operator::F32Const { value } => GlobalInit::F32Const(value.bits()),
275 Operator::F64Const { value } => GlobalInit::F64Const(value.bits()),
276 Operator::V128Const { value } => {
277 GlobalInit::V128Const(V128Imm::from(value.bytes().to_vec().as_slice()))
278 }
279 Operator::RefNull { ty: _ } => GlobalInit::RefNullConst,
280 Operator::RefFunc { function_index } => {
281 GlobalInit::RefFunc(FuncIndex::from_u32(function_index))
282 }
283 Operator::GlobalGet { global_index } => {
284 GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
285 }
286 ref s => {
287 return Err(wasm_unsupported!(
288 "unsupported init expr in global section: {:?}",
289 s
290 ));
291 }
292 };
293 let ty = global(ty, environ, initializer)?;
294 environ.declare_global(ty)?;
295 }
296
297 Ok(())
298 }
299
300 /// Parses the Export section of the wasm module.
parse_export_section<'data>( exports: ExportSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>301 pub fn parse_export_section<'data>(
302 exports: ExportSectionReader<'data>,
303 environ: &mut dyn ModuleEnvironment<'data>,
304 ) -> WasmResult<()> {
305 environ.reserve_exports(exports.get_count())?;
306
307 for entry in exports {
308 let Export {
309 field,
310 ref kind,
311 index,
312 } = entry?;
313
314 // The input has already been validated, so we should be able to
315 // assume valid UTF-8 and use `from_utf8_unchecked` if performance
316 // becomes a concern here.
317 let index = index as usize;
318 match *kind {
319 ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), field)?,
320 ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field)?,
321 ExternalKind::Memory => {
322 environ.declare_memory_export(MemoryIndex::new(index), field)?
323 }
324 ExternalKind::Event => environ.declare_event_export(EventIndex::new(index), field)?,
325 ExternalKind::Global => {
326 environ.declare_global_export(GlobalIndex::new(index), field)?
327 }
328 ExternalKind::Module => {
329 environ.declare_module_export(ModuleIndex::new(index), field)?
330 }
331 ExternalKind::Instance => {
332 environ.declare_instance_export(InstanceIndex::new(index), field)?
333 }
334
335 // this never gets past validation
336 ExternalKind::Type => unreachable!(),
337 }
338 }
339
340 environ.finish_exports()?;
341 Ok(())
342 }
343
344 /// Parses the Start section of the wasm module.
parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> WasmResult<()>345 pub fn parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> WasmResult<()> {
346 environ.declare_start_func(FuncIndex::from_u32(index))?;
347 Ok(())
348 }
349
read_elems(items: &ElementItems) -> WasmResult<Box<[FuncIndex]>>350 fn read_elems(items: &ElementItems) -> WasmResult<Box<[FuncIndex]>> {
351 let items_reader = items.get_items_reader()?;
352 let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap());
353 for item in items_reader {
354 let elem = match item? {
355 ElementItem::Null(_ty) => FuncIndex::reserved_value(),
356 ElementItem::Func(index) => FuncIndex::from_u32(index),
357 };
358 elems.push(elem);
359 }
360 Ok(elems.into_boxed_slice())
361 }
362
363 /// Parses the Element section of the wasm module.
parse_element_section<'data>( elements: ElementSectionReader<'data>, environ: &mut dyn ModuleEnvironment, ) -> WasmResult<()>364 pub fn parse_element_section<'data>(
365 elements: ElementSectionReader<'data>,
366 environ: &mut dyn ModuleEnvironment,
367 ) -> WasmResult<()> {
368 environ.reserve_table_elements(elements.get_count())?;
369
370 for (index, entry) in elements.into_iter().enumerate() {
371 let Element { kind, items, ty: _ } = entry?;
372 let segments = read_elems(&items)?;
373 match kind {
374 ElementKind::Active {
375 table_index,
376 init_expr,
377 } => {
378 let mut init_expr_reader = init_expr.get_binary_reader();
379 let (base, offset) = match init_expr_reader.read_operator()? {
380 Operator::I32Const { value } => (None, value as u32),
381 Operator::GlobalGet { global_index } => {
382 (Some(GlobalIndex::from_u32(global_index)), 0)
383 }
384 ref s => {
385 return Err(wasm_unsupported!(
386 "unsupported init expr in element section: {:?}",
387 s
388 ));
389 }
390 };
391 environ.declare_table_elements(
392 TableIndex::from_u32(table_index),
393 base,
394 offset,
395 segments,
396 )?
397 }
398 ElementKind::Passive => {
399 let index = ElemIndex::from_u32(index as u32);
400 environ.declare_passive_element(index, segments)?;
401 }
402 ElementKind::Declared => {
403 environ.declare_elements(segments)?;
404 }
405 }
406 }
407 Ok(())
408 }
409
410 /// Parses the Data section of the wasm module.
parse_data_section<'data>( data: DataSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>411 pub fn parse_data_section<'data>(
412 data: DataSectionReader<'data>,
413 environ: &mut dyn ModuleEnvironment<'data>,
414 ) -> WasmResult<()> {
415 environ.reserve_data_initializers(data.get_count())?;
416
417 for (index, entry) in data.into_iter().enumerate() {
418 let Data { kind, data } = entry?;
419 match kind {
420 DataKind::Active {
421 memory_index,
422 init_expr,
423 } => {
424 let mut init_expr_reader = init_expr.get_binary_reader();
425 let (base, offset) = match init_expr_reader.read_operator()? {
426 Operator::I32Const { value } => (None, value as u32),
427 Operator::GlobalGet { global_index } => {
428 (Some(GlobalIndex::from_u32(global_index)), 0)
429 }
430 ref s => {
431 return Err(wasm_unsupported!(
432 "unsupported init expr in data section: {:?}",
433 s
434 ))
435 }
436 };
437 environ.declare_data_initialization(
438 MemoryIndex::from_u32(memory_index),
439 base,
440 offset,
441 data,
442 )?;
443 }
444 DataKind::Passive => {
445 let index = DataIndex::from_u32(index as u32);
446 environ.declare_passive_data(index, data)?;
447 }
448 }
449 }
450
451 Ok(())
452 }
453
454 /// Parses the Name section of the wasm module.
parse_name_section<'data>( names: NameSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>455 pub fn parse_name_section<'data>(
456 names: NameSectionReader<'data>,
457 environ: &mut dyn ModuleEnvironment<'data>,
458 ) -> WasmResult<()> {
459 for subsection in names {
460 match subsection? {
461 wasmparser::Name::Function(f) => {
462 let mut names = f.get_map()?;
463 for _ in 0..names.get_count() {
464 let Naming { index, name } = names.read()?;
465 // We reserve `u32::MAX` for our own use in cranelift-entity.
466 if index != u32::max_value() {
467 environ.declare_func_name(FuncIndex::from_u32(index), name);
468 }
469 }
470 }
471 wasmparser::Name::Module(module) => {
472 let name = module.get_name()?;
473 environ.declare_module_name(name);
474 }
475 wasmparser::Name::Local(l) => {
476 let mut reader = l.get_function_local_reader()?;
477 for _ in 0..reader.get_count() {
478 let f = reader.read()?;
479 if f.func_index == u32::max_value() {
480 continue;
481 }
482 let mut map = f.get_map()?;
483 for _ in 0..map.get_count() {
484 let Naming { index, name } = map.read()?;
485 environ.declare_local_name(FuncIndex::from_u32(f.func_index), index, name)
486 }
487 }
488 }
489 wasmparser::Name::Unknown { .. } => {}
490 }
491 }
492 Ok(())
493 }
494
495 /// Parses the Instance section of the wasm module.
parse_instance_section<'data>( section: wasmparser::InstanceSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>496 pub fn parse_instance_section<'data>(
497 section: wasmparser::InstanceSectionReader<'data>,
498 environ: &mut dyn ModuleEnvironment<'data>,
499 ) -> WasmResult<()> {
500 environ.reserve_instances(section.get_count());
501
502 for instance in section {
503 let instance = instance?;
504 let module = ModuleIndex::from_u32(instance.module());
505 let args = instance
506 .args()?
507 .into_iter()
508 .map(|arg| {
509 let arg = arg?;
510 let index = match arg.kind {
511 ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(arg.index)),
512 ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(arg.index)),
513 ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(arg.index)),
514 ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(arg.index)),
515 ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(arg.index)),
516 ExternalKind::Instance => {
517 EntityIndex::Instance(InstanceIndex::from_u32(arg.index))
518 }
519 ExternalKind::Event => unimplemented!(),
520
521 // this won't pass validation
522 ExternalKind::Type => unreachable!(),
523 };
524 Ok((arg.name, index))
525 })
526 .collect::<WasmResult<Vec<_>>>()?;
527 environ.declare_instance(module, args)?;
528 }
529 Ok(())
530 }
531
532 /// Parses the Alias section of the wasm module.
parse_alias_section<'data>( section: wasmparser::AliasSectionReader<'data>, environ: &mut dyn ModuleEnvironment<'data>, ) -> WasmResult<()>533 pub fn parse_alias_section<'data>(
534 section: wasmparser::AliasSectionReader<'data>,
535 environ: &mut dyn ModuleEnvironment<'data>,
536 ) -> WasmResult<()> {
537 for alias in section {
538 let alias = match alias? {
539 wasmparser::Alias::OuterType {
540 relative_depth,
541 index,
542 } => Alias::OuterType {
543 relative_depth,
544 index: TypeIndex::from_u32(index),
545 },
546 wasmparser::Alias::OuterModule {
547 relative_depth,
548 index,
549 } => Alias::OuterModule {
550 relative_depth,
551 index: ModuleIndex::from_u32(index),
552 },
553 wasmparser::Alias::InstanceExport {
554 instance,
555 export,
556 kind: _,
557 } => Alias::InstanceExport {
558 instance: InstanceIndex::from_u32(instance),
559 export,
560 },
561 };
562 environ.declare_alias(alias)?;
563 }
564 Ok(())
565 }
566