1use crate::{
2 error::{CreationError, LinkError, LinkResult},
3 export::{Context, Export},
4 global::Global,
5 import::ImportObject,
6 memory::Memory,
7 module::{ImportName, ModuleInfo, ModuleInner},
8 sig_registry::SigRegistry,
9 structures::{BoxedMap, Map, SliceMap, TypedIndex},
10 table::Table,
11 typed_func::{always_trap, Func},
12 types::{
13 ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex,
14 Initializer, LocalFuncIndex, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport,
15 LocalTableIndex, SigIndex, Value,
16 },
17 vm,
18};
19use std::{fmt::Debug, ptr::NonNull, slice};
20
21pub const INTERNALS_SIZE: usize = 256;
23
24pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]);
25
26impl Debug for Internals {
27 fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
28 write!(formatter, "Internals({:?})", &self.0[..])
29 }
30}
31
32#[derive(Debug)]
36pub struct LocalBacking {
37 pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
40 pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
41 pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
42
43 pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
47 pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
48 pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
49
50 pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
54 pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
55
56 pub(crate) internals: Internals,
57}
58
59unsafe impl Send for LocalBacking {}
61
62impl LocalBacking {
63 pub(crate) fn new(
64 module: &ModuleInner,
65 imports: &ImportBacking,
66 vmctx: *mut vm::Ctx,
67 ) -> LinkResult<Self> {
68 let mut memories = match Self::generate_memories(module) {
69 Ok(m) => m,
70 Err(e) => {
71 return Err(vec![LinkError::Generic {
72 message: format!("unable to create memory: {:?}", e),
73 }]);
74 }
75 };
76 let mut tables = Self::generate_tables(module);
77 let mut globals = Self::generate_globals(module, imports)?;
78
79 Self::validate_memories(module, imports)?;
81 Self::validate_tables(module, imports, &mut tables)?;
82
83 let vm_memories = Self::finalize_memories(module, imports, &mut memories)?;
84 let vm_tables = Self::finalize_tables(module, imports, &mut tables, vmctx)?;
85 let vm_globals = Self::finalize_globals(&mut globals);
86
87 let dynamic_sigindices = Self::generate_sigindices(&module.info);
88 let local_functions = Self::generate_local_functions(module);
89
90 Ok(Self {
91 memories,
92 tables,
93 globals,
94
95 vm_memories,
96 vm_tables,
97 vm_globals,
98
99 dynamic_sigindices,
100 local_functions,
101
102 internals: Internals([0; INTERNALS_SIZE]),
103 })
104 }
105
106 fn generate_local_functions(module: &ModuleInner) -> BoxedMap<LocalFuncIndex, *const vm::Func> {
107 (0..module.info.func_assoc.len() - module.info.imported_functions.len())
108 .map(|index| {
109 module
110 .runnable_module
111 .get_func(&module.info, LocalFuncIndex::new(index))
112 .unwrap()
113 .as_ptr() as *const _
114 })
115 .collect::<Map<_, _>>()
116 .into_boxed_map()
117 }
118
119 fn generate_sigindices(info: &ModuleInfo) -> BoxedMap<SigIndex, vm::SigId> {
120 info.signatures
121 .iter()
122 .map(|(_, signature)| {
123 let signature = SigRegistry.lookup_signature_ref(signature);
124 let sig_index = SigRegistry.lookup_sig_index(signature);
125 vm::SigId(sig_index.index() as u32)
126 })
127 .collect::<Map<_, _>>()
128 .into_boxed_map()
129 }
130
131 fn generate_memories(
132 module: &ModuleInner,
133 ) -> Result<BoxedMap<LocalMemoryIndex, Memory>, CreationError> {
134 let mut memories = Map::with_capacity(module.info.memories.len());
135 for (_, &desc) in &module.info.memories {
136 let memory = Memory::new(desc)?;
137 memories.push(memory);
138 }
139
140 Ok(memories.into_boxed_map())
141 }
142
143 fn validate_memories(module: &ModuleInner, imports: &ImportBacking) -> LinkResult<()> {
147 for init in module.info.data_initializers.iter() {
149 let init_base = match init.base {
150 Initializer::Const(Value::I32(offset)) => offset as u32,
151 Initializer::Const(_) => {
152 return Err(vec![LinkError::Generic {
153 message: "a const initializer must be an i32".to_string(),
154 }]);
155 }
156 Initializer::GetGlobal(import_global_index) => {
157 if import_global_index.index() >= imports.globals.len() {
158 return Err(vec![LinkError::Generic {
159 message: "incorrect global index for initializer".to_string(),
160 }]);
161 }
162 if let Value::I32(x) = imports.globals[import_global_index].get() {
163 x as u32
164 } else {
165 return Err(vec![LinkError::Generic {
166 message: "unsupported global type for initializer".to_string(),
167 }]);
168 }
169 }
170 } as usize;
171
172 match init.memory_index.local_or_import(&module.info) {
174 LocalOrImport::Local(local_memory_index) => {
175 let memory_desc = module.info.memories[local_memory_index];
176 let data_top = init_base + init.data.len();
177 if memory_desc.minimum.bytes().0 < data_top || data_top < init_base {
178 return Err(vec![LinkError::Generic {
179 message: "data segment does not fit".to_string(),
180 }]);
181 }
182 }
183 LocalOrImport::Import(imported_memory_index) => {
184 let local_memory = unsafe { &*imports.vm_memories[imported_memory_index] };
187 let data_top = init_base + init.data.len();
188 if local_memory.bound < data_top || data_top < init_base {
189 return Err(vec![LinkError::Generic {
190 message: "data segment does not fit".to_string(),
191 }]);
192 }
193 }
194 }
195 }
196 Ok(())
197 }
198
199 fn finalize_memories(
203 module: &ModuleInner,
204 imports: &ImportBacking,
205 memories: &mut SliceMap<LocalMemoryIndex, Memory>,
206 ) -> LinkResult<BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>> {
207 for init in module.info.data_initializers.iter() {
210 let init_base = match init.base {
211 Initializer::Const(Value::I32(offset)) => offset as u32,
212 Initializer::Const(_) => {
213 return Err(vec![LinkError::Generic {
214 message: "a const initializer must be an i32".to_string(),
215 }]);
216 }
217 Initializer::GetGlobal(import_global_index) => {
218 if import_global_index.index() >= imports.globals.len() {
219 return Err(vec![LinkError::Generic {
220 message: "incorrect global index for initializer".to_string(),
221 }]);
222 }
223 if let Value::I32(x) = imports.globals[import_global_index].get() {
224 x as u32
225 } else {
226 return Err(vec![LinkError::Generic {
227 message: "unsupported global type for initializer".to_string(),
228 }]);
229 }
230 }
231 } as usize;
232
233 match init.memory_index.local_or_import(&module.info) {
234 LocalOrImport::Local(local_memory_index) => {
235 let mem = &memories[local_memory_index];
236 for (mem_byte, data_byte) in mem.view()[init_base..init_base + init.data.len()]
237 .iter()
238 .zip(init.data.iter())
239 {
240 mem_byte.set(*data_byte);
241 }
242 }
243 LocalOrImport::Import(imported_memory_index) => {
244 let memory_slice = unsafe {
247 let local_memory = &*imports.vm_memories[imported_memory_index];
248 slice::from_raw_parts_mut(local_memory.base, local_memory.bound)
249 };
250
251 let mem_init_view = &mut memory_slice[init_base..init_base + init.data.len()];
252 mem_init_view.copy_from_slice(&init.data);
253 }
254 }
255 }
256
257 Ok(memories
258 .iter_mut()
259 .map(|(_, mem)| mem.vm_local_memory())
260 .collect::<Map<_, _>>()
261 .into_boxed_map())
262 }
263
264 fn generate_tables(module: &ModuleInner) -> BoxedMap<LocalTableIndex, Table> {
265 let mut tables = Map::with_capacity(module.info.tables.len());
266
267 for (_, &table_desc) in module.info.tables.iter() {
268 let table = Table::new(table_desc).unwrap();
269 tables.push(table);
270 }
271
272 tables.into_boxed_map()
273 }
274
275 #[allow(clippy::cast_ptr_alignment)]
277 fn validate_tables(
278 module: &ModuleInner,
279 imports: &ImportBacking,
280 tables: &mut SliceMap<LocalTableIndex, Table>,
281 ) -> LinkResult<()> {
282 for init in &module.info.elem_initializers {
283 let init_base = match init.base {
284 Initializer::Const(Value::I32(offset)) => offset as u32,
285 Initializer::Const(_) => {
286 return Err(vec![LinkError::Generic {
287 message: "a const initializer must be an i32".to_string(),
288 }]);
289 }
290 Initializer::GetGlobal(import_global_index) => {
291 if import_global_index.index() >= imports.globals.len() {
292 return Err(vec![LinkError::Generic {
293 message: "incorrect global index for initializer".to_string(),
294 }]);
295 }
296 if let Value::I32(x) = imports.globals[import_global_index].get() {
297 x as u32
298 } else {
299 return Err(vec![LinkError::Generic {
300 message: "unsupported global type for initializer".to_string(),
301 }]);
302 }
303 }
304 } as usize;
305
306 match init.table_index.local_or_import(&module.info) {
307 LocalOrImport::Local(local_table_index) => {
308 let table = &tables[local_table_index];
309
310 if (table.size() as usize) < init_base + init.elements.len() {
311 return Err(vec![LinkError::Generic {
312 message: "elements segment does not fit".to_string(),
313 }]);
314 }
315 }
316 LocalOrImport::Import(import_table_index) => {
317 let table = &imports.tables[import_table_index];
318
319 if (table.size() as usize) < init_base + init.elements.len() {
320 return Err(vec![LinkError::Generic {
321 message: "elements segment does not fit".to_string(),
322 }]);
323 }
324 }
325 }
326 }
327 Ok(())
328 }
329
330 #[allow(clippy::cast_ptr_alignment)]
334 fn finalize_tables(
335 module: &ModuleInner,
336 imports: &ImportBacking,
337 tables: &mut SliceMap<LocalTableIndex, Table>,
338 vmctx: *mut vm::Ctx,
339 ) -> LinkResult<BoxedMap<LocalTableIndex, *mut vm::LocalTable>> {
340 for init in &module.info.elem_initializers {
341 let init_base = match init.base {
342 Initializer::Const(Value::I32(offset)) => offset as u32,
343 Initializer::Const(_) => {
344 return Err(vec![LinkError::Generic {
345 message: "a const initializer be an i32".to_string(),
346 }]);
347 }
348 Initializer::GetGlobal(import_global_index) => {
349 if import_global_index.index() >= imports.globals.len() {
350 return Err(vec![LinkError::Generic {
351 message: "incorrect global index for initializer".to_string(),
352 }]);
353 }
354 if let Value::I32(x) = imports.globals[import_global_index].get() {
355 x as u32
356 } else {
357 return Err(vec![LinkError::Generic {
358 message: "unsupported global type for initializer".to_string(),
359 }]);
360 }
361 }
362 } as usize;
363
364 match init.table_index.local_or_import(&module.info) {
365 LocalOrImport::Local(local_table_index) => {
366 let table = &tables[local_table_index];
367 table.anyfunc_direct_access_mut(|elements| {
368 for (i, &func_index) in init.elements.iter().enumerate() {
369 let sig_index = module.info.func_assoc[func_index];
370 let signature = SigRegistry
372 .lookup_signature_ref(&module.info.signatures[sig_index]);
373 let sig_id =
374 vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
375
376 let (func, ctx) = match func_index.local_or_import(&module.info) {
377 LocalOrImport::Local(local_func_index) => (
378 module
379 .runnable_module
380 .get_func(&module.info, local_func_index)
381 .unwrap()
382 .as_ptr()
383 as *const vm::Func,
384 vmctx,
385 ),
386 LocalOrImport::Import(imported_func_index) => {
387 let vm::ImportedFunc { func, func_ctx } =
388 imports.vm_functions[imported_func_index];
389 (func, unsafe { func_ctx.as_ref() }.vmctx.as_ptr())
390 }
391 };
392
393 elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
394 }
395 });
396 }
397 LocalOrImport::Import(import_table_index) => {
398 let table = &imports.tables[import_table_index];
399
400 table.anyfunc_direct_access_mut(|elements| {
401 for (i, &func_index) in init.elements.iter().enumerate() {
402 let sig_index = module.info.func_assoc[func_index];
403 let signature = SigRegistry
404 .lookup_signature_ref(&module.info.signatures[sig_index]);
405 let sig_id =
407 vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
408
409 let (func, ctx) = match func_index.local_or_import(&module.info) {
410 LocalOrImport::Local(local_func_index) => (
411 module
412 .runnable_module
413 .get_func(&module.info, local_func_index)
414 .unwrap()
415 .as_ptr()
416 as *const vm::Func,
417 vmctx,
418 ),
419 LocalOrImport::Import(imported_func_index) => {
420 let vm::ImportedFunc { func, func_ctx } =
421 imports.vm_functions[imported_func_index];
422 (func, unsafe { func_ctx.as_ref() }.vmctx.as_ptr())
423 }
424 };
425
426 elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id };
427 }
428 });
429 }
430 }
431 }
432
433 Ok(tables
434 .iter_mut()
435 .map(|(_, table)| table.vm_local_table())
436 .collect::<Map<_, _>>()
437 .into_boxed_map())
438 }
439
440 fn generate_globals(
441 module: &ModuleInner,
442 imports: &ImportBacking,
443 ) -> LinkResult<BoxedMap<LocalGlobalIndex, Global>> {
444 let mut globals = Map::with_capacity(module.info.globals.len());
445
446 for (_, global_init) in module.info.globals.iter() {
447 let value = match &global_init.init {
448 Initializer::Const(value) => value.clone(),
449 Initializer::GetGlobal(import_global_index) => {
450 if imports.globals.len() <= import_global_index.index() {
451 return Err(vec![LinkError::Generic {
452 message: format!(
453 "Trying to read the `{:?}` global that is not properly initialized.",
454 import_global_index.index()
455 ),
456 }]);
457 }
458
459 imports.globals[*import_global_index].get()
460 }
461 };
462
463 let global = if global_init.desc.mutable {
464 Global::new_mutable(value)
465 } else {
466 Global::new(value)
467 };
468
469 globals.push(global);
470 }
471
472 Ok(globals.into_boxed_map())
473 }
474
475 fn finalize_globals(
476 globals: &mut SliceMap<LocalGlobalIndex, Global>,
477 ) -> BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal> {
478 globals
479 .iter_mut()
480 .map(|(_, global)| global.vm_local_global())
481 .collect::<Map<_, _>>()
482 .into_boxed_map()
483 }
484}
485
486#[derive(Debug)]
489pub struct ImportBacking {
490 pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>,
491 pub(crate) tables: BoxedMap<ImportedTableIndex, Table>,
492 pub(crate) globals: BoxedMap<ImportedGlobalIndex, Global>,
493
494 pub(crate) vm_functions: BoxedMap<ImportedFuncIndex, vm::ImportedFunc>,
495 pub(crate) vm_memories: BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
496 pub(crate) vm_tables: BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
497 pub(crate) vm_globals: BoxedMap<ImportedGlobalIndex, *mut vm::LocalGlobal>,
498}
499
500unsafe impl Send for ImportBacking {}
502
503impl ImportBacking {
504 pub fn new(
506 module: &ModuleInner,
507 imports: &ImportObject,
508 vmctx: *mut vm::Ctx,
509 ) -> LinkResult<Self> {
510 let mut failed = false;
511 let mut link_errors = vec![];
512
513 let vm_functions = import_functions(module, imports, vmctx).unwrap_or_else(|le| {
514 failed = true;
515 link_errors.extend(le);
516 Map::new().into_boxed_map()
517 });
518
519 let (memories, vm_memories) = import_memories(module, imports).unwrap_or_else(|le| {
520 failed = true;
521 link_errors.extend(le);
522 (Map::new().into_boxed_map(), Map::new().into_boxed_map())
523 });
524
525 let (tables, vm_tables) = import_tables(module, imports).unwrap_or_else(|le| {
526 failed = true;
527 link_errors.extend(le);
528 (Map::new().into_boxed_map(), Map::new().into_boxed_map())
529 });
530
531 let (globals, vm_globals) = import_globals(module, imports).unwrap_or_else(|le| {
532 failed = true;
533 link_errors.extend(le);
534 (Map::new().into_boxed_map(), Map::new().into_boxed_map())
535 });
536
537 if failed {
538 Err(link_errors)
539 } else {
540 Ok(ImportBacking {
541 memories,
542 tables,
543 globals,
544
545 vm_functions,
546 vm_memories,
547 vm_tables,
548 vm_globals,
549 })
550 }
551 }
552
553 pub fn imported_func(&self, index: ImportedFuncIndex) -> vm::ImportedFunc {
555 self.vm_functions[index].clone()
556 }
557}
558
559impl Drop for ImportBacking {
560 fn drop(&mut self) {
561 for (_imported_func_index, imported_func) in (*self.vm_functions).iter_mut() {
563 let func_ctx_ptr = imported_func.func_ctx.as_ptr();
564
565 if !func_ctx_ptr.is_null() {
566 let _: Box<vm::FuncCtx> = unsafe { Box::from_raw(func_ctx_ptr) };
567 }
568 }
569 }
570}
571
572fn import_functions(
573 module: &ModuleInner,
574 imports: &ImportObject,
575 vmctx: *mut vm::Ctx,
576) -> LinkResult<BoxedMap<ImportedFuncIndex, vm::ImportedFunc>> {
577 let mut link_errors = vec![];
578 let mut functions = Map::with_capacity(module.info.imported_functions.len());
579 for (
580 index,
581 ImportName {
582 namespace_index,
583 name_index,
584 },
585 ) in &module.info.imported_functions
586 {
587 let sig_index = module.info.func_assoc[index.convert_up(&module.info)];
588 let expected_sig = &module.info.signatures[sig_index];
589
590 let namespace = module.info.namespace_table.get(*namespace_index);
591 let name = module.info.name_table.get(*name_index);
592
593 let import =
594 imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name));
595
596 match import {
597 Some(Export::Function {
598 func,
599 ctx,
600 signature,
601 }) => {
602 if *expected_sig == *signature {
603 functions.push(vm::ImportedFunc {
604 func: func.inner(),
605 func_ctx: NonNull::new(Box::into_raw(Box::new(vm::FuncCtx {
606 vmctx: NonNull::new(match ctx {
610 Context::External(vmctx) => vmctx,
611 Context::ExternalWithEnv(vmctx_, _) => {
612 if vmctx_.is_null() {
613 vmctx
614 } else {
615 vmctx_
616 }
617 }
618 Context::Internal => vmctx,
619 })
620 .expect("`vmctx` must not be null."),
621 func_env: match ctx {
622 Context::ExternalWithEnv(_, func_env) => func_env,
623 _ => None,
624 },
625 })))
626 .unwrap(),
627 });
628 } else {
629 link_errors.push(LinkError::IncorrectImportSignature {
630 namespace: namespace.to_string(),
631 name: name.to_string(),
632 expected: (*expected_sig).clone(),
633 found: (*signature).clone(),
634 });
635 }
636 }
637 Some(export_type) => {
638 let export_type_name = match export_type {
639 Export::Function { .. } => "function",
640 Export::Memory { .. } => "memory",
641 Export::Table { .. } => "table",
642 Export::Global { .. } => "global",
643 }
644 .to_string();
645 link_errors.push(LinkError::IncorrectImportType {
646 namespace: namespace.to_string(),
647 name: name.to_string(),
648 expected: "function".to_string(),
649 found: export_type_name,
650 });
651 }
652 None => {
653 if imports.allow_missing_functions {
654 let always_trap = Func::new(always_trap);
655
656 functions.push(vm::ImportedFunc {
657 func: always_trap.get_vm_func().as_ptr(),
658 func_ctx: NonNull::new(Box::into_raw(Box::new(vm::FuncCtx {
659 vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."),
663 func_env: None,
664 })))
665 .unwrap(),
666 });
667 } else {
668 link_errors.push(LinkError::ImportNotFound {
669 namespace: namespace.to_string(),
670 name: name.to_string(),
671 });
672 }
673 }
674 }
675 }
676
677 if !link_errors.is_empty() {
678 Err(link_errors)
679 } else {
680 Ok(functions.into_boxed_map())
681 }
682}
683
684fn import_memories(
685 module: &ModuleInner,
686 imports: &ImportObject,
687) -> LinkResult<(
688 BoxedMap<ImportedMemoryIndex, Memory>,
689 BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
690)> {
691 let mut link_errors = vec![];
692 let mut memories = Map::with_capacity(module.info.imported_memories.len());
693 let mut vm_memories = Map::with_capacity(module.info.imported_memories.len());
694 for (
695 _index,
696 (
697 ImportName {
698 namespace_index,
699 name_index,
700 },
701 expected_memory_desc,
702 ),
703 ) in &module.info.imported_memories
704 {
705 let namespace = module.info.namespace_table.get(*namespace_index);
706 let name = module.info.name_table.get(*name_index);
707
708 let memory_import =
709 imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name));
710 match memory_import {
711 Some(Export::Memory(memory)) => {
712 if expected_memory_desc.fits_in_imported(memory.descriptor()) {
713 memories.push(memory.clone());
714 vm_memories.push(memory.vm_local_memory());
715 } else {
716 link_errors.push(LinkError::IncorrectMemoryDescriptor {
717 namespace: namespace.to_string(),
718 name: name.to_string(),
719 expected: *expected_memory_desc,
720 found: memory.descriptor(),
721 });
722 }
723 }
724 Some(export_type) => {
725 let export_type_name = match export_type {
726 Export::Function { .. } => "function",
727 Export::Memory { .. } => "memory",
728 Export::Table { .. } => "table",
729 Export::Global { .. } => "global",
730 }
731 .to_string();
732 link_errors.push(LinkError::IncorrectImportType {
733 namespace: namespace.to_string(),
734 name: name.to_string(),
735 expected: "memory".to_string(),
736 found: export_type_name,
737 });
738 }
739 None => {
740 link_errors.push(LinkError::ImportNotFound {
741 namespace: namespace.to_string(),
742 name: name.to_string(),
743 });
744 }
745 }
746 }
747
748 if !link_errors.is_empty() {
749 Err(link_errors)
750 } else {
751 Ok((memories.into_boxed_map(), vm_memories.into_boxed_map()))
752 }
753}
754
755fn import_tables(
756 module: &ModuleInner,
757 imports: &ImportObject,
758) -> LinkResult<(
759 BoxedMap<ImportedTableIndex, Table>,
760 BoxedMap<ImportedTableIndex, *mut vm::LocalTable>,
761)> {
762 let mut link_errors = vec![];
763 let mut tables = Map::with_capacity(module.info.imported_tables.len());
764 let mut vm_tables = Map::with_capacity(module.info.imported_tables.len());
765 for (
766 _index,
767 (
768 ImportName {
769 namespace_index,
770 name_index,
771 },
772 expected_table_desc,
773 ),
774 ) in &module.info.imported_tables
775 {
776 let namespace = module.info.namespace_table.get(*namespace_index);
777 let name = module.info.name_table.get(*name_index);
778
779 let table_import =
780 imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name));
781 match table_import {
782 Some(Export::Table(mut table)) => {
783 if expected_table_desc.fits_in_imported(table.descriptor()) {
784 vm_tables.push(table.vm_local_table());
785 tables.push(table);
786 } else {
787 link_errors.push(LinkError::IncorrectTableDescriptor {
788 namespace: namespace.to_string(),
789 name: name.to_string(),
790 expected: *expected_table_desc,
791 found: table.descriptor(),
792 });
793 }
794 }
795 Some(export_type) => {
796 let export_type_name = match export_type {
797 Export::Function { .. } => "function",
798 Export::Memory { .. } => "memory",
799 Export::Table { .. } => "table",
800 Export::Global { .. } => "global",
801 }
802 .to_string();
803 link_errors.push(LinkError::IncorrectImportType {
804 namespace: namespace.to_string(),
805 name: name.to_string(),
806 expected: "table".to_string(),
807 found: export_type_name,
808 });
809 }
810 None => {
811 link_errors.push(LinkError::ImportNotFound {
812 namespace: namespace.to_string(),
813 name: name.to_string(),
814 });
815 }
816 }
817 }
818
819 if link_errors.len() > 0 {
820 Err(link_errors)
821 } else {
822 Ok((tables.into_boxed_map(), vm_tables.into_boxed_map()))
823 }
824}
825
826fn import_globals(
827 module: &ModuleInner,
828 imports: &ImportObject,
829) -> LinkResult<(
830 BoxedMap<ImportedGlobalIndex, Global>,
831 BoxedMap<ImportedGlobalIndex, *mut vm::LocalGlobal>,
832)> {
833 let mut link_errors = vec![];
834 let mut globals = Map::with_capacity(module.info.imported_globals.len());
835 let mut vm_globals = Map::with_capacity(module.info.imported_globals.len());
836 for (
837 _,
838 (
839 ImportName {
840 namespace_index,
841 name_index,
842 },
843 imported_global_desc,
844 ),
845 ) in &module.info.imported_globals
846 {
847 let namespace = module.info.namespace_table.get(*namespace_index);
848 let name = module.info.name_table.get(*name_index);
849 let import =
850 imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name));
851 match import {
852 Some(Export::Global(mut global)) => {
853 if global.descriptor() == *imported_global_desc {
854 vm_globals.push(global.vm_local_global());
855 globals.push(global);
856 } else {
857 link_errors.push(LinkError::IncorrectGlobalDescriptor {
858 namespace: namespace.to_string(),
859 name: name.to_string(),
860 expected: *imported_global_desc,
861 found: global.descriptor(),
862 });
863 }
864 }
865 Some(export_type) => {
866 let export_type_name = match export_type {
867 Export::Function { .. } => "function",
868 Export::Memory { .. } => "memory",
869 Export::Table { .. } => "table",
870 Export::Global { .. } => "global",
871 }
872 .to_string();
873 link_errors.push(LinkError::IncorrectImportType {
874 namespace: namespace.to_string(),
875 name: name.to_string(),
876 expected: "global".to_string(),
877 found: export_type_name,
878 });
879 }
880 None => {
881 link_errors.push(LinkError::ImportNotFound {
882 namespace: namespace.to_string(),
883 name: name.to_string(),
884 });
885 }
886 }
887 }
888
889 if !link_errors.is_empty() {
890 Err(link_errors)
891 } else {
892 Ok((globals.into_boxed_map(), vm_globals.into_boxed_map()))
893 }
894}