1 package binary
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/leb128"
10 "github.com/tetratelabs/wazero/internal/wasm"
11 )
12
13 func ensureElementKindFuncRef(r *bytes.Reader) error {
14 elemKind, err := r.ReadByte()
15 if err != nil {
16 return fmt.Errorf("read element prefix: %w", err)
17 }
18 if elemKind != 0x0 {
19 return fmt.Errorf("element kind must be zero but was 0x%x", elemKind)
20 }
21 return nil
22 }
23
24 func decodeElementInitValueVector(r *bytes.Reader) ([]wasm.Index, error) {
25 vs, _, err := leb128.DecodeUint32(r)
26 if err != nil {
27 return nil, fmt.Errorf("get size of vector: %w", err)
28 }
29
30 vec := make([]wasm.Index, vs)
31 for i := range vec {
32 u32, _, err := leb128.DecodeUint32(r)
33 if err != nil {
34 return nil, fmt.Errorf("read function index: %w", err)
35 }
36
37 if u32 >= wasm.MaximumFunctionIndex {
38 return nil, fmt.Errorf("too large function index in Element init: %d", u32)
39 }
40 vec[i] = u32
41 }
42 return vec, nil
43 }
44
45 func decodeElementConstExprVector(r *bytes.Reader, elemType wasm.RefType, enabledFeatures api.CoreFeatures) ([]wasm.Index, error) {
46 vs, _, err := leb128.DecodeUint32(r)
47 if err != nil {
48 return nil, fmt.Errorf("failed to get the size of constexpr vector: %w", err)
49 }
50 vec := make([]wasm.Index, vs)
51 for i := range vec {
52 var expr wasm.ConstantExpression
53 err := decodeConstantExpression(r, enabledFeatures, &expr)
54 if err != nil {
55 return nil, err
56 }
57 switch expr.Opcode {
58 case wasm.OpcodeRefFunc:
59 if elemType != wasm.RefTypeFuncref {
60 return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has funcref", wasm.RefTypeName(elemType))
61 }
62 v, _, _ := leb128.LoadUint32(expr.Data)
63 if v >= wasm.MaximumFunctionIndex {
64 return nil, fmt.Errorf("too large function index in Element init: %d", v)
65 }
66 vec[i] = v
67 case wasm.OpcodeRefNull:
68 if elemType != expr.Data[0] {
69 return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has %s",
70 wasm.RefTypeName(elemType), wasm.RefTypeName(expr.Data[0]))
71 }
72 vec[i] = wasm.ElementInitNullReference
73 case wasm.OpcodeGlobalGet:
74 i32, _, _ := leb128.LoadInt32(expr.Data)
75 if elemType != wasm.RefTypeFuncref {
76 return nil, fmt.Errorf("element type mismatch: want %s, but requires funcref", wasm.RefTypeName(elemType))
77 }
78
79
80 vec[i] = wasm.ElementInitImportedGlobalFunctionReference | wasm.Index(i32)
81 default:
82 return nil, fmt.Errorf("const expr must be either ref.null or ref.func but was %s", wasm.InstructionName(expr.Opcode))
83 }
84 }
85 return vec, nil
86 }
87
88 func decodeElementRefType(r *bytes.Reader) (ret wasm.RefType, err error) {
89 ret, err = r.ReadByte()
90 if err != nil {
91 err = fmt.Errorf("read element ref type: %w", err)
92 return
93 }
94 if ret != wasm.RefTypeFuncref && ret != wasm.RefTypeExternref {
95 return 0, errors.New("ref type must be funcref or externref for element as of WebAssembly 2.0")
96 }
97 return
98 }
99
100 const (
101
102
103
104 elementSegmentPrefixLegacy = iota
105
106 elementSegmentPrefixPassiveFuncrefValueVector
107
108 elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex
109
110 elementSegmentPrefixDeclarativeFuncrefValueVector
111
112 elementSegmentPrefixActiveFuncrefConstExprVector
113
114 elementSegmentPrefixPassiveConstExprVector
115
116 elementSegmentPrefixActiveConstExprVector
117
118 elementSegmentPrefixDeclarativeConstExprVector
119 )
120
121 func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.ElementSegment) error {
122 prefix, _, err := leb128.DecodeUint32(r)
123 if err != nil {
124 return fmt.Errorf("read element prefix: %w", err)
125 }
126
127 if prefix != elementSegmentPrefixLegacy {
128 if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
129 return fmt.Errorf("non-zero prefix for element segment is invalid as %w", err)
130 }
131 }
132
133
134 switch prefix {
135 case elementSegmentPrefixLegacy:
136
137 err = decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
138 if err != nil {
139 return fmt.Errorf("read expr for offset: %w", err)
140 }
141
142 ret.Init, err = decodeElementInitValueVector(r)
143 if err != nil {
144 return err
145 }
146
147 ret.Mode = wasm.ElementModeActive
148 ret.Type = wasm.RefTypeFuncref
149 return nil
150 case elementSegmentPrefixPassiveFuncrefValueVector:
151
152 if err = ensureElementKindFuncRef(r); err != nil {
153 return err
154 }
155
156 ret.Init, err = decodeElementInitValueVector(r)
157 if err != nil {
158 return err
159 }
160 ret.Mode = wasm.ElementModePassive
161 ret.Type = wasm.RefTypeFuncref
162 return nil
163 case elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex:
164 ret.TableIndex, _, err = leb128.DecodeUint32(r)
165 if err != nil {
166 return fmt.Errorf("get size of vector: %w", err)
167 }
168
169 if ret.TableIndex != 0 {
170 if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
171 return fmt.Errorf("table index must be zero but was %d: %w", ret.TableIndex, err)
172 }
173 }
174
175 err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
176 if err != nil {
177 return fmt.Errorf("read expr for offset: %w", err)
178 }
179
180
181 if err = ensureElementKindFuncRef(r); err != nil {
182 return err
183 }
184
185 ret.Init, err = decodeElementInitValueVector(r)
186 if err != nil {
187 return err
188 }
189
190 ret.Mode = wasm.ElementModeActive
191 ret.Type = wasm.RefTypeFuncref
192 return nil
193 case elementSegmentPrefixDeclarativeFuncrefValueVector:
194
195 if err = ensureElementKindFuncRef(r); err != nil {
196 return err
197 }
198 ret.Init, err = decodeElementInitValueVector(r)
199 if err != nil {
200 return err
201 }
202 ret.Type = wasm.RefTypeFuncref
203 ret.Mode = wasm.ElementModeDeclarative
204 return nil
205 case elementSegmentPrefixActiveFuncrefConstExprVector:
206 err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
207 if err != nil {
208 return fmt.Errorf("read expr for offset: %w", err)
209 }
210
211 ret.Init, err = decodeElementConstExprVector(r, wasm.RefTypeFuncref, enabledFeatures)
212 if err != nil {
213 return err
214 }
215 ret.Mode = wasm.ElementModeActive
216 ret.Type = wasm.RefTypeFuncref
217 return nil
218 case elementSegmentPrefixPassiveConstExprVector:
219 ret.Type, err = decodeElementRefType(r)
220 if err != nil {
221 return err
222 }
223 ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
224 if err != nil {
225 return err
226 }
227 ret.Mode = wasm.ElementModePassive
228 return nil
229 case elementSegmentPrefixActiveConstExprVector:
230 ret.TableIndex, _, err = leb128.DecodeUint32(r)
231 if err != nil {
232 return fmt.Errorf("get size of vector: %w", err)
233 }
234
235 if ret.TableIndex != 0 {
236 if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
237 return fmt.Errorf("table index must be zero but was %d: %w", ret.TableIndex, err)
238 }
239 }
240 err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
241 if err != nil {
242 return fmt.Errorf("read expr for offset: %w", err)
243 }
244
245 ret.Type, err = decodeElementRefType(r)
246 if err != nil {
247 return err
248 }
249
250 ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
251 if err != nil {
252 return err
253 }
254
255 ret.Mode = wasm.ElementModeActive
256 return nil
257 case elementSegmentPrefixDeclarativeConstExprVector:
258 ret.Type, err = decodeElementRefType(r)
259 if err != nil {
260 return err
261 }
262 ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
263 if err != nil {
264 return err
265 }
266
267 ret.Mode = wasm.ElementModeDeclarative
268 return nil
269 default:
270 return fmt.Errorf("invalid element segment prefix: 0x%x", prefix)
271 }
272 }
273
View as plain text