// 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/go-interpreter/wagon/wasm/internal/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 Types *SectionTypes Import *SectionImports Function *SectionFunctions Table *SectionTables Memory *SectionMemories Global *SectionGlobals Export *SectionExports Start *SectionStartFunction Elements *SectionElements Code *SectionCode Data *SectionData // 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 Other []Section // Other holds the custom sections if any imports struct { Funcs []uint32 Globals int Tables int Memories int } } // 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) // 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) { 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 { break } } m.LinearMemoryIndexSpace = make([][]byte, 1) if m.Table != nil { m.TableIndexSpace = make([][]uint32, int(len(m.Table.Entries))) } if m.Import != nil && resolvePath != nil { 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 }