land/vendor/github.com/go-interpreter/wagon/wasm/index.go

181 lines
4.8 KiB
Go

// 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 (
"fmt"
"reflect"
)
type InvalidTableIndexError uint32
func (e InvalidTableIndexError) Error() string {
return fmt.Sprintf("wasm: Invalid table to table index space: %d", uint32(e))
}
type InvalidValueTypeInitExprError struct {
Wanted reflect.Kind
Got reflect.Kind
}
func (e InvalidValueTypeInitExprError) Error() string {
return fmt.Sprintf("wasm: Wanted initializer expression to return %v value, got %v", e.Wanted, e.Got)
}
type InvalidLinearMemoryIndexError uint32
func (e InvalidLinearMemoryIndexError) Error() string {
return fmt.Sprintf("wasm: Invalid linear memory index: %d", uint32(e))
}
// Functions for populating and looking up entries in a module's index space.
// More info: http://webassembly.org/docs/modules/#function-index-space
func (m *Module) populateFunctions() error {
if m.Types == nil || m.Function == nil {
return nil
}
for codeIndex, typeIndex := range m.Function.Types {
if int(typeIndex) >= len(m.Types.Entries) {
return InvalidFunctionIndexError(typeIndex)
}
fn := Function{
Sig: &m.Types.Entries[typeIndex],
Body: &m.Code.Bodies[codeIndex],
}
m.FunctionIndexSpace = append(m.FunctionIndexSpace, fn)
}
funcs := make([]uint32, 0, len(m.Function.Types)+len(m.imports.Funcs))
funcs = append(funcs, m.imports.Funcs...)
funcs = append(funcs, m.Function.Types...)
m.Function.Types = funcs
return nil
}
// GetFunction returns a *Function, based on the function's index in
// the function index space. Returns nil when the index is invalid
func (m *Module) GetFunction(i int) *Function {
if i >= len(m.FunctionIndexSpace) || i < 0 {
return nil
}
return &m.FunctionIndexSpace[i]
}
func (m *Module) populateGlobals() error {
if m.Global == nil {
return nil
}
m.GlobalIndexSpace = append(m.GlobalIndexSpace, m.Global.Globals...)
logger.Printf("There are %d entries in the global index spaces.", len(m.GlobalIndexSpace))
return nil
}
// GetGlobal returns a *GlobalEntry, based on the global index space.
// Returns nil when the index is invalid
func (m *Module) GetGlobal(i int) *GlobalEntry {
if i >= len(m.GlobalIndexSpace) || i < 0 {
return nil
}
return &m.GlobalIndexSpace[i]
}
func (m *Module) populateTables() error {
if m.Table == nil || len(m.Table.Entries) == 0 || m.Elements == nil || len(m.Elements.Entries) == 0 {
return nil
}
for _, elem := range m.Elements.Entries {
// the MVP dictates that index should always be zero, we shuold
// probably check this
if int(elem.Index) >= len(m.TableIndexSpace) {
return InvalidTableIndexError(elem.Index)
}
val, err := m.ExecInitExpr(elem.Offset)
if err != nil {
return err
}
offset, ok := val.(int32)
if !ok {
return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(offset).Kind()}
}
table := m.TableIndexSpace[int(elem.Index)]
if int(offset)+len(elem.Elems) > len(table) {
data := make([]uint32, int(offset)+len(elem.Elems))
copy(data[offset:], elem.Elems)
copy(data, table)
m.TableIndexSpace[int(elem.Index)] = data
} else {
copy(table[int(offset):], elem.Elems)
m.TableIndexSpace[int(elem.Index)] = table
}
}
logger.Printf("There are %d entries in the table index space.", len(m.TableIndexSpace))
return nil
}
// GetTableElement returns an element from the tableindex space indexed
// by the integer index. It returns an error if index is invalid.
func (m *Module) GetTableElement(index int) (uint32, error) {
if index >= len(m.TableIndexSpace[0]) {
return 0, InvalidTableIndexError(index)
}
return m.TableIndexSpace[0][index], nil
}
func (m *Module) populateLinearMemory() error {
if m.Data == nil || len(m.Data.Entries) == 0 {
return nil
}
// each module can only have a single linear memory in the MVP
for _, entry := range m.Data.Entries {
if entry.Index != 0 {
return InvalidLinearMemoryIndexError(entry.Index)
}
val, err := m.ExecInitExpr(entry.Offset)
if err != nil {
return err
}
offset, ok := val.(int32)
if !ok {
return InvalidValueTypeInitExprError{reflect.Int32, reflect.TypeOf(offset).Kind()}
}
memory := m.LinearMemoryIndexSpace[int(entry.Index)]
if int(offset)+len(entry.Data) > len(memory) {
data := make([]byte, int(offset)+len(entry.Data))
copy(data[offset:], entry.Data)
copy(data, memory)
m.LinearMemoryIndexSpace[int(entry.Index)] = data
} else {
copy(memory[int(offset):], entry.Data)
m.LinearMemoryIndexSpace[int(entry.Index)] = memory
}
}
return nil
}
func (m *Module) GetLinearMemoryData(index int) (byte, error) {
if index >= len(m.LinearMemoryIndexSpace[0]) {
return 0, InvalidLinearMemoryIndexError(uint32(index))
}
return m.LinearMemoryIndexSpace[0][index], nil
}