...
1 package binary
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "math"
8
9 "github.com/tetratelabs/wazero/internal/leb128"
10 "github.com/tetratelabs/wazero/internal/wasm"
11 )
12
13 func decodeCode(r *bytes.Reader, codeSectionStart uint64, ret *wasm.Code) (err error) {
14 ss, _, err := leb128.DecodeUint32(r)
15 if err != nil {
16 return fmt.Errorf("get the size of code: %w", err)
17 }
18 remaining := int64(ss)
19
20
21 ls, bytesRead, err := leb128.DecodeUint32(r)
22 remaining -= int64(bytesRead)
23 if err != nil {
24 return fmt.Errorf("get the size locals: %v", err)
25 } else if remaining < 0 {
26 return io.EOF
27 }
28
29
30 bytesRead = 0
31 var sum uint64
32 for i := uint32(0); i < ls; i++ {
33 num, n, err := leb128.DecodeUint32(r)
34 if err != nil {
35 return fmt.Errorf("read n of locals: %v", err)
36 } else if remaining < 0 {
37 return io.EOF
38 }
39
40 sum += uint64(num)
41
42 b, err := r.ReadByte()
43 if err != nil {
44 return fmt.Errorf("read type of local: %v", err)
45 }
46
47 bytesRead += n + 1
48 switch vt := b; vt {
49 case wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeI64, wasm.ValueTypeF64,
50 wasm.ValueTypeFuncref, wasm.ValueTypeExternref, wasm.ValueTypeV128:
51 default:
52 return fmt.Errorf("invalid local type: 0x%x", vt)
53 }
54 }
55
56 if sum > math.MaxUint32 {
57 return fmt.Errorf("too many locals: %d", sum)
58 }
59
60
61 _, err = r.Seek(-int64(bytesRead), io.SeekCurrent)
62 if err != nil {
63 return err
64 }
65
66 localTypes := make([]wasm.ValueType, 0, sum)
67 for i := uint32(0); i < ls; i++ {
68 num, bytesRead, err := leb128.DecodeUint32(r)
69 remaining -= int64(bytesRead) + 1
70 if err != nil {
71 return fmt.Errorf("read n of locals: %v", err)
72 } else if remaining < 0 {
73 return io.EOF
74 }
75
76 b, err := r.ReadByte()
77 if err != nil {
78 return fmt.Errorf("read type of local: %v", err)
79 }
80
81 for j := uint32(0); j < num; j++ {
82 localTypes = append(localTypes, b)
83 }
84 }
85
86 bodyOffsetInCodeSection := codeSectionStart - uint64(r.Len())
87 body := make([]byte, remaining)
88 if _, err = io.ReadFull(r, body); err != nil {
89 return fmt.Errorf("read body: %w", err)
90 }
91
92 if endIndex := len(body) - 1; endIndex < 0 || body[endIndex] != wasm.OpcodeEnd {
93 return fmt.Errorf("expr not end with OpcodeEnd")
94 }
95
96 ret.BodyOffsetInCodeSection = bodyOffsetInCodeSection
97 ret.LocalTypes = localTypes
98 ret.Body = body
99 return nil
100 }
101
View as plain text