wasmi/table/mod.rs
1pub use self::{
2 element::{ElementSegment, ElementSegmentEntity, ElementSegmentIdx},
3 error::TableError,
4};
5use super::{AsContext, AsContextMut, Stored};
6use crate::{
7 collections::arena::ArenaIndex,
8 core::{TrapCode, UntypedVal, ValType},
9 error::EntityGrowError,
10 module::FuncIdx,
11 store::{Fuel, FuelError, ResourceLimiterRef},
12 value::WithType,
13 Func,
14 FuncRef,
15 Val,
16};
17use core::cmp::max;
18use std::{vec, vec::Vec};
19
20mod element;
21mod error;
22
23#[cfg(test)]
24mod tests;
25
26/// A raw index to a table entity.
27#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
28pub struct TableIdx(u32);
29
30impl ArenaIndex for TableIdx {
31 fn into_usize(self) -> usize {
32 self.0 as usize
33 }
34
35 fn from_usize(value: usize) -> Self {
36 let value = value.try_into().unwrap_or_else(|error| {
37 panic!("index {value} is out of bounds as table index: {error}")
38 });
39 Self(value)
40 }
41}
42
43/// A descriptor for a [`Table`] instance.
44#[derive(Debug, Copy, Clone, PartialEq, Eq)]
45pub struct TableType {
46 /// The type of values stored in the [`Table`].
47 element: ValType,
48 /// The minimum number of elements the [`Table`] must have.
49 min: u32,
50 /// The optional maximum number of elements the [`Table`] can have.
51 ///
52 /// If this is `None` then the [`Table`] is not limited in size.
53 max: Option<u32>,
54}
55
56impl TableType {
57 /// Creates a new [`TableType`].
58 ///
59 /// # Panics
60 ///
61 /// If `min` is greater than `max`.
62 pub fn new(element: ValType, min: u32, max: Option<u32>) -> Self {
63 if let Some(max) = max {
64 assert!(min <= max);
65 }
66 Self { element, min, max }
67 }
68
69 /// Returns the [`ValType`] of elements stored in the [`Table`].
70 pub fn element(&self) -> ValType {
71 self.element
72 }
73
74 /// Returns minimum number of elements the [`Table`] must have.
75 pub fn minimum(&self) -> u32 {
76 self.min
77 }
78
79 /// The optional maximum number of elements the [`Table`] can have.
80 ///
81 /// If this returns `None` then the [`Table`] is not limited in size.
82 pub fn maximum(&self) -> Option<u32> {
83 self.max
84 }
85
86 /// Returns a [`TableError`] if `ty` does not match the [`Table`] element [`ValType`].
87 fn matches_element_type(&self, ty: ValType) -> Result<(), TableError> {
88 let expected = self.element();
89 let actual = ty;
90 if actual != expected {
91 return Err(TableError::ElementTypeMismatch { expected, actual });
92 }
93 Ok(())
94 }
95
96 /// Checks if `self` is a subtype of `other`.
97 ///
98 /// # Note
99 ///
100 /// This implements the [subtyping rules] according to the WebAssembly spec.
101 ///
102 /// [import subtyping]:
103 /// https://webassembly.github.io/spec/core/valid/types.html#import-subtyping
104 ///
105 /// # Errors
106 ///
107 /// - If the `element` type of `self` does not match the `element` type of `other`.
108 /// - If the `minimum` size of `self` is less than or equal to the `minimum` size of `other`.
109 /// - If the `maximum` size of `self` is greater than the `maximum` size of `other`.
110 pub(crate) fn is_subtype_or_err(&self, other: &TableType) -> Result<(), TableError> {
111 match self.is_subtype_of(other) {
112 true => Ok(()),
113 false => Err(TableError::InvalidSubtype {
114 ty: *self,
115 other: *other,
116 }),
117 }
118 }
119
120 /// Returns `true` if the [`TableType`] is a subtype of the `other` [`TableType`].
121 ///
122 /// # Note
123 ///
124 /// This implements the [subtyping rules] according to the WebAssembly spec.
125 ///
126 /// [import subtyping]:
127 /// https://webassembly.github.io/spec/core/valid/types.html#import-subtyping
128 pub(crate) fn is_subtype_of(&self, other: &Self) -> bool {
129 if self.matches_element_type(other.element()).is_err() {
130 return false;
131 }
132 if self.minimum() < other.minimum() {
133 return false;
134 }
135 match (self.maximum(), other.maximum()) {
136 (_, None) => true,
137 (Some(max), Some(other_max)) => max <= other_max,
138 _ => false,
139 }
140 }
141}
142
143/// A Wasm table entity.
144#[derive(Debug)]
145pub struct TableEntity {
146 ty: TableType,
147 elements: Vec<UntypedVal>,
148}
149
150impl TableEntity {
151 /// Creates a new table entity with the given resizable limits.
152 ///
153 /// # Errors
154 ///
155 /// If `init` does not match the [`TableType`] element type.
156 pub fn new(
157 ty: TableType,
158 init: Val,
159 limiter: &mut ResourceLimiterRef<'_>,
160 ) -> Result<Self, TableError> {
161 ty.matches_element_type(init.ty())?;
162
163 if let Some(limiter) = limiter.as_resource_limiter() {
164 if !limiter.table_growing(0, ty.minimum(), ty.maximum())? {
165 // Here there's no meaningful way to map Ok(false) to
166 // INVALID_GROWTH_ERRCODE, so we just translate it to an
167 // appropriate Err(...)
168 return Err(TableError::GrowOutOfBounds {
169 maximum: ty.maximum().unwrap_or(u32::MAX),
170 current: 0,
171 delta: ty.minimum(),
172 });
173 }
174 }
175
176 let elements = vec![init.into(); ty.minimum() as usize];
177 Ok(Self { ty, elements })
178 }
179
180 /// Returns the resizable limits of the table.
181 pub fn ty(&self) -> TableType {
182 self.ty
183 }
184
185 /// Returns the dynamic [`TableType`] of the [`TableEntity`].
186 ///
187 /// # Note
188 ///
189 /// This respects the current size of the [`TableEntity`]
190 /// as its minimum size and is useful for import subtyping checks.
191 pub fn dynamic_ty(&self) -> TableType {
192 TableType::new(self.ty().element(), self.size(), self.ty().maximum())
193 }
194
195 /// Returns the current size of the [`Table`].
196 pub fn size(&self) -> u32 {
197 self.elements.len() as u32
198 }
199
200 /// Grows the table by the given amount of elements.
201 ///
202 /// Returns the old size of the [`Table`] upon success.
203 ///
204 /// # Note
205 ///
206 /// The newly added elements are initialized to the `init` [`Val`].
207 ///
208 /// # Errors
209 ///
210 /// - If the table is grown beyond its maximum limits.
211 /// - If `value` does not match the [`Table`] element type.
212 pub fn grow(
213 &mut self,
214 delta: u32,
215 init: Val,
216 fuel: Option<&mut Fuel>,
217 limiter: &mut ResourceLimiterRef<'_>,
218 ) -> Result<u32, EntityGrowError> {
219 self.ty()
220 .matches_element_type(init.ty())
221 .map_err(|_| EntityGrowError::InvalidGrow)?;
222 self.grow_untyped(delta, init.into(), fuel, limiter)
223 }
224
225 /// Grows the table by the given amount of elements.
226 ///
227 /// Returns the old size of the [`Table`] upon success.
228 ///
229 /// # Note
230 ///
231 /// This is an internal API that exists for efficiency purposes.
232 ///
233 /// The newly added elements are initialized to the `init` [`Val`].
234 ///
235 /// # Errors
236 ///
237 /// If the table is grown beyond its maximum limits.
238 pub fn grow_untyped(
239 &mut self,
240 delta: u32,
241 init: UntypedVal,
242 fuel: Option<&mut Fuel>,
243 limiter: &mut ResourceLimiterRef<'_>,
244 ) -> Result<u32, EntityGrowError> {
245 // ResourceLimiter gets first look at the request.
246 let current = self.size();
247 let desired = current.checked_add(delta);
248 let maximum = self.ty.maximum();
249 if let Some(limiter) = limiter.as_resource_limiter() {
250 match limiter.table_growing(current, desired.unwrap_or(u32::MAX), maximum) {
251 Ok(true) => (),
252 Ok(false) => return Err(EntityGrowError::InvalidGrow),
253 Err(_) => return Err(EntityGrowError::TrapCode(TrapCode::GrowthOperationLimited)),
254 }
255 }
256
257 let maximum = maximum.unwrap_or(u32::MAX);
258 let notify_limiter =
259 |limiter: &mut ResourceLimiterRef<'_>| -> Result<u32, EntityGrowError> {
260 if let Some(limiter) = limiter.as_resource_limiter() {
261 limiter.table_grow_failed(&TableError::GrowOutOfBounds {
262 maximum,
263 current,
264 delta,
265 });
266 }
267 Err(EntityGrowError::InvalidGrow)
268 };
269
270 let Some(desired) = desired else {
271 return notify_limiter(limiter);
272 };
273 if desired > maximum {
274 return notify_limiter(limiter);
275 }
276 if let Some(fuel) = fuel {
277 match fuel.consume_fuel(|costs| costs.fuel_for_copies(u64::from(delta))) {
278 Ok(_) | Err(FuelError::FuelMeteringDisabled) => {}
279 Err(FuelError::OutOfFuel) => return notify_limiter(limiter),
280 }
281 }
282 self.elements.resize(desired as usize, init);
283 Ok(current)
284 }
285
286 /// Converts the internal [`UntypedVal`] into a [`Val`] for this [`Table`] element type.
287 fn make_typed(&self, untyped: UntypedVal) -> Val {
288 untyped.with_type(self.ty().element())
289 }
290
291 /// Returns the [`Table`] element value at `index`.
292 ///
293 /// Returns `None` if `index` is out of bounds.
294 pub fn get(&self, index: u32) -> Option<Val> {
295 self.get_untyped(index)
296 .map(|untyped| self.make_typed(untyped))
297 }
298
299 /// Returns the untyped [`Table`] element value at `index`.
300 ///
301 /// Returns `None` if `index` is out of bounds.
302 ///
303 /// # Note
304 ///
305 /// This is a more efficient version of [`Table::get`] for
306 /// internal use only.
307 pub fn get_untyped(&self, index: u32) -> Option<UntypedVal> {
308 self.elements.get(index as usize).copied()
309 }
310
311 /// Sets the [`Val`] of this [`Table`] at `index`.
312 ///
313 /// # Errors
314 ///
315 /// - If `index` is out of bounds.
316 /// - If `value` does not match the [`Table`] element type.
317 pub fn set(&mut self, index: u32, value: Val) -> Result<(), TableError> {
318 self.ty().matches_element_type(value.ty())?;
319 self.set_untyped(index, value.into())
320 }
321
322 /// Returns the [`UntypedVal`] of the [`Table`] at `index`.
323 ///
324 /// # Errors
325 ///
326 /// If `index` is out of bounds.
327 pub fn set_untyped(&mut self, index: u32, value: UntypedVal) -> Result<(), TableError> {
328 let current = self.size();
329 let untyped =
330 self.elements
331 .get_mut(index as usize)
332 .ok_or(TableError::AccessOutOfBounds {
333 current,
334 offset: index,
335 })?;
336 *untyped = value;
337 Ok(())
338 }
339
340 /// Initialize `len` elements from `src_element[src_index..]` into
341 /// `dst_table[dst_index..]`.
342 ///
343 /// Uses the `instance` to resolve function indices of the element to [`Func`][`crate::Func`].
344 ///
345 /// # Errors
346 ///
347 /// Returns an error if the range is out of bounds
348 /// of either the source or destination tables.
349 ///
350 /// # Panics
351 ///
352 /// - Panics if the `instance` cannot resolve all the `element` func indices.
353 /// - If the [`ElementSegmentEntity`] element type does not match the [`Table`] element type.
354 /// Note: This is a panic instead of an error since it is asserted at Wasm validation time.
355 pub fn init(
356 &mut self,
357 dst_index: u32,
358 element: &ElementSegmentEntity,
359 src_index: u32,
360 len: u32,
361 fuel: Option<&mut Fuel>,
362 get_func: impl Fn(u32) -> Func,
363 ) -> Result<(), TrapCode> {
364 let table_type = self.ty();
365 assert!(
366 table_type.element().is_ref(),
367 "table.init currently only works on reftypes"
368 );
369 table_type
370 .matches_element_type(element.ty())
371 .map_err(|_| TrapCode::BadSignature)?;
372 // Convert parameters to indices.
373 let dst_index = dst_index as usize;
374 let src_index = src_index as usize;
375 let len = len as usize;
376 // Perform bounds check before anything else.
377 let dst_items = self
378 .elements
379 .get_mut(dst_index..)
380 .and_then(|items| items.get_mut(..len))
381 .ok_or(TrapCode::TableOutOfBounds)?;
382 let src_items = element
383 .items()
384 .get(src_index..)
385 .and_then(|items| items.get(..len))
386 .ok_or(TrapCode::TableOutOfBounds)?;
387 if len == 0 {
388 // Bail out early if nothing needs to be initialized.
389 // The Wasm spec demands to still perform the bounds check
390 // so we cannot bail out earlier.
391 return Ok(());
392 }
393 if let Some(fuel) = fuel {
394 fuel.consume_fuel_if(|costs| costs.fuel_for_copies(len as u64))?;
395 }
396 // Perform the actual table initialization.
397 match table_type.element() {
398 ValType::FuncRef => {
399 // Initialize element interpreted as Wasm `funrefs`.
400 dst_items.iter_mut().zip(src_items).for_each(|(dst, src)| {
401 let func_or_null = src.funcref().map(FuncIdx::into_u32).map(&get_func);
402 *dst = FuncRef::new(func_or_null).into();
403 });
404 }
405 ValType::ExternRef => {
406 // Initialize element interpreted as Wasm `externrefs`.
407 dst_items.iter_mut().zip(src_items).for_each(|(dst, src)| {
408 *dst = src.eval_const().expect("must evaluate to some value");
409 });
410 }
411 _ => panic!("table.init currently only works on reftypes"),
412 };
413 Ok(())
414 }
415
416 /// Copy `len` elements from `src_table[src_index..]` into
417 /// `dst_table[dst_index..]`.
418 ///
419 /// # Errors
420 ///
421 /// Returns an error if the range is out of bounds of either the source or
422 /// destination tables.
423 pub fn copy(
424 dst_table: &mut Self,
425 dst_index: u32,
426 src_table: &Self,
427 src_index: u32,
428 len: u32,
429 fuel: Option<&mut Fuel>,
430 ) -> Result<(), TrapCode> {
431 // Turn parameters into proper slice indices.
432 let src_index = src_index as usize;
433 let dst_index = dst_index as usize;
434 let len = len as usize;
435 // Perform bounds check before anything else.
436 let dst_items = dst_table
437 .elements
438 .get_mut(dst_index..)
439 .and_then(|items| items.get_mut(..len))
440 .ok_or(TrapCode::TableOutOfBounds)?;
441 let src_items = src_table
442 .elements
443 .get(src_index..)
444 .and_then(|items| items.get(..len))
445 .ok_or(TrapCode::TableOutOfBounds)?;
446 if let Some(fuel) = fuel {
447 fuel.consume_fuel_if(|costs| costs.fuel_for_copies(len as u64))?;
448 }
449 // Finally, copy elements in-place for the table.
450 dst_items.copy_from_slice(src_items);
451 Ok(())
452 }
453
454 /// Copy `len` elements from `self[src_index..]` into `self[dst_index..]`.
455 ///
456 /// # Errors
457 ///
458 /// Returns an error if the range is out of bounds of the table.
459 pub fn copy_within(
460 &mut self,
461 dst_index: u32,
462 src_index: u32,
463 len: u32,
464 fuel: Option<&mut Fuel>,
465 ) -> Result<(), TrapCode> {
466 // These accesses just perform the bounds checks required by the Wasm spec.
467 let max_offset = max(dst_index, src_index);
468 max_offset
469 .checked_add(len)
470 .filter(|&offset| offset <= self.size())
471 .ok_or(TrapCode::TableOutOfBounds)?;
472 // Turn parameters into proper indices.
473 let src_index = src_index as usize;
474 let dst_index = dst_index as usize;
475 let len = len as usize;
476 if let Some(fuel) = fuel {
477 fuel.consume_fuel_if(|costs| costs.fuel_for_copies(len as u64))?;
478 }
479 // Finally, copy elements in-place for the table.
480 self.elements
481 .copy_within(src_index..src_index.wrapping_add(len), dst_index);
482 Ok(())
483 }
484
485 /// Fill `table[dst..(dst + len)]` with the given value.
486 ///
487 /// # Errors
488 ///
489 /// - If `val` has a type mismatch with the element type of the [`Table`].
490 /// - If the region to be filled is out of bounds for the [`Table`].
491 /// - If `val` originates from a different [`Store`] than the [`Table`].
492 ///
493 /// # Panics
494 ///
495 /// If `ctx` does not own `dst_table` or `src_table`.
496 ///
497 /// [`Store`]: [`crate::Store`]
498 pub fn fill(
499 &mut self,
500 dst: u32,
501 val: Val,
502 len: u32,
503 fuel: Option<&mut Fuel>,
504 ) -> Result<(), TrapCode> {
505 self.ty()
506 .matches_element_type(val.ty())
507 .map_err(|_| TrapCode::BadSignature)?;
508 self.fill_untyped(dst, val.into(), len, fuel)
509 }
510
511 /// Fill `table[dst..(dst + len)]` with the given value.
512 ///
513 /// # Note
514 ///
515 /// This is an API for internal use only and exists for efficiency reasons.
516 ///
517 /// # Errors
518 ///
519 /// - If the region to be filled is out of bounds for the [`Table`].
520 ///
521 /// # Panics
522 ///
523 /// If `ctx` does not own `dst_table` or `src_table`.
524 ///
525 /// [`Store`]: [`crate::Store`]
526 pub fn fill_untyped(
527 &mut self,
528 dst: u32,
529 val: UntypedVal,
530 len: u32,
531 fuel: Option<&mut Fuel>,
532 ) -> Result<(), TrapCode> {
533 let dst_index = dst as usize;
534 let len = len as usize;
535 let dst = self
536 .elements
537 .get_mut(dst_index..)
538 .and_then(|elements| elements.get_mut(..len))
539 .ok_or(TrapCode::TableOutOfBounds)?;
540 if let Some(fuel) = fuel {
541 fuel.consume_fuel_if(|costs| costs.fuel_for_copies(len as u64))?;
542 }
543 dst.fill(val);
544 Ok(())
545 }
546}
547
548/// A Wasm table reference.
549#[derive(Debug, Copy, Clone)]
550#[repr(transparent)]
551pub struct Table(Stored<TableIdx>);
552
553impl Table {
554 /// Creates a new table reference.
555 pub(super) fn from_inner(stored: Stored<TableIdx>) -> Self {
556 Self(stored)
557 }
558
559 /// Returns the underlying stored representation.
560 pub(super) fn as_inner(&self) -> &Stored<TableIdx> {
561 &self.0
562 }
563
564 /// Creates a new table to the store.
565 ///
566 /// # Errors
567 ///
568 /// If `init` does not match the [`TableType`] element type.
569 pub fn new(mut ctx: impl AsContextMut, ty: TableType, init: Val) -> Result<Self, TableError> {
570 let (inner, mut resource_limiter) = ctx
571 .as_context_mut()
572 .store
573 .store_inner_and_resource_limiter_ref();
574 let entity = TableEntity::new(ty, init, &mut resource_limiter)?;
575 let table = inner.alloc_table(entity);
576 Ok(table)
577 }
578
579 /// Returns the type and limits of the table.
580 ///
581 /// # Panics
582 ///
583 /// Panics if `ctx` does not own this [`Table`].
584 pub fn ty(&self, ctx: impl AsContext) -> TableType {
585 ctx.as_context().store.inner.resolve_table(self).ty()
586 }
587
588 /// Returns the dynamic [`TableType`] of the [`Table`].
589 ///
590 /// # Note
591 ///
592 /// This respects the current size of the [`Table`] as
593 /// its minimum size and is useful for import subtyping checks.
594 ///
595 /// # Panics
596 ///
597 /// Panics if `ctx` does not own this [`Table`].
598 pub(crate) fn dynamic_ty(&self, ctx: impl AsContext) -> TableType {
599 ctx.as_context()
600 .store
601 .inner
602 .resolve_table(self)
603 .dynamic_ty()
604 }
605
606 /// Returns the current size of the [`Table`].
607 ///
608 /// # Panics
609 ///
610 /// If `ctx` does not own this [`Table`].
611 pub fn size(&self, ctx: impl AsContext) -> u32 {
612 ctx.as_context().store.inner.resolve_table(self).size()
613 }
614
615 /// Grows the table by the given amount of elements.
616 ///
617 /// Returns the old size of the [`Table`] upon success.
618 ///
619 /// # Note
620 ///
621 /// The newly added elements are initialized to the `init` [`Val`].
622 ///
623 /// # Errors
624 ///
625 /// - If the table is grown beyond its maximum limits.
626 /// - If `value` does not match the [`Table`] element type.
627 ///
628 /// # Panics
629 ///
630 /// Panics if `ctx` does not own this [`Table`].
631 pub fn grow(
632 &self,
633 mut ctx: impl AsContextMut,
634 delta: u32,
635 init: Val,
636 ) -> Result<u32, TableError> {
637 let (inner, mut limiter) = ctx
638 .as_context_mut()
639 .store
640 .store_inner_and_resource_limiter_ref();
641 let table = inner.resolve_table_mut(self);
642 let current = table.size();
643 let maximum = table.ty().maximum().unwrap_or(u32::MAX);
644 table
645 .grow(delta, init, None, &mut limiter)
646 .map_err(|_| TableError::GrowOutOfBounds {
647 maximum,
648 current,
649 delta,
650 })
651 }
652
653 /// Returns the [`Table`] element value at `index`.
654 ///
655 /// Returns `None` if `index` is out of bounds.
656 ///
657 /// # Panics
658 ///
659 /// Panics if `ctx` does not own this [`Table`].
660 pub fn get(&self, ctx: impl AsContext, index: u32) -> Option<Val> {
661 ctx.as_context().store.inner.resolve_table(self).get(index)
662 }
663
664 /// Sets the [`Val`] of this [`Table`] at `index`.
665 ///
666 /// # Errors
667 ///
668 /// - If `index` is out of bounds.
669 /// - If `value` does not match the [`Table`] element type.
670 ///
671 /// # Panics
672 ///
673 /// Panics if `ctx` does not own this [`Table`].
674 pub fn set(
675 &self,
676 mut ctx: impl AsContextMut,
677 index: u32,
678 value: Val,
679 ) -> Result<(), TableError> {
680 ctx.as_context_mut()
681 .store
682 .inner
683 .resolve_table_mut(self)
684 .set(index, value)
685 }
686
687 /// Returns `true` if `lhs` and `rhs` [`Table`] refer to the same entity.
688 ///
689 /// # Note
690 ///
691 /// We do not implement `Eq` and `PartialEq` and
692 /// intentionally keep this API hidden from users.
693 #[inline]
694 pub(crate) fn eq(lhs: &Self, rhs: &Self) -> bool {
695 lhs.as_inner() == rhs.as_inner()
696 }
697
698 /// Copy `len` elements from `src_table[src_index..]` into
699 /// `dst_table[dst_index..]`.
700 ///
701 /// # Errors
702 ///
703 /// Returns an error if the range is out of bounds of either the source or
704 /// destination tables.
705 ///
706 /// # Panics
707 ///
708 /// Panics if `store` does not own either `dst_table` or `src_table`.
709 pub fn copy(
710 mut store: impl AsContextMut,
711 dst_table: &Table,
712 dst_index: u32,
713 src_table: &Table,
714 src_index: u32,
715 len: u32,
716 ) -> Result<(), TableError> {
717 if Self::eq(dst_table, src_table) {
718 // The `dst_table` and `src_table` are the same table
719 // therefore we have to copy within the same table.
720 let table = store
721 .as_context_mut()
722 .store
723 .inner
724 .resolve_table_mut(dst_table);
725 table
726 .copy_within(dst_index, src_index, len, None)
727 .map_err(|_| TableError::CopyOutOfBounds)
728 } else {
729 // The `dst_table` and `src_table` are different entities
730 // therefore we have to copy from one table to the other.
731 let dst_ty = dst_table.ty(&store);
732 let src_ty = src_table.ty(&store).element();
733 dst_ty.matches_element_type(src_ty)?;
734 let (dst_table, src_table, _fuel) = store
735 .as_context_mut()
736 .store
737 .inner
738 .resolve_table_pair_and_fuel(dst_table, src_table);
739 TableEntity::copy(dst_table, dst_index, src_table, src_index, len, None)
740 .map_err(|_| TableError::CopyOutOfBounds)
741 }
742 }
743
744 /// Fill `table[dst..(dst + len)]` with the given value.
745 ///
746 /// # Errors
747 ///
748 /// - If `val` has a type mismatch with the element type of the [`Table`].
749 /// - If the region to be filled is out of bounds for the [`Table`].
750 /// - If `val` originates from a different [`Store`] than the [`Table`].
751 ///
752 /// # Panics
753 ///
754 /// If `ctx` does not own `dst_table` or `src_table`.
755 ///
756 /// [`Store`]: [`crate::Store`]
757 pub fn fill(
758 &self,
759 mut ctx: impl AsContextMut,
760 dst: u32,
761 val: Val,
762 len: u32,
763 ) -> Result<(), TrapCode> {
764 ctx.as_context_mut()
765 .store
766 .inner
767 .resolve_table_mut(self)
768 .fill(dst, val, len, None)
769 }
770}