1 | /* Copyright 2018 Mozilla Foundation |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | * you may not use this file except in compliance with the License. |
5 | * You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS, |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and |
13 | * limitations under the License. |
14 | */ |
15 | |
16 | use crate::{BinaryReader, ConstExpr, FromReader, Result, SectionLimited, TableType}; |
17 | |
18 | /// A reader for the table section of a WebAssembly module. |
19 | pub type TableSectionReader<'a> = SectionLimited<'a, Table<'a>>; |
20 | |
21 | /// Type information about a table defined in the table section of a WebAssembly |
22 | /// module. |
23 | #[derive (Clone, Debug)] |
24 | pub struct Table<'a> { |
25 | /// The type of this table, including its element type and its limits. |
26 | pub ty: TableType, |
27 | /// The initialization expression for the table. |
28 | pub init: TableInit<'a>, |
29 | } |
30 | |
31 | /// Different modes of initializing a table. |
32 | #[derive (Clone, Debug)] |
33 | pub enum TableInit<'a> { |
34 | /// The table is initialized to all null elements. |
35 | RefNull, |
36 | /// Each element in the table is initialized with the specified constant |
37 | /// expression. |
38 | Expr(ConstExpr<'a>), |
39 | } |
40 | |
41 | impl<'a> FromReader<'a> for Table<'a> { |
42 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
43 | let has_init_expr: bool = if reader.peek()? == 0x40 { |
44 | reader.read_u8()?; |
45 | true |
46 | } else { |
47 | false |
48 | }; |
49 | |
50 | if has_init_expr { |
51 | if reader.read_u8()? != 0x00 { |
52 | bail!(reader.original_position() - 1, "invalid table encoding" ); |
53 | } |
54 | } |
55 | |
56 | let ty: TableType = reader.read::<TableType>()?; |
57 | let init: TableInit<'_> = if has_init_expr { |
58 | TableInit::Expr(reader.read()?) |
59 | } else { |
60 | TableInit::RefNull |
61 | }; |
62 | Ok(Table { ty, init }) |
63 | } |
64 | } |
65 | |
66 | impl<'a> FromReader<'a> for TableType { |
67 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
68 | let element_type = reader.read()?; |
69 | let pos = reader.original_position(); |
70 | let flags = reader.read_u8()?; |
71 | if (flags & !0b111) != 0 { |
72 | bail!(pos, "invalid table resizable limits flags" ); |
73 | } |
74 | let has_max = (flags & 0b001) != 0; |
75 | let shared = (flags & 0b010) != 0; |
76 | let table64 = (flags & 0b100) != 0; |
77 | Ok(TableType { |
78 | element_type, |
79 | table64, |
80 | initial: if table64 { |
81 | reader.read_var_u64()? |
82 | } else { |
83 | reader.read_var_u32()?.into() |
84 | }, |
85 | maximum: if !has_max { |
86 | None |
87 | } else if table64 { |
88 | Some(reader.read_var_u64()?) |
89 | } else { |
90 | Some(reader.read_var_u32()?.into()) |
91 | }, |
92 | shared, |
93 | }) |
94 | } |
95 | } |
96 | |