This repository has been archived by the owner on May 11, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 150
/
imports.go
226 lines (191 loc) · 6.25 KB
/
imports.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// 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"
"fmt"
"io"
"github.com/go-interpreter/wagon/wasm/leb128"
)
// Import is an interface implemented by types that can be imported by a WebAssembly module.
type Import interface {
Kind() External
Marshaler
isImport()
}
// ImportEntry describes an import statement in a Wasm module.
type ImportEntry struct {
ModuleName string // module name string
FieldName string // field name string
// If Kind is Function, Type is a FuncImport containing the type index of the function signature
// If Kind is Table, Type is a TableImport containing the type of the imported table
// If Kind is Memory, Type is a MemoryImport containing the type of the imported memory
// If the Kind is Global, Type is a GlobalVarImport
Type Import
}
type FuncImport struct {
Type uint32
}
func (FuncImport) isImport() {}
func (FuncImport) Kind() External {
return ExternalFunction
}
func (f FuncImport) MarshalWASM(w io.Writer) error {
_, err := leb128.WriteVarUint32(w, uint32(f.Type))
return err
}
type TableImport struct {
Type Table
}
func (TableImport) isImport() {}
func (TableImport) Kind() External {
return ExternalTable
}
func (t TableImport) MarshalWASM(w io.Writer) error {
return t.Type.MarshalWASM(w)
}
type MemoryImport struct {
Type Memory
}
func (MemoryImport) isImport() {}
func (MemoryImport) Kind() External {
return ExternalMemory
}
func (t MemoryImport) MarshalWASM(w io.Writer) error {
return t.Type.MarshalWASM(w)
}
type GlobalVarImport struct {
Type GlobalVar
}
func (GlobalVarImport) isImport() {}
func (GlobalVarImport) Kind() External {
return ExternalGlobal
}
func (t GlobalVarImport) MarshalWASM(w io.Writer) error {
return t.Type.MarshalWASM(w)
}
var (
ErrImportMutGlobal = errors.New("wasm: cannot import global mutable variable")
ErrNoExportsInImportedModule = errors.New("wasm: imported module has no exports")
)
type InvalidExternalError uint8
func (e InvalidExternalError) Error() string {
return fmt.Sprintf("wasm: invalid external_kind value %d", uint8(e))
}
type ExportNotFoundError struct {
ModuleName string
FieldName string
}
type KindMismatchError struct {
ModuleName string
FieldName string
Import External
Export External
}
func (e KindMismatchError) Error() string {
return fmt.Sprintf("wasm: mismatching import and export external kind values for %s.%s (%v, %v)", e.FieldName, e.ModuleName, e.Import, e.Export)
}
func (e ExportNotFoundError) Error() string {
return fmt.Sprintf("wasm: couldn't find export with name %s in module %s", e.FieldName, e.ModuleName)
}
type InvalidFunctionIndexError uint32
func (e InvalidFunctionIndexError) Error() string {
return fmt.Sprintf("wasm: invalid index to function index space: %#x", uint32(e))
}
// InvalidImportError is returned when the export of a resolved module doesn't
// match the signature of its import declaration.
type InvalidImportError struct {
ModuleName string
FieldName string
TypeIndex uint32
}
func (e InvalidImportError) Error() string {
return fmt.Sprintf("wasm: invalid signature for import %#x with name '%s' in module %s", e.TypeIndex, e.FieldName, e.ModuleName)
}
func (module *Module) resolveImports(resolve ResolveFunc) error {
if module.Import == nil {
return nil
}
modules := make(map[string]*Module)
var funcs uint32
for _, importEntry := range module.Import.Entries {
importedModule, ok := modules[importEntry.ModuleName]
if !ok {
var err error
importedModule, err = resolve(importEntry.ModuleName)
if err != nil {
return err
}
modules[importEntry.ModuleName] = importedModule
}
if importedModule.Export == nil {
return ErrNoExportsInImportedModule
}
exportEntry, ok := importedModule.Export.Entries[importEntry.FieldName]
if !ok {
return ExportNotFoundError{importEntry.ModuleName, importEntry.FieldName}
}
if exportEntry.Kind != importEntry.Type.Kind() {
return KindMismatchError{
FieldName: importEntry.FieldName,
ModuleName: importEntry.ModuleName,
Import: importEntry.Type.Kind(),
Export: exportEntry.Kind,
}
}
index := exportEntry.Index
switch exportEntry.Kind {
case ExternalFunction:
fn := importedModule.GetFunction(int(index))
if fn == nil {
return InvalidFunctionIndexError(index)
}
importIndex := importEntry.Type.(FuncImport).Type
if len(fn.Sig.ReturnTypes) != len(module.Types.Entries[importIndex].ReturnTypes) || len(fn.Sig.ParamTypes) != len(module.Types.Entries[importIndex].ParamTypes) {
return InvalidImportError{importEntry.ModuleName, importEntry.FieldName, importIndex}
}
for i, typ := range fn.Sig.ReturnTypes {
if typ != module.Types.Entries[importIndex].ReturnTypes[i] {
return InvalidImportError{importEntry.ModuleName, importEntry.FieldName, importIndex}
}
}
for i, typ := range fn.Sig.ParamTypes {
if typ != module.Types.Entries[importIndex].ParamTypes[i] {
return InvalidImportError{importEntry.ModuleName, importEntry.FieldName, importIndex}
}
}
module.FunctionIndexSpace = append(module.FunctionIndexSpace, *fn)
module.Code.Bodies = append(module.Code.Bodies, *fn.Body)
module.imports.Funcs = append(module.imports.Funcs, funcs)
funcs++
case ExternalGlobal:
glb := importedModule.GetGlobal(int(index))
if glb == nil {
return InvalidGlobalIndexError(index)
}
if glb.Type.Mutable {
return ErrImportMutGlobal
}
module.GlobalIndexSpace = append(module.GlobalIndexSpace, *glb)
module.imports.Globals++
// In both cases below, index should be always 0 (according to the MVP)
// We check it against the length of the index space anyway.
case ExternalTable:
if int(index) >= len(importedModule.TableIndexSpace) {
return InvalidTableIndexError(index)
}
module.TableIndexSpace[0] = importedModule.TableIndexSpace[0]
module.imports.Tables++
case ExternalMemory:
if int(index) >= len(importedModule.LinearMemoryIndexSpace) {
return InvalidLinearMemoryIndexError(index)
}
module.LinearMemoryIndexSpace[0] = importedModule.LinearMemoryIndexSpace[0]
module.imports.Memories++
default:
return InvalidExternalError(exportEntry.Kind)
}
}
return nil
}