forked from go-interpreter/wagon
-
Notifications
You must be signed in to change notification settings - Fork 1
/
module.go
167 lines (143 loc) · 3.76 KB
/
module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2017 The go-interpreter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wasm
import (
"errors"
"io"
"reflect"
"github.com/SummerCash/wagon/wasm/intrnl/readpos"
)
var ErrInvalidMagic = errors.New("wasm: Invalid magic number")
const (
Magic uint32 = 0x6d736100
Version uint32 = 0x1
)
// Function represents an entry in the function index space of a module.
type Function struct {
Sig *FunctionSig
Body *FunctionBody
Host reflect.Value
}
// IsHost indicates whether this function is a host function as defined in:
// https://webassembly.github.io/spec/core/exec/modules.html#host-functions
func (fct *Function) IsHost() bool {
return fct.Host != reflect.Value{}
}
// Module represents a parsed WebAssembly module:
// http://webassembly.org/docs/modules/
type Module struct {
Version uint32 // Version
Sections []Section
Types *SectionTypes
Import *SectionImports
Function *SectionFunctions
Table *SectionTables
Memory *SectionMemories
Global *SectionGlobals
Export *SectionExports
Start *SectionStartFunction
Elements *SectionElements
Code *SectionCode
Data *SectionData
Customs []*SectionCustom
// The function index space of the module
FunctionIndexSpace []Function
GlobalIndexSpace []GlobalEntry
// function indices into the global function space
// the limit of each table is its capacity (cap)
TableIndexSpace [][]uint32
LinearMemoryIndexSpace [][]byte
imports struct {
Funcs []uint32
Globals int
Tables int
Memories int
}
}
// Custom returns a custom section with a specific name, if it exists.
func (m *Module) Custom(name string) *SectionCustom {
for _, s := range m.Customs {
if s.Name == name {
return s
}
}
return nil
}
// NewModule creates a new empty module
func NewModule() *Module {
return &Module{
Types: &SectionTypes{},
Import: &SectionImports{},
Table: &SectionTables{},
Memory: &SectionMemories{},
Global: &SectionGlobals{},
Export: &SectionExports{},
Start: &SectionStartFunction{},
Elements: &SectionElements{},
Data: &SectionData{},
}
}
// ResolveFunc is a function that takes a module name and
// returns a valid resolved module.
type ResolveFunc func(name string) (*Module, error)
// DecodeModule is the same as ReadModule, but it only decodes the module without
// initializing the index space or resolving imports.
func DecodeModule(r io.Reader) (*Module, error) {
reader := &readpos.ReadPos{
R: r,
CurPos: 0,
}
m := &Module{}
magic, err := readU32(reader)
if err != nil {
return nil, err
}
if magic != Magic {
return nil, ErrInvalidMagic
}
if m.Version, err = readU32(reader); err != nil {
return nil, err
}
for {
done, err := m.readSection(reader)
if err != nil {
return nil, err
} else if done {
return m, nil
}
}
}
// ReadModule reads a module from the reader r. resolvePath must take a string
// and a return a reader to the module pointed to by the string.
func ReadModule(r io.Reader, resolvePath ResolveFunc) (*Module, error) {
m, err := DecodeModule(r)
if err != nil {
return nil, err
}
m.LinearMemoryIndexSpace = make([][]byte, 1)
if m.Table != nil {
m.TableIndexSpace = make([][]uint32, int(len(m.Table.Entries)))
}
if m.Import != nil && resolvePath != nil {
if m.Code == nil {
m.Code = &SectionCode{}
}
err := m.resolveImports(resolvePath)
if err != nil {
return nil, err
}
}
for _, fn := range []func() error{
m.populateGlobals,
m.populateFunctions,
m.populateTables,
m.populateLinearMemory,
} {
if err := fn(); err != nil {
return nil, err
}
}
logger.Printf("There are %d entries in the function index space.", len(m.FunctionIndexSpace))
return m, nil
}