Skip to content
This repository has been archived by the owner on May 11, 2020. It is now read-only.

Commit

Permalink
wasm: support name section
Browse files Browse the repository at this point in the history
  • Loading branch information
Denys Smirnov authored and sbinet committed Aug 8, 2018
1 parent 9c7430f commit 876a973
Showing 1 changed file with 224 additions and 0 deletions.
224 changes: 224 additions & 0 deletions wasm/section.go
Original file line number Diff line number Diff line change
Expand Up @@ -977,3 +977,227 @@ func (s *DataSegment) MarshalWASM(w io.Writer) error {
}
return writeBytesUint(w, s.Data)
}

// A list of well-known custom sections
const (
CustomSectionName = "name"
)

var (
_ Marshaler = (*NameSection)(nil)
_ Unmarshaler = (*NameSection)(nil)
)

// NameType is the type of name subsection.
type NameType byte

const (
NameModule = NameType(0)
NameFunction = NameType(1)
NameLocal = NameType(2)
)

// NameSection is a custom section that stores names of modules, functions and locals for debugging purposes.
// See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#name-section for more details.
type NameSection struct {
Types map[NameType][]byte
}

func (s *NameSection) UnmarshalWASM(r io.Reader) error {
s.Types = make(map[NameType][]byte)
for {
typ, err := leb128.ReadVarUint32(r)
if err == io.EOF {
return nil
} else if err != nil {
return err
}
data, err := readBytesUint(r)
if err != nil {
return err
}
s.Types[NameType(typ)] = data
}
}

func (s *NameSection) MarshalWASM(w io.Writer) error {
keys := make([]NameType, 0, len(s.Types))
for k := range s.Types {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
for _, k := range keys {
data := s.Types[k]
if _, err := leb128.WriteVarUint32(w, uint32(k)); err != nil {
return err
}
if err := writeBytesUint(w, data); err != nil {
return err
}
}
return nil
}

// Decode finds a specific subsection type and decodes it.
func (s *NameSection) Decode(typ NameType) (NameSubsection, error) {
var sub NameSubsection
switch typ {
case NameModule:
sub = &ModuleName{}
case NameFunction:
sub = &FunctionNames{}
case NameLocal:
sub = &LocalNames{}
default:
return nil, fmt.Errorf("unsupported name subsection: %x", typ)
}
data, ok := s.Types[typ]
if !ok {
return nil, nil
}
if err := sub.UnmarshalWASM(bytes.NewReader(data)); err != nil {
return nil, err
}
return sub, nil
}

// NameSubsection is an interface for subsections of NameSection.
//
// Valid types:
// * ModuleName
// * FunctionNames
// * LocalNames
type NameSubsection interface {
Marshaler
Unmarshaler
isNameSubsection()
}

// ModuleName is the name of a module.
type ModuleName struct {
Name string
}

func (*ModuleName) isNameSubsection() {}

func (s *ModuleName) UnmarshalWASM(r io.Reader) error {
var err error
s.Name, err = readStringUint(r)
return err
}

func (s *ModuleName) MarshalWASM(w io.Writer) error {
return writeStringUint(w, s.Name)
}

// FunctionNames is a set of names for functions.
type FunctionNames struct {
Names NameMap
}

func (*FunctionNames) isNameSubsection() {}

func (s *FunctionNames) UnmarshalWASM(r io.Reader) error {
s.Names = make(NameMap)
return s.Names.UnmarshalWASM(r)
}

func (s *FunctionNames) MarshalWASM(w io.Writer) error {
return s.Names.MarshalWASM(w)
}

// LocalNames is a set of local variable names for functions.
type LocalNames struct {
// Funcs maps a function index to a set of variable names.
Funcs map[uint32]NameMap
}

func (*LocalNames) isNameSubsection() {}

func (s *LocalNames) UnmarshalWASM(r io.Reader) error {
s.Funcs = make(map[uint32]NameMap)
size, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := 0; i < int(size); i++ {
ind, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
m := make(NameMap)
if err := m.UnmarshalWASM(r); err != nil {
return err
}
s.Funcs[ind] = m
}
return nil
}

func (s *LocalNames) MarshalWASM(w io.Writer) error {
keys := make([]uint32, 0, len(s.Funcs))
for k := range s.Funcs {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
for _, k := range keys {
m := s.Funcs[k]
if _, err := leb128.WriteVarUint32(w, k); err != nil {
return err
}
if err := m.MarshalWASM(w); err != nil {
return err
}
}
return nil
}

var (
_ Marshaler = (NameMap)(nil)
_ Unmarshaler = (NameMap)(nil)
)

// NameMap maps an index of the entry to a name.
type NameMap map[uint32]string

func (m NameMap) UnmarshalWASM(r io.Reader) error {
size, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
for i := 0; i < int(size); i++ {
ind, err := leb128.ReadVarUint32(r)
if err != nil {
return err
}
name, err := readStringUint(r)
if err != nil {
return err
}
m[ind] = name
}
return nil
}
func (m NameMap) MarshalWASM(w io.Writer) error {
keys := make([]uint32, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
for _, k := range keys {
name := m[k]
if _, err := leb128.WriteVarUint32(w, k); err != nil {
return err
}
if err := writeStringUint(w, name); err != nil {
return err
}
}
return nil
}

0 comments on commit 876a973

Please sign in to comment.