[fidl][go] Switch to new encoding/decoding

Change-Id: Id5638e9c893d541b4fd39a77c77ba5fd446a2e3b
diff --git a/src/syscall/zx/fidl/bindings.go b/src/syscall/zx/fidl/bindings.go
index b330cea..4e9e56b 100644
--- a/src/syscall/zx/fidl/bindings.go
+++ b/src/syscall/zx/fidl/bindings.go
@@ -147,10 +147,10 @@
 	msg := respb[:nb]
 	handles := resph[:nh]
 	var header MessageHeader
-	if err := UnmarshalHeader(msg, &header); err != nil {
+	if _, _, err := UnmarshalNew(msg, nil, &header); err != nil {
 		return false, err
 	}
-	p, err := b.Stub.Dispatch(header.Ordinal, msg[MessageHeaderSize:], handles)
+	p, err := b.Stub.DispatchNew(header.Ordinal, msg[MessageHeaderSize:], handles)
 	switch {
 	case err == ErrUnknownOrdinal:
 		// If we couldn't determine the ordinal, we still own the
@@ -166,7 +166,7 @@
 	if p == nil {
 		return false, nil
 	}
-	cnb, cnh, err := MarshalMessage(&header, p, respb, resph)
+	cnb, cnh, err := marshalHeaderThenMessage(&header, p, respb, resph)
 	if err != nil {
 		return false, err
 	}
diff --git a/src/syscall/zx/fidl/deletemepostmigration.go b/src/syscall/zx/fidl/deletemepostmigration.go
new file mode 100644
index 0000000..5aa4788
--- /dev/null
+++ b/src/syscall/zx/fidl/deletemepostmigration.go
@@ -0,0 +1,67 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import "syscall/zx"
+
+// TODO(pascallouis): Delete all of this post migration.
+
+const MessageHeaderSize int = 16
+
+type Payload interface{}
+
+func MarshalHeader(header *MessageHeader, data []byte) {
+	_, _, err := MarshalNew(header, data, nil)
+	if err != nil {
+		panic(err)
+	}
+}
+
+func UnmarshalHeader(data []byte, header *MessageHeader) error {
+	_, _, err := UnmarshalNew(data, nil, header)
+	return err
+}
+
+func MarshalMessage(header *MessageHeader, s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+	return marshalHeaderThenMessage(header, toMessage(s), data, handles)
+}
+
+func UnmarshalMessage(data []byte, handles []zx.Handle, header *MessageHeader, s Payload) error {
+	return unmarshalHeaderThenMessage(data, handles, header, toMessage(s))
+}
+
+func (p *ChannelProxy) Send(ordinal uint32, req Payload) error {
+	return p.SendNew(ordinal, toMessage(req))
+}
+
+func (p *ChannelProxy) Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error {
+	return p.RecvNew(ordinal, toMessage(resp), gen_ordinal...)
+}
+
+func (p *ChannelProxy) Call(ordinal uint32, req Payload, resp Payload) error {
+	return p.CallNew(ordinal, toMessage(req), resp.(Message))
+}
+
+func (p *SocketControlProxy) Send(ordinal uint32, req Payload) error {
+	return p.SendNew(ordinal, toMessage(req))
+}
+
+func (p *SocketControlProxy) Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error {
+	return p.RecvNew(ordinal, toMessage(resp), gen_ordinal...)
+}
+
+func (p *SocketControlProxy) Call(ordinal uint32, req Payload, resp Payload) error {
+	return p.CallNew(ordinal, toMessage(req), toMessage(resp))
+}
+
+func toMessage(s Payload) Message {
+	var msg Message
+	if s != nil {
+		msg = s.(Message)
+	}
+	return msg
+}
diff --git a/src/syscall/zx/fidl/encoding.go b/src/syscall/zx/fidl/encoding.go
index e2c6394..7410470 100644
--- a/src/syscall/zx/fidl/encoding.go
+++ b/src/syscall/zx/fidl/encoding.go
@@ -7,11 +7,8 @@
 package fidl
 
 import (
-	"errors"
 	"math"
 	"reflect"
-	"strconv"
-	"strings"
 	"syscall/zx"
 )
 
@@ -41,33 +38,6 @@
 	proxyType                         = reflect.TypeOf(ChannelProxy{})
 )
 
-type structKind int
-
-const (
-	_ structKind = iota
-	aStruct
-	aUnion
-	aXUnion
-	aTable
-)
-
-// whichStructKind returns the kind of FIDL type this golang type represents.
-func whichStructKind(t reflect.Type) structKind {
-	if t.Kind() != reflect.Struct {
-		panic("can only determine struct kind")
-	}
-	if t.NumField() > 1 {
-		if t.Field(0).Tag.Get("fidl") == "tag" {
-			return aUnion
-		} else if strings.HasPrefix(t.Field(0).Tag.Get("fidl2"), "t") {
-			return aTable
-		} else if strings.HasPrefix(t.Field(0).Tag.Get("fidl2"), "x") {
-			return aXUnion
-		}
-	}
-	return aStruct
-}
-
 // isHandleType returns true if the reflected type is a Fuchsia handle type.
 func isHandleType(t reflect.Type) bool {
 	switch t {
@@ -104,158 +74,6 @@
 	return t.ConvertibleTo(interfaceRequestType)
 }
 
-// getSize returns the size of the type. Occasionally this requires the value,
-// particularly for a struct.
-func getSize(t reflect.Type, v reflect.Value) (int, error) {
-	switch t.Kind() {
-	case reflect.Array:
-		if v.Len() == 0 {
-			return 0, nil
-		}
-		s, err := getSize(t.Elem(), v.Index(0))
-		if err != nil {
-			return 0, err
-		}
-		return v.Len() * s, nil
-	case reflect.Bool, reflect.Int8, reflect.Uint8:
-		return 1, nil
-	case reflect.Int16, reflect.Uint16:
-		return 2, nil
-	case reflect.Int32, reflect.Uint32, reflect.Float32:
-		return 4, nil
-	case reflect.Int64, reflect.Uint64, reflect.Float64:
-		return 8, nil
-	case reflect.Ptr:
-		i := t.Elem()
-		switch i.Kind() {
-		case reflect.Slice:
-			return 16, nil
-		case reflect.String:
-			return 16, nil
-		case reflect.Struct:
-			// Handles structs, unions, and tables.
-			return 8, nil
-		}
-		return 0, newValueError(ErrInvalidPointerType, t.Name())
-	case reflect.String:
-		return 16, nil
-	case reflect.Slice:
-		return 16, nil
-	case reflect.Struct:
-		// Handles structs, unions, and tables.
-		return getPayloadSize(t, v)
-	}
-	return 0, newValueError(ErrInvalidInlineType, t.Name())
-}
-
-func structAsPayload(t reflect.Type, v reflect.Value) (Payload, error) {
-	// Get the size and alignment for the struct.
-	//
-	// Note that Addr can fail if the originally derived value is not "addressable",
-	// meaning the root ValueOf() call was on a struct value, not a pointer. However,
-	// we guarantee the struct is addressable by forcing a Payload to be passed in
-	// (a struct value will never cast as an interface).
-	//
-	// We avoid using Implements(), MethodByName(), and Call() here because they're
-	// very slow.
-	payload, ok := v.Addr().Interface().(Payload)
-	if !ok {
-		return nil, ErrStructIsNotPayload
-	}
-	return payload, nil
-}
-
-func getPayloadSize(t reflect.Type, v reflect.Value) (int, error) {
-	p, err := structAsPayload(t, v)
-	if err != nil {
-		return 0, err
-	}
-	return p.InlineSize(), nil
-}
-
-func getPayloadAlignment(t reflect.Type, v reflect.Value) (int, error) {
-	p, err := structAsPayload(t, v)
-	if err != nil {
-		return 0, err
-	}
-	return p.InlineAlignment(), nil
-}
-
-// fieldData contains metadata for a single struct field for use during encoding and
-// decoding. It is derived from a struct field tag, and generally contains facilities
-// for managing state in a recursive context (since even the type in a single struct field
-// may be recursively defined).
-type nestedTypeData struct {
-	// maxElems represents the maximum number of elements allowed for a
-	// container type. "nil" means there is no maximum. It is represented
-	// as a slice because FIDL container types may be nested arbitrarily
-	// deeply. The lower the index, the more deeply nested the type is.
-	maxElems []*int
-
-	// nullable reflects whether the innermost type for a struct field is nullable.
-	// This is only used for types where nullability is non-obvious, which is only
-	// handles for now.
-	nullable bool
-
-	// ordinal captures the table ordinal if applicable
-	ordinal int
-
-	// tagKind: fidl2 tag
-	tagKind
-
-	// bounds: fidl2 bounds
-	bounds
-}
-
-// Unnest attempts to unnest the nestedTypeData one level. If it succeeds, it returns the type
-// data for that nesting level, and modifies the data structure for the next nested container.
-func (n *nestedTypeData) Unnest() *int {
-	if len(n.maxElems) == 0 {
-		return nil
-	}
-	v := n.maxElems[len(n.maxElems)-1]
-	n.maxElems = n.maxElems[:len(n.maxElems)-1]
-	return v
-}
-
-// FromTag derives metadata from data serialized into a golang struct field
-// tag.
-func (n *nestedTypeData) FromTag(field reflect.StructField, isTable bool) error {
-	tagKind, bounds := readTag(field)
-	n.tagKind = tagKind
-	n.bounds = bounds
-
-	raw, ok := field.Tag.Lookup("fidl")
-	if !ok {
-		return nil
-	}
-	split := strings.Split(raw, ",")
-	if split[0] == "*" {
-		n.nullable = true
-		split = split[1:]
-	}
-	var maxElems []*int
-	for _, e := range split {
-		if e == "" {
-			maxElems = append(maxElems, nil)
-			continue
-		}
-		i, err := strconv.ParseInt(e, 0, 64)
-		if err != nil {
-			return err
-		}
-		val := int(i)
-		maxElems = append(maxElems, &val)
-	}
-	if isTable {
-		lenMaxElems := len(maxElems)
-		n.ordinal = *maxElems[lenMaxElems-1]
-		maxElems = maxElems[:lenMaxElems-1]
-	}
-	n.maxElems = maxElems
-	return nil
-}
-
 // align increases size such that size is aligned to bytes, and returns the new size.
 //
 // bytes must be a power of 2.
@@ -292,16 +110,6 @@
 	return start
 }
 
-// writeInt writes an integer of byte-width size to the buffer.
-//
-// Before writing, it pads the buffer such that the integer is aligned to
-// its own byte-width.
-//
-// size must be a power of 2 <= 8.
-func (e *encoder) writeInt(val int64, size int) {
-	e.writeUint(uint64(val), size)
-}
-
 // writeUint writes an unsigned integer of byte-width size to the buffer.
 //
 // Before writing, it pads the buffer such that the integer is aligned to
@@ -317,373 +125,6 @@
 	e.head += size
 }
 
-// marshalStructOrUnionInline first aligns head to the struct's or union's alignment
-// factor, and then writes its field(s) inline.
-//
-// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
-func (e *encoder) marshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
-	a, err := getPayloadAlignment(t, v)
-	if err != nil {
-		return err
-	}
-	e.head = align(e.head, a)
-	switch whichStructKind(t) {
-	case aUnion:
-		err = e.marshalUnion(t, v, a)
-	case aStruct:
-		err = e.marshalStructFields(t, v)
-	case aXUnion:
-		fallthrough
-	case aTable:
-		err = e.marshalWithMarshaler(t, v)
-	}
-	if err != nil {
-		return err
-	}
-	e.head = align(e.head, a)
-	return nil
-}
-
-// marshalStructOrUnionPointer marshals a nullable struct's or union's reference, and then
-// marshals the value itself out-of-line.
-//
-// Expects the Type t and Value v to refer to a pointer to a golang struct.
-func (e *encoder) marshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
-	if v.IsNil() {
-		e.writeUint(noAlloc, 8)
-		return nil
-	}
-	e.writeUint(allocPresent, 8)
-	et := t.Elem()
-	ev := v.Elem()
-	// Encode the value out-of-line.
-	payload, err := structAsPayload(et, ev)
-	if err != nil {
-		return err
-	}
-	oldHead := e.head
-	e.head = e.newObject(align(payload.InlineSize(), 8))
-	switch whichStructKind(et) {
-	case aUnion:
-		err = e.marshalUnion(et, ev, payload.InlineAlignment())
-	case aStruct:
-		err = e.marshalStructFields(et, ev)
-	}
-	if err != nil {
-		return err
-	}
-	e.head = oldHead
-	return nil
-}
-
-// marshalStructFields marshals the fields of a struct inline without any alignment.
-//
-// Expects the Type t and Value v to refer to a struct value, not a pointer.
-//
-// It marshals only exported struct fields.
-func (e *encoder) marshalStructFields(t reflect.Type, v reflect.Value) error {
-	// TODO(FIDL-410): Currently, we generate a request or response struct with
-	// size 0 for methods and events with no arguments or returns. This escapes
-	// this case. We shouldn't generate those structs, and instead assemble
-	// transactional messages differently.
-	if v.Addr().Interface().(Payload).InlineSize() == 0 {
-		return nil
-	}
-
-	var exportedNumFields int
-
-	for i := 0; i < t.NumField(); i++ {
-		f := t.Field(i)
-		// If it's an unexported field, ignore it.
-		if f.PkgPath != "" {
-			continue
-		}
-
-		exportedNumFields++
-
-		var n nestedTypeData
-		if err := n.FromTag(f, false); err != nil {
-			return err
-		}
-		if err := e.marshal(f.Type, v.Field(i), n); err != nil {
-			return err
-		}
-	}
-
-	if exportedNumFields == 0 {
-		// Encountered an empty struct, which is all-zero and has a size of 1.
-		e.writeUint(0, 1)
-	}
-
-	return nil
-}
-
-// marshalUnion marshals a FIDL union represented as a golang struct inline,
-// without any external alignment.
-//
-// Expects the Type t and Value v to refer to a golang struct value, not a
-// pointer. The alignment field is used to align the union's field.
-func (e *encoder) marshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
-	fieldIndex := int(v.Field(0).Uint()) // Union tag values start at 1.
-	if fieldIndex < 1 || fieldIndex >= t.NumField() {
-		return newValueError(ErrInvalidUnionTag, fieldIndex)
-	}
-
-	kind := uint64(fieldIndex - 1) // Wire format tags start at 0.
-	// Save the head for proper padding.
-	head := e.head
-	e.writeUint(kind, 4)
-
-	f := t.Field(fieldIndex)
-	var n nestedTypeData
-	if err := n.FromTag(f, false); err != nil {
-		return err
-	}
-	// Re-align to the union's alignment before writing its field.
-	e.head = align(e.head, alignment)
-	if err := e.marshal(f.Type, v.Field(fieldIndex), n); err != nil {
-		return err
-	}
-	s, err := getPayloadSize(t, v)
-	if err != nil {
-		return err
-	}
-	e.head = head + s
-	return nil
-}
-
-func (e *encoder) marshalWithMarshaler(t reflect.Type, v reflect.Value) error {
-	m, err := createMarshaler(t)
-	if err != nil {
-		return err
-	}
-	return m.marshal(v, e)
-}
-
-func (e *encoder) marshalWithOptMarshaler(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	m, err := createOptMarshalerForField(t.Elem(), n.bounds)
-	if err != nil {
-		return err
-	}
-	return m.marshal(v, e)
-}
-
-// marshalArray marshals a FIDL array inline.
-func (e *encoder) marshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	elemType := t.Elem()
-	for i := 0; i < t.Len(); i++ {
-		if err := e.marshal(elemType, v.Index(i), n); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// marshalInline marshals a number of different supported FIDL types inline.
-func (e *encoder) marshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	switch t.Kind() {
-	case reflect.Array:
-		return e.marshalArray(t, v, n)
-	case reflect.Bool:
-		i := uint64(0)
-		if v.Bool() {
-			i = 1
-		}
-		e.writeUint(i, 1)
-	case reflect.Int8:
-		e.writeInt(v.Int(), 1)
-	case reflect.Int16:
-		e.writeInt(v.Int(), 2)
-	case reflect.Int32:
-		e.writeInt(v.Int(), 4)
-	case reflect.Int64:
-		e.writeInt(v.Int(), 8)
-	case reflect.Uint8:
-		e.writeUint(v.Uint(), 1)
-	case reflect.Uint16:
-		e.writeUint(v.Uint(), 2)
-	case reflect.Uint32:
-		e.writeUint(v.Uint(), 4)
-	case reflect.Uint64:
-		e.writeUint(v.Uint(), 8)
-	case reflect.Float32:
-		e.writeUint(uint64(math.Float32bits(float32(v.Float()))), 4)
-	case reflect.Float64:
-		e.writeUint(math.Float64bits(v.Float()), 8)
-	case reflect.Struct:
-		return e.marshalStructOrUnionInline(t, v)
-	default:
-		return newValueError(ErrInvalidInlineType, t.Name())
-	}
-	return nil
-}
-
-// marshalVector writes the vector metadata inline and the elements of the vector in a new
-// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
-func (e *encoder) marshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	if !v.IsValid() {
-		e.writeUint(0, 8)
-		e.writeUint(noAlloc, 8)
-		return nil
-	}
-	max := n.Unnest()
-	if max != nil && v.Len() > *max {
-		return newExpectError(ErrVectorTooLong, *max, v.Len())
-	}
-	e.writeUint(uint64(v.Len()), 8)
-	e.writeUint(allocPresent, 8)
-	// Don't bother creating the out-of-line struct if its length is 0.
-	if v.Len() == 0 {
-		return nil
-	}
-	elemType := t.Elem()
-	elemSize, err := getSize(elemType, v.Index(0))
-	if err != nil {
-		return err
-	}
-	// Encode in the out-of-line object.
-	oldHead := e.head
-	e.head = e.newObject(v.Len() * elemSize)
-
-	if elemType.Kind() == reflect.Uint8 {
-		// optimize the fdio case of a vector of bytes
-		copy(e.buffer[e.head:], v.Bytes())
-	} else {
-		for i := 0; i < v.Len(); i++ {
-			if err := e.marshal(elemType, v.Index(i), n); err != nil {
-				return err
-			}
-		}
-	}
-	e.head = oldHead
-	return nil
-}
-
-// marshalString writes the string metadata inline and the bytes of the string in a new
-// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
-func (e *encoder) marshalString(v reflect.Value, n nestedTypeData) error {
-	if !v.IsValid() {
-		e.writeUint(0, 8)
-		e.writeUint(noAlloc, 8)
-		return nil
-	}
-	s := v.String()
-	max := n.Unnest()
-	if max != nil && len(s) > *max {
-		return newExpectError(ErrStringTooLong, *max, len(s))
-	}
-	e.writeUint(uint64(len(s)), 8)
-	e.writeUint(allocPresent, 8)
-
-	// Create a new out-of-line object and write bytes of the string.
-	head := e.newObject(len(s))
-	for i := 0; i < len(s); i++ {
-		e.buffer[head+i] = s[i]
-	}
-	return nil
-}
-
-// marshalHandle marshals a Fuchsia handle type, and ensures that the handle is
-// valid if it is not nullable.
-func (e *encoder) marshalHandle(v reflect.Value, n nestedTypeData) error {
-	// The underlying type of all the handles is a uint32, so we're
-	// safe calling Uint(). This will panic if that is no longer true.
-	raw := zx.Handle(v.Uint())
-	if raw == zx.HandleInvalid {
-		if !n.nullable {
-			return ErrUnexpectedNullHandle
-		}
-		e.writeUint(uint64(noHandle), 4)
-		return nil
-	}
-	e.handles = append(e.handles, raw)
-	e.writeUint(uint64(handlePresent), 4)
-	return nil
-}
-
-// marshalPointer marshals nullable FIDL types that are represented by golang pointer
-// indirections. The input type and value should be the dereference of the golang pointers,
-// that is, if we're marshalling *string, we should get string.
-func (e *encoder) marshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	switch t.Elem().Kind() {
-	case reflect.Slice:
-		return e.marshalVector(t.Elem(), v.Elem(), n)
-	case reflect.String:
-		return e.marshalString(v.Elem(), n)
-	case reflect.Struct:
-		if whichStructKind(t.Elem()) == aXUnion {
-			return e.marshalWithOptMarshaler(t, v, n)
-		}
-		return e.marshalStructOrUnionPointer(t, v)
-	}
-	return newValueError(ErrInvalidPointerType, t.Name())
-}
-
-// marshal is the central recursive function core to marshalling, and
-// traverses the tree-like structure of the input type t. v represents
-// the value associated with the type t.
-func (e *encoder) marshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	switch t.Kind() {
-	case reflect.Ptr:
-		return e.marshalPointer(t, v, n)
-	case reflect.Slice:
-		return e.marshalVector(t, v, n)
-	case reflect.String:
-		return e.marshalString(v, n)
-	}
-	if isHandleType(t) {
-		return e.marshalHandle(v, n)
-	}
-	if isInterfaceType(t) || isInterfaceRequestType(t) {
-		// An interface is represented by a Proxy, whose first field is
-		// a zx.Channel, and we can just marshal that. Same goes for an
-		// interface request, which is just an InterfaceRequest whose
-		// first field is a zx.Channel.
-		return e.marshalHandle(v.Field(0), n)
-	}
-	return e.marshalInline(t, v, n)
-}
-
-// MarshalHeader encodes the FIDL message header into the beginning of data.
-func MarshalHeader(header *MessageHeader, data []byte) {
-	// Clear the buffer so we can append to it.
-	e := encoder{buffer: data[:0]}
-	e.head = e.newObject(MessageHeaderSize)
-	e.writeUint(uint64(header.Txid), 4)
-	e.writeUint(uint64(header.Reserved), 4)
-	e.writeUint(uint64(header.Flags), 4)
-	e.writeUint(uint64(header.Ordinal), 4)
-}
-
-// Marshal the FIDL payload in s into data and handles.
-//
-// s must be a pointer to a struct, since the primary object in a FIDL message
-// is always a struct.
-//
-// Marshal traverses the value s recursively, following nested type values via
-// reflection in order to encode the FIDL struct.
-func Marshal(s Payload, data []byte, handles []zx.Handle) (int, int, error) {
-	// First, let's make sure we have the right type in s.
-	t := reflect.TypeOf(s)
-	if t.Kind() != reflect.Ptr {
-		return 0, 0, errors.New("expected a pointer")
-	}
-	t = t.Elem()
-	if t.Kind() != reflect.Struct {
-		return 0, 0, errors.New("primary object must be a struct")
-	}
-
-	// Now, let's get the value of s, marshal the header into a starting
-	// buffer, and then marshal the rest of the payload in s.
-	v := reflect.ValueOf(s).Elem()
-	e := encoder{buffer: data[:0], handles: handles[:0]}
-	e.head = e.newObject(s.InlineSize())
-	if err := e.marshalStructFields(t, v); err != nil {
-		return 0, 0, err
-	}
-	return len(e.buffer), len(e.handles), nil
-}
-
 // decoder represents the decoding context that is necessary to maintain
 // across recursive calls within the same FIDL object.
 type decoder struct {
@@ -702,18 +143,6 @@
 	handles []zx.Handle
 }
 
-// readInt reads an integer value of byte-width size from the
-// buffer, and protects against reading past the end of the buffer.
-//
-// Before a read, the head is moved forward so as to be naturally aligned with
-// the byte-width of the integer it is reading.
-//
-// size must be a power of 2 <= 8.
-func (d *decoder) readInt(size int) (int64, error) {
-	i, err := d.readUint(size)
-	return int64(i), err
-}
-
 // readUint reads an unsigned integer value of byte-width size from the
 // buffer, and protects against reading past the end of the buffer.
 //
@@ -738,453 +167,3 @@
 	d.head += size
 	return val, nil
 }
-
-// unmarshalStructOrUnionInline unmarshals a struct or union inline based on Type t
-// into Value v, first aligning head to the alignment of the value.
-//
-// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
-func (d *decoder) unmarshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
-	a, err := getPayloadAlignment(t, v)
-	if err != nil {
-		return err
-	}
-	d.head = align(d.head, a)
-	switch whichStructKind(t) {
-	case aUnion:
-		err = d.unmarshalUnion(t, v, a)
-	case aStruct:
-		err = d.unmarshalStructFields(t, v)
-	case aXUnion:
-		fallthrough
-	case aTable:
-		err = d.unmarshalWithMarshaler(t, v)
-	}
-	if err != nil {
-		return err
-	}
-	d.head = align(d.head, a)
-	return nil
-}
-
-// unmarshalStructOrUnionPointer unmarshals a pointer to a golang struct (i.e. a
-// nullable FIDL struct or union) into the Value v.
-//
-// Expects the Type t and Value v to refer to a pointer to a golang struct.
-func (d *decoder) unmarshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
-	if i, err := d.readUint(8); err != nil {
-		return err
-	} else if i == noAlloc {
-		v.Set(reflect.Zero(t))
-		return nil
-	}
-
-	// Create the new struct.
-	v.Set(reflect.New(t.Elem()))
-	et := t.Elem()
-	ev := v.Elem()
-
-	// Set up the out-of-line space and the head.
-	oldHead := d.head
-	d.head = d.nextObject
-	payload, err := structAsPayload(et, ev)
-	if err != nil {
-		return err
-	}
-	d.nextObject += align(payload.InlineSize(), 8)
-
-	// Unmarshal the value itself out-of-line.
-	switch whichStructKind(et) {
-	case aUnion:
-		err = d.unmarshalUnion(et, ev, payload.InlineAlignment())
-	case aStruct:
-		err = d.unmarshalStructFields(et, ev)
-	}
-	if err != nil {
-		return err
-	}
-
-	// Fix up head to the old head if it's a nullable struct.
-	d.head = oldHead
-	return nil
-}
-
-// unmarshalStructFields unmarshals the exported fields of the struct at d.head into
-// the Value v.
-//
-// Expects the Type t and Value v to refer to a struct value, not a pointer.
-func (d *decoder) unmarshalStructFields(t reflect.Type, v reflect.Value) error {
-	// TODO(FIDL-410): Currently, we generate a request or response struct with
-	// size 0 for methods and events with no arguments or returns. This escapes
-	// this case. We shouldn't generate those structs, and instead assemble
-	// transactional messages differently.
-	if v.Addr().Interface().(Payload).InlineSize() == 0 {
-		return nil
-	}
-
-	var exportedNumFields int
-
-	for i := 0; i < t.NumField(); i++ {
-		f := t.Field(i)
-
-		// If it's an unexported field, ignore it.
-		if f.PkgPath != "" {
-			continue
-		}
-
-		exportedNumFields++
-
-		var n nestedTypeData
-		if err := n.FromTag(f, false); err != nil {
-			return err
-		}
-
-		if err := d.unmarshal(f.Type, v.Field(i), n); err != nil {
-			return err
-		}
-	}
-
-	if exportedNumFields == 0 {
-		// Encountered an empty struct, which should be all-zero and has a size of
-		// 1.
-		expectedZero, err := d.readUint(1)
-		if err != nil {
-			return err
-		} else if expectedZero != 0 {
-			return newValueError(ErrInvalidEmptyStruct, expectedZero)
-		}
-	}
-
-	return nil
-}
-
-// unmarshalUnion unmarshals a FIDL union at d.head into the Value v (a golang
-// struct) without any external alignment.
-//
-// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
-// The alignment field is used to align to the union's field before reading.
-func (d *decoder) unmarshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
-	// Save the head for proper padding.
-	head := d.head
-	kind, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-
-	// Index into the fields of the struct, adding 1 for the tag.
-	fieldIndex := int(kind) + 1
-	if fieldIndex >= t.NumField() {
-		return ErrInvalidUnionTag
-	}
-	v.Field(0).SetUint(kind + 1)
-
-	f := t.Field(fieldIndex)
-	var n nestedTypeData
-	if err := n.FromTag(f, false); err != nil {
-		return err
-	}
-	d.head = align(d.head, alignment)
-	if err := d.unmarshal(f.Type, v.Field(fieldIndex), n); err != nil {
-		return err
-	}
-	s, err := getPayloadSize(t, v)
-	if err != nil {
-		return err
-	}
-	d.head = head + s
-	return nil
-}
-
-func (d *decoder) unmarshalWithMarshaler(t reflect.Type, v reflect.Value) error {
-	m, err := createMarshaler(t)
-	if err != nil {
-		return err
-	}
-	return m.unmarshal(d, v)
-}
-
-func (d *decoder) unmarshalWithOptMarshaler(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	m, err := createOptMarshalerForField(t.Elem(), n.bounds)
-	if err != nil {
-		return err
-	}
-	return m.unmarshal(d, v)
-}
-
-// unmarshalArray unmarshals an array inline based on Type t into Value v, taking into account
-// nestedTypeData n, since an array is a container type.
-func (d *decoder) unmarshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	elemType := t.Elem()
-	for i := 0; i < t.Len(); i++ {
-		if err := d.unmarshal(elemType, v.Index(i), n); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// unmarshalInline unmarshals a variety of types inline, or delegates to their types' specific
-// unmarshalling functions.
-func (d *decoder) unmarshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	kind := t.Kind()
-	if kind == reflect.Array {
-		return d.unmarshalArray(t, v, n)
-	}
-	if kind == reflect.Struct {
-		return d.unmarshalStructOrUnionInline(t, v)
-	}
-
-	val, err := d.readUint(int(t.Size()))
-	if err != nil {
-		return err
-	}
-
-	switch kind {
-	case reflect.Bool:
-		switch val {
-		case 0:
-			v.SetBool(false)
-		case 1:
-			v.SetBool(true)
-		default:
-			return newValueError(ErrInvalidBoolValue, val)
-		}
-	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		v.SetInt(int64(val))
-	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		v.SetUint(val)
-	case reflect.Float32:
-		v.SetFloat(float64(math.Float32frombits(uint32(val))))
-	case reflect.Float64:
-		v.SetFloat(math.Float64frombits(val))
-	default:
-		return newValueError(ErrInvalidInlineType, t.Name())
-	}
-	return nil
-}
-
-// unmarshalVector unmarshals an out-of-line FIDL vector into a golang slice which is placed
-// into v. nestedTypeData is also necessary because a vector can have a maximum size). The
-// expected types and values are either pointers, i.e. *[]int8 or an "inline" vector value
-// i.e. []int8.
-func (d *decoder) unmarshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	size, err := d.readInt(8)
-	if err != nil {
-		return err
-	} else if size < 0 {
-		return newExpectError(ErrVectorTooLong, math.MaxInt64, size)
-	}
-	if ptr, err := d.readUint(8); err != nil {
-		return err
-	} else if ptr == noAlloc {
-		if t.Kind() != reflect.Ptr {
-			return newValueError(ErrUnexpectedNullRef, "vector")
-		}
-		v.Set(reflect.Zero(t))
-		return nil
-	}
-	max := n.Unnest()
-	if max != nil && int(size) > *max {
-		return newExpectError(ErrVectorTooLong, *max, size)
-	}
-
-	// Create the slice with reflection.
-	sliceType := t
-	elemType := t.Elem()
-	if t.Kind() == reflect.Ptr {
-		sliceType = elemType
-		elemType = sliceType.Elem()
-	}
-	s := reflect.MakeSlice(sliceType, int(size), int(size))
-
-	// Unmarshal the out-of-line structure.
-	oldHead := d.head
-	d.head = d.nextObject
-	// TODO(mknyszek): Get rid of this extra reflect.New somehow.
-	elemSize, err := getSize(elemType, reflect.New(elemType).Elem())
-	if err != nil {
-		return err
-	}
-	d.nextObject += align(int(size)*elemSize, 8)
-	if elemType.Kind() == reflect.Uint8 {
-		copy(s.Bytes(), d.buffer[d.head:])
-	} else {
-		for i := 0; i < int(size); i++ {
-			if err := d.unmarshal(elemType, s.Index(i), n); err != nil {
-				return err
-			}
-		}
-	}
-	d.head = oldHead
-	if t.Kind() == reflect.Ptr {
-		v.Set(reflect.New(t.Elem()))
-		v.Elem().Set(s)
-	} else {
-		v.Set(s)
-	}
-	return nil
-}
-
-// unmarshalString unmarshals an out-of-line FIDL string into a golang string which is placed
-// into v. nestedTypeData is also necessary because it can have a maximum size). The expected
-// types and values are either pointers, i.e. *string or an "inline" string value. i.e. string.
-// This method uses whether or not the type is a golang pointer type to determine if it is
-// nullable.
-func (d *decoder) unmarshalString(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	size, err := d.readInt(8)
-	if err != nil {
-		return err
-	} else if size < 0 {
-		return newExpectError(ErrVectorTooLong, math.MaxInt64, size)
-	}
-
-	if ptr, err := d.readUint(8); err != nil {
-		return err
-	} else if ptr == noAlloc {
-		if t.Kind() != reflect.Ptr {
-			return newValueError(ErrUnexpectedNullRef, "string")
-		}
-		v.Set(reflect.Zero(t))
-		return nil
-	}
-	max := n.Unnest()
-	if max != nil && int(size) > *max {
-		return newExpectError(ErrStringTooLong, *max, size)
-	}
-	s := string(d.buffer[d.nextObject : d.nextObject+int(size)])
-	if t.Kind() == reflect.Ptr {
-		v.Set(reflect.New(t.Elem()))
-		v.Elem().Set(reflect.ValueOf(s))
-	} else {
-		v.Set(reflect.ValueOf(s))
-	}
-	d.nextObject += align(int(size), 8)
-	return nil
-}
-
-// unmarshalHandle unmarshals a handle into a value, validating that it is valid if the handle is
-// not nullable.
-func (d *decoder) unmarshalHandle(v reflect.Value, n nestedTypeData) error {
-	h, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-	switch h {
-	case uint64(noHandle):
-		if !n.nullable {
-			return ErrUnexpectedNullHandle
-		}
-		v.SetUint(uint64(zx.HandleInvalid))
-	case uint64(handlePresent):
-		if len(d.handles) == 0 {
-			return ErrNotEnoughHandles
-		}
-		v.SetUint(uint64(d.handles[0]))
-		d.handles = d.handles[1:]
-	default:
-		return newValueError(ErrBadHandleEncoding, h)
-	}
-	return nil
-}
-
-// unmarshalPointer unmarshals nullable FIDL types that are represented by golang pointer
-// indirections. The expected types and values t and v are pointers, i.e. they start with *.
-func (d *decoder) unmarshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	switch t.Elem().Kind() {
-	case reflect.Slice:
-		return d.unmarshalVector(t, v, n)
-	case reflect.String:
-		return d.unmarshalString(t, v, n)
-	case reflect.Struct:
-		if whichStructKind(t.Elem()) == aXUnion {
-			return d.unmarshalWithOptMarshaler(t, v, n)
-		}
-		return d.unmarshalStructOrUnionPointer(t, v)
-	}
-	return newValueError(ErrInvalidPointerType, t.Name())
-}
-
-// unmarshal is the central recursive function core to unmarshalling, and
-// traverses the tree-like structure of the input type t. v represents
-// the value associated with the type t.
-func (d *decoder) unmarshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
-	switch t.Kind() {
-	case reflect.Ptr:
-		return d.unmarshalPointer(t, v, n)
-	case reflect.Slice:
-		return d.unmarshalVector(t, v, n)
-	case reflect.String:
-		return d.unmarshalString(t, v, n)
-	}
-	if isHandleType(t) {
-		return d.unmarshalHandle(v, n)
-	}
-	if isInterfaceType(t) || isInterfaceRequestType(t) {
-		// An interface is represented by a Proxy, whose first field is
-		// a zx.Channel, and we can just marshal that. Same goes for an
-		// interface request, which is just an InterfaceRequest whose
-		// first field is a zx.Channel.
-		return d.unmarshalHandle(v.Field(0), n)
-	}
-
-	return d.unmarshalInline(t, v, n)
-}
-
-// UnmarshalHeader parses a FIDL header in the data into m.
-func UnmarshalHeader(data []byte, m *MessageHeader) error {
-	if len(data) < 16 {
-		return ErrMessageTooSmall
-	}
-	d := decoder{buffer: data}
-	txid, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-	reserved, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-	flags, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-	ordinal, err := d.readUint(4)
-	if err != nil {
-		return err
-	}
-
-	m.Txid = uint32(txid)
-	m.Reserved = uint32(reserved)
-	m.Flags = uint32(flags)
-	m.Ordinal = uint32(ordinal)
-	return nil
-}
-
-// Unmarshal parses the encoded FIDL payload in data and handles, storing the
-// decoded payload in s.
-//
-// The value pointed to by s must be a pointer to a golang struct which represents
-// the decoded primary object of a FIDL message. The data decode process is guided
-// by the structure of the struct pointed to by s.
-//
-// TODO(mknyszek): More rigorously validate the input.
-func Unmarshal(data []byte, handles []zx.Handle, s Payload) error {
-	// First, let's make sure we have the right type in s.
-	t := reflect.TypeOf(s)
-	if t.Kind() != reflect.Ptr {
-		return errors.New("expected a pointer")
-	}
-	t = t.Elem()
-	if t.Kind() != reflect.Struct {
-		return errors.New("primary object must be a struct")
-	}
-
-	// Get the payload's value and unmarshal it.
-	nextObject := align(s.InlineSize(), 8)
-	d := decoder{
-		buffer:     data,
-		handles:    handles,
-		nextObject: nextObject,
-	}
-
-	return d.unmarshalStructFields(t, reflect.ValueOf(s).Elem())
-}
diff --git a/src/syscall/zx/fidl/encoding_new.go b/src/syscall/zx/fidl/encoding_new.go
index 2233235..c49f270 100644
--- a/src/syscall/zx/fidl/encoding_new.go
+++ b/src/syscall/zx/fidl/encoding_new.go
@@ -94,7 +94,12 @@
 	return m.delegate.unmarshal(in, v)
 }
 
-// MarshalNew marshals (or encodes) a message into the data and handles slices.
+// Marshal marshals (or encodes) a message into the data and handles slices.
+func Marshal(s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+	return MarshalNew(s.(Message), data, handles)
+}
+
+// TODO(pascallouis): promote to being The Marshal.
 func MarshalNew(message Message, data []byte, handles []zx.Handle) (int, int, error) {
 	// By construction, we know that message is a pointer to a struct since
 	// we only generate pointer receiver methods for top-level messages.
@@ -116,9 +121,15 @@
 	return len(out.buffer), len(out.handles), nil
 }
 
-// UnmarshalNew unmarshals (or decodes) into message using the data and handles
+// Unmarshal unmarshals (or decodes) into message using the data and handles
 // slices.
-func UnmarshalNew(data []byte, handles []zx.Handle, message Message) error {
+func Unmarshal(data []byte, handles []zx.Handle, s Payload) error {
+	_, _, err := UnmarshalNew(data, handles, s.(Message))
+	return err
+}
+
+// TODO(pascallouis): promote to being The Unmarshal.
+func UnmarshalNew(data []byte, handles []zx.Handle, message Message) (int, int, error) {
 	// By construction, we know that message is a pointer to a struct since
 	// we only generate pointer receiver methods for top-level messages.
 	// Should one implement the interface differently, and call into this
@@ -136,7 +147,10 @@
 		handles:    handles,
 		nextObject: nextObject,
 	}
-	return m.unmarshal(in, v)
+	if err := m.unmarshal(in, v); err != nil {
+		return 0, 0, err
+	}
+	return len(in.buffer), len(handles) - len(in.handles), nil
 }
 
 const tagKey = "fidl2"
@@ -1147,7 +1161,7 @@
 
 func (m mInt) marshal(v reflect.Value, out *encoder) error {
 	size := int(m)
-	out.writeInt(v.Int(), size)
+	out.writeUint(uint64(v.Int()), size)
 	return nil
 }
 
diff --git a/src/syscall/zx/fidl/fidl_test/encoding_new_test.go b/src/syscall/zx/fidl/fidl_test/encoding_new_test.go
index 561de06..49e5034 100644
--- a/src/syscall/zx/fidl/fidl_test/encoding_new_test.go
+++ b/src/syscall/zx/fidl/fidl_test/encoding_new_test.go
@@ -19,30 +19,6 @@
 	. "syscall/zx/fidl/bindingstest"
 )
 
-type marshalFunc struct {
-	name string
-	fn   func(Message, []byte, []zx.Handle) (int, int, error)
-}
-
-var marshalFuncs = []marshalFunc{
-	{"Marshal", func(input Message, respb []byte, resph []zx.Handle) (int, int, error) {
-		return Marshal(input, respb, resph)
-	}},
-	{"MarshalNew", MarshalNew},
-}
-
-type unmarshalFunc struct {
-	name string
-	fn   func([]byte, []zx.Handle, Message) error
-}
-
-var unmarshalFuncs = []unmarshalFunc{
-	{"Unmarshal", func(respb []byte, resph []zx.Handle, output Message) error {
-		return Unmarshal(respb, resph, output)
-	}},
-	{"UnmarshalNew", UnmarshalNew},
-}
-
 type example struct {
 	name       string
 	input      Message
@@ -306,12 +282,8 @@
 	}
 }
 
-type checker struct {
-	marshalFunc
-	unmarshalFunc
-}
-
-func (c checker) check(t *testing.T, input Message, expectSize int) {
+// TODO(FIDL-508): Convert all these tests to be conformance tests, using GIDL.
+func check(t *testing.T, input Message, expectSize int) {
 	t.Helper()
 	defer func() {
 		if r := recover(); r != nil {
@@ -324,7 +296,7 @@
 	}()
 	var respb [zx.ChannelMaxMessageBytes]byte
 	var resph [zx.ChannelMaxMessageHandles]zx.Handle
-	nb, nh, err := c.marshalFunc.fn(input, respb[:], resph[:])
+	nb, nh, err := MarshalNew(input, respb[:], resph[:])
 	if err != nil {
 		t.Fatalf("marshal: failed: %s", err)
 	}
@@ -332,29 +304,31 @@
 		t.Fatalf("marshal: expected size %d but got %d: %v", expectSize, nb, respb[:nb])
 	}
 	output := makeDefault(input)
-	if err := c.unmarshalFunc.fn(respb[:nb], resph[:nh], output); err != nil {
+	nbActual, nhActual, err := UnmarshalNew(respb[:nb], resph[:nh], output)
+	if err != nil {
 		t.Fatalf("unmarshal: failed: %s", err)
 	}
 	if !reflect.DeepEqual(input, output) {
 		t.Fatalf("unmarshal: expected: %v, got: %v", input, output)
 	}
+	if nb != nbActual {
+		t.Fatalf("unmarshal: num bytes, expected: %d, got: %d", nb, nbActual)
+	}
+	if nh != nhActual {
+		t.Fatalf("unmarshal: num handles, expected: %d, got: %d", nh, nhActual)
+	}
 }
 
 func TestCorrectness(t *testing.T) {
-	for _, m := range marshalFuncs {
-		for _, u := range unmarshalFuncs {
-			c := checker{m, u}
-			for _, ex := range general() {
-				t.Run(fmt.Sprintf("%s-%s-%s", m.name, u.name, ex.name), func(t *testing.T) {
-					c.check(t, ex.input, ex.expectSize)
-				})
-			}
-			for _, ex := range fuchsia() {
-				t.Run(fmt.Sprintf("%s-%s-%s", m.name, u.name, ex.name), func(t *testing.T) {
-					c.check(t, ex.input, ex.expectSize)
-				})
-			}
-		}
+	for _, ex := range general() {
+		t.Run(ex.name, func(t *testing.T) {
+			check(t, ex.input, ex.expectSize)
+		})
+	}
+	for _, ex := range fuchsia() {
+		t.Run(ex.name, func(t *testing.T) {
+			check(t, ex.input, ex.expectSize)
+		})
 	}
 }
 
@@ -376,46 +350,49 @@
 }
 
 func (ex successCase) check(t *testing.T) {
-	for _, mFn := range marshalFuncs {
-		for _, uFn := range unmarshalFuncs {
-			t.Run(ex.name+"_"+mFn.name+"_"+uFn.name, func(t *testing.T) {
-				defer func() {
-					if r := recover(); r != nil {
-						// When running tests on device, this bubbles up the error
-						// on the console launching the tests, rather than having
-						// to look at the device's kernel logs.
-						t.Fatalf("panic: %s", r)
-						panic(r)
-					}
-				}()
-				var respb [zx.ChannelMaxMessageBytes]byte
-				var resph [zx.ChannelMaxMessageHandles]zx.Handle
-				nb, nh, err := mFn.fn(ex.input, respb[:], resph[:])
-				if err != nil {
-					t.Fatal(err)
-				}
-				if !bytes.Equal(ex.bytes, respb[:nb]) {
-					t.Fatalf("expected %x, got %x", ex.bytes, respb[:nb])
-				}
-				if len(ex.handles) == 0 {
-					if nh != 0 {
-						t.Fatalf("no handles expected, got %d", nh)
-					}
-				} else {
-					if !reflect.DeepEqual(ex.handles, resph[:nh]) {
-						t.Fatalf("expected %v, got %v", ex.handles, resph[:nh])
-					}
-				}
-				output := makeDefault(ex.input)
-				if err := uFn.fn(respb[:nb], resph[:nh], output); err != nil {
-					t.Fatalf("unmarshal: failed: %s", err)
-				}
-				if !reflect.DeepEqual(ex.input, output) {
-					t.Fatalf("unmarshal: expected: %v, got: %v", ex.input, output)
-				}
-			})
+	t.Run(ex.name, func(t *testing.T) {
+		defer func() {
+			// When running tests on device, this bubbles up the error on the
+			// console launching the tests, rather than having to look at the
+			// device's kernel logs.
+			if r := recover(); r != nil {
+				t.Fatalf("panic: %s", r)
+				panic(r)
+			}
+		}()
+		var respb [zx.ChannelMaxMessageBytes]byte
+		var resph [zx.ChannelMaxMessageHandles]zx.Handle
+		nb, nh, err := MarshalNew(ex.input, respb[:], resph[:])
+		if err != nil {
+			t.Fatal(err)
 		}
-	}
+		if !bytes.Equal(ex.bytes, respb[:nb]) {
+			t.Fatalf("expected %x, got %x", ex.bytes, respb[:nb])
+		}
+		if len(ex.handles) == 0 {
+			if nh != 0 {
+				t.Fatalf("no handles expected, got %d", nh)
+			}
+		} else {
+			if !reflect.DeepEqual(ex.handles, resph[:nh]) {
+				t.Fatalf("expected %v, got %v", ex.handles, resph[:nh])
+			}
+		}
+		output := makeDefault(ex.input)
+		nbActual, nhActual, err := UnmarshalNew(respb[:nb], resph[:nh], output)
+		if err != nil {
+			t.Fatalf("unmarshal: failed: %s", err)
+		}
+		if !reflect.DeepEqual(ex.input, output) {
+			t.Fatalf("unmarshal: expected: %v, got: %v", ex.input, output)
+		}
+		if nb != nbActual {
+			t.Fatalf("unmarshal: num bytes, expected: %d, got: %d", nb, nbActual)
+		}
+		if nh != nhActual {
+			t.Fatalf("unmarshal: num handles, expected: %d, got: %d", nh, nhActual)
+		}
+	})
 }
 
 type errorCaseUnmarshal struct {
@@ -894,12 +871,12 @@
 		&TestNewerSimpleTable{Table: nst},
 	}
 	for _, expected := range cases {
-		for _, u := range unmarshalFuncs {
-			output := makeDefault(expected)
-			u.fn(simpleTableWithXY, nil, output)
-			if !reflect.DeepEqual(expected, output) {
-				t.Fatalf("unmarshal: expected: %v, got: %v", expected, output)
-			}
+		output := makeDefault(expected)
+		if _, _, err := UnmarshalNew(simpleTableWithXY, nil, output); err != nil {
+			t.Fatalf("unmarshal: failed: %s", err)
+		}
+		if !reflect.DeepEqual(expected, output) {
+			t.Fatalf("unmarshal: expected: %v, got: %v", expected, output)
 		}
 	}
 }
@@ -916,12 +893,13 @@
 		&TestNewerSimpleTable{Table: nst},
 	}
 	for _, expected := range cases {
-		for _, u := range unmarshalFuncs {
-			output := makeDefault(expected)
-			u.fn(simpleTableWithY, nil, output)
-			if !reflect.DeepEqual(expected, output) {
-				t.Fatalf("unmarshal: expected: %v, got: %v", expected, output)
-			}
+		output := makeDefault(expected)
+		_, _, err := UnmarshalNew(simpleTableWithY, nil, output)
+		if err != nil {
+			t.Fatalf("unmarshal: failed: %s", err)
+		}
+		if !reflect.DeepEqual(expected, output) {
+			t.Fatalf("unmarshal: expected: %v, got: %v", expected, output)
 		}
 	}
 }
@@ -980,7 +958,7 @@
 func TestFailuresUnmarshalNoHandles(t *testing.T) {
 	for _, ex := range allErrorCasesUnmarshal {
 		t.Run(ex.name, func(t *testing.T) {
-			err := UnmarshalNew(ex.input, nil, ex.message)
+			_, _, err := UnmarshalNew(ex.input, nil, ex.message)
 			validationErr, ok := err.(ValidationError)
 			if !ok {
 				t.Fatalf("expected ValidationError, was %v", err)
@@ -993,19 +971,17 @@
 }
 
 func benchmarkMarshal(b *testing.B, ex example) {
-	for _, m := range marshalFuncs {
-		b.Run(fmt.Sprintf("%s-%s", m.name, ex.name), func(b *testing.B) {
-			b.StopTimer()
-			var respb [zx.ChannelMaxMessageBytes]byte
-			var resph [zx.ChannelMaxMessageHandles]zx.Handle
-			b.StartTimer()
-			for n := 0; n < b.N; n++ {
-				if _, _, err := m.fn(ex.input, respb[:], resph[:]); err != nil {
-					b.Fail()
-				}
+	b.Run(ex.name, func(b *testing.B) {
+		b.StopTimer()
+		var respb [zx.ChannelMaxMessageBytes]byte
+		var resph [zx.ChannelMaxMessageHandles]zx.Handle
+		b.StartTimer()
+		for n := 0; n < b.N; n++ {
+			if _, _, err := MarshalNew(ex.input, respb[:], resph[:]); err != nil {
+				b.Fail()
 			}
-		})
-	}
+		}
+	})
 }
 
 func BenchmarkMarshal(b *testing.B) {
@@ -1018,24 +994,22 @@
 }
 
 func benchmarkUnmarshal(b *testing.B, ex example) {
-	for _, u := range unmarshalFuncs {
-		b.Run(fmt.Sprintf("%s-%s", u.name, ex.name), func(b *testing.B) {
-			b.StopTimer()
-			var respb [zx.ChannelMaxMessageBytes]byte
-			var resph [zx.ChannelMaxMessageHandles]zx.Handle
-			nb, nh, err := Marshal(ex.input, respb[:], resph[:])
-			if err != nil {
+	b.Run(ex.name, func(b *testing.B) {
+		b.StopTimer()
+		var respb [zx.ChannelMaxMessageBytes]byte
+		var resph [zx.ChannelMaxMessageHandles]zx.Handle
+		nb, nh, err := MarshalNew(ex.input, respb[:], resph[:])
+		if err != nil {
+			b.Fail()
+		}
+		output := makeDefault(ex.input)
+		b.StartTimer()
+		for n := 0; n < b.N; n++ {
+			if _, _, err := UnmarshalNew(respb[:nb], resph[:nh], output); err != nil {
 				b.Fail()
 			}
-			output := makeDefault(ex.input)
-			b.StartTimer()
-			for n := 0; n < b.N; n++ {
-				if err := u.fn(respb[:nb], resph[:nh], output); err != nil {
-					b.Fail()
-				}
-			}
-		})
-	}
+		}
+	})
 }
 
 func BenchmarkUnmarshal(b *testing.B) {
diff --git a/src/syscall/zx/fidl/fidl_test/encoding_test.go b/src/syscall/zx/fidl/fidl_test/encoding_test.go
deleted file mode 100644
index d9f03e2..0000000
--- a/src/syscall/zx/fidl/fidl_test/encoding_test.go
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build fuchsia
-
-package fidl_test
-
-import (
-	"reflect"
-	"syscall/zx"
-	"testing"
-
-	. "syscall/zx/fidl"
-	. "syscall/zx/fidl/bindingstest"
-)
-
-func testIdentity(t *testing.T, input Payload, expectSize int, output Payload) {
-	t.Helper()
-	var respb [zx.ChannelMaxMessageBytes]byte
-	var resph [zx.ChannelMaxMessageHandles]zx.Handle
-	nb, nh, err := Marshal(input, respb[:], resph[:])
-	if err != nil {
-		t.Fatal(err)
-	}
-	if nb != expectSize {
-		t.Fatalf("expected size %d but got %d: %v", expectSize, nb, respb[:nb])
-	}
-	if err := Unmarshal(respb[:nb], resph[:nh], output); err != nil {
-		t.Fatal(err)
-	}
-	if !reflect.DeepEqual(input, output) {
-		t.Fatalf("expected: %v, got: %v", input, output)
-	}
-}
-
-func TestEncodingIdentity(t *testing.T) {
-	t.Run("Header", func(t *testing.T) {
-		var buf [MessageHeaderSize]byte
-		m := MessageHeader{
-			Txid:     1215,
-			Reserved: 0,
-			Flags:    111111,
-			Ordinal:  889,
-		}
-		MarshalHeader(&m, buf[:])
-
-		var header MessageHeader
-		if err := UnmarshalHeader(buf[:], &header); err != nil {
-			t.Fatal(err)
-		}
-		if m != header {
-			t.Fatalf("expected: %v, got: %v", m, header)
-		}
-	})
-	t.Run("Simple", func(t *testing.T) {
-		testIdentity(t, &TestSimple{X: 124}, 8, &TestSimple{})
-		testIdentity(t, &TestSimpleBool{X: true}, 8, &TestSimpleBool{})
-	})
-	t.Run("Alignment", func(t *testing.T) {
-		testIdentity(t, &TestAlignment1{X: -36, Y: -10, Z: 51}, 8, &TestAlignment1{})
-		testIdentity(t, &TestAlignment2{
-			A: 1212141,
-			B: 908935,
-			C: -1,
-			D: 125,
-			E: -22,
-			F: 111,
-			G: 1515,
-			H: 65535,
-			I: 1515,
-		}, 24, &TestAlignment2{})
-	})
-	t.Run("Floats", func(t *testing.T) {
-		testIdentity(t, &TestFloat1{A: -36.0}, 8, &TestFloat1{})
-		testIdentity(t, &TestFloat2{A: -1254918271.0}, 8, &TestFloat2{})
-		testIdentity(t, &TestFloat3{A: 1241.1, B: 0.2141, C: 20, D: 0.0}, 32, &TestFloat3{})
-	})
-	t.Run("Arrays", func(t *testing.T) {
-		testIdentity(t, &TestArray1{A: [5]int8{1, 77, 2, 4, 5}}, 8, &TestArray1{})
-		testIdentity(t, &TestArray2{A: -1.0, B: [1]float32{0.2}}, 16, &TestArray2{})
-		testIdentity(t, &TestArray3{
-			A: -999,
-			B: [3]uint16{11, 12, 13},
-			C: 1021,
-		}, 24, &TestArray3{})
-		testIdentity(t, &TestArray4{
-			A: [9]bool{true, false, false, true, false, true, true, true, true},
-		}, 16, &TestArray4{})
-	})
-	t.Run("Strings", func(t *testing.T) {
-		testIdentity(t, &TestString1{A: "str", B: nil}, 40, &TestString1{})
-		testIdentity(t, &TestString2{A: [2]string{"hello", "g"}}, 48, &TestString2{})
-		s := "bye"
-		testIdentity(t, &TestString3{
-			A: [2]string{"boop", "g"},
-			B: [2]*string{&s, nil},
-		}, 88, &TestString3{})
-	})
-	t.Run("Vectors", func(t *testing.T) {
-		v1 := []int64{-1}
-		testIdentity(t, &TestVector1{
-			A: []int8{1, 2, 3, 4},
-			B: nil,
-			C: []int32{99},
-			D: &v1,
-		}, 88, &TestVector1{})
-		v2 := []string{"x", "hello"}
-		testIdentity(t, &TestVector2{
-			A: [2][]int8{{9, -1}, {}},
-			B: [][]int8{{-111, 41}, {-1, -1, -1, -1}},
-			C: []*[]string{nil, &v2},
-		}, 200, &TestVector2{})
-	})
-	t.Run("Structs", func(t *testing.T) {
-		testIdentity(t, &TestStruct1{
-			A: TestSimple{
-				X: -9999,
-			},
-			B: &TestSimple{
-				X: 1254125,
-			},
-		}, 24, &TestStruct1{})
-		v1 := []int64{101010}
-		testIdentity(t, &TestStruct2{
-			A: TestArray1{
-				A: [5]int8{1, 77, 2, 4, 5},
-			},
-			B: TestFloat1{
-				A: 2.81212,
-			},
-			C: TestVector1{
-				A: []int8{1, 2, 3, 4},
-				B: nil,
-				C: []int32{99},
-				D: &v1,
-			},
-			D: &TestString1{
-				A: "str",
-				B: nil,
-			},
-		}, 152, &TestStruct2{})
-	})
-	t.Run("Unions", func(t *testing.T) {
-		u1 := Union1{}
-		u1.SetB(TestSimple{X: 555})
-		testIdentity(t, &TestUnion1{
-			A: u1,
-			B: nil,
-		}, 24, &TestUnion1{})
-		testIdentity(t, &TestUnion2{
-			A: []Union1{u1, u1, u1},
-			B: []*Union1{&u1, nil, nil},
-		}, 120, &TestUnion2{})
-	})
-	t.Run("Uninitialized unions", func(t *testing.T) {
-		u1 := Union1{}
-		// Intentionally don't set any members of the union.
-		tu1 := TestUnion1{
-			A: u1,
-			B: nil,
-		}
-		var respb [zx.ChannelMaxMessageBytes]byte
-		var resph [zx.ChannelMaxMessageHandles]zx.Handle
-		_, _, err := Marshal(&tu1, respb[:], resph[:])
-		if err == nil {
-			t.Errorf("got %v when marshalling invalid union but expected ErrInvalidUnionTag", err)
-		}
-	})
-	t.Run("Handles", func(t *testing.T) {
-		vmo, err := zx.NewVMO(10, 0)
-		if err != nil {
-			t.Fatalf("failed to create vmo: %v", err)
-		}
-		testIdentity(t, &TestHandle1{
-			A: zx.Handle(22),
-			B: zx.HandleInvalid,
-			C: vmo,
-			D: zx.VMO(zx.HandleInvalid),
-		}, 16, &TestHandle1{})
-		testIdentity(t, &TestHandle2{
-			A: []zx.Handle{zx.Handle(vmo)},
-			B: []zx.VMO{zx.VMO(zx.HandleInvalid)},
-		}, 48, &TestHandle2{})
-		vmo.Close()
-	})
-	t.Run("Interfaces", func(t *testing.T) {
-		h0, h1, err := zx.NewChannel(0)
-		defer h0.Close()
-		defer h1.Close()
-		if err != nil {
-			t.Fatalf("failed to create vmo: %v", err)
-		}
-		testIdentity(t, &TestInterface1{
-			A: Test1Interface(ChannelProxy{Channel: h0}),
-			B: Test1Interface(ChannelProxy{Channel: zx.Channel(zx.HandleInvalid)}),
-			C: Test1InterfaceRequest(InterfaceRequest{Channel: h1}),
-			D: Test1InterfaceRequest(InterfaceRequest{
-				Channel: zx.Channel(zx.HandleInvalid),
-			}),
-		}, 16, &TestInterface1{})
-	})
-	t.Run("Tables", func(t *testing.T) {
-		st := SimpleTable{}
-		st.SetX(5)
-		st.SetY(7)
-		testIdentity(t, &TestSimpleTable{
-			Table: st,
-		}, 112, &TestSimpleTable{})
-	})
-}
-
-func TestDontPanic(t *testing.T) {
-	for _, tt := range baseErrorCasesUnmarshal {
-		t.Run(tt.name, func(t *testing.T) {
-			defer func() {
-				if r := recover(); r != nil {
-					t.Fatalf("code did panic: %v", r)
-				}
-			}()
-			err := Unmarshal(tt.input, nil, tt.message)
-			validationErr, ok := err.(ValidationError)
-			if !ok {
-				t.Fatalf("expected ValidationError, was %v", err)
-			}
-			if validationErr.Code() != tt.errorCode {
-				t.Fatalf("expected %s, was %s", tt.errorCode, validationErr.Code())
-			}
-		})
-	}
-}
diff --git a/src/syscall/zx/fidl/interface.go b/src/syscall/zx/fidl/interface.go
index 2e83bf3..9ad96b0 100644
--- a/src/syscall/zx/fidl/interface.go
+++ b/src/syscall/zx/fidl/interface.go
@@ -42,6 +42,11 @@
 // Proxy represents the client side of a FIDL interface.
 type Proxy interface {
 	IsValid() bool
+	SendNew(ordinal uint32, req Message) error
+	RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error
+	CallNew(ordinal uint32, req Message, resp Message) error
+
+	// TODO(pascallouis): delete when migration is over
 	Send(ordinal uint32, req Payload) error
 	Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error
 	Call(ordinal uint32, req Payload, resp Payload) error
@@ -59,6 +64,9 @@
 	// It also takes the data as bytes and transforms it into arguments usable by
 	// the method implementation. It then optionally returns a response if the
 	// method has a response.
+	DispatchNew(ordinal uint32, bytes []byte, handles []zx.Handle) (Message, error)
+
+	// TODO(pascallouis): delete post migration.
 	Dispatch(ordinal uint32, bytes []byte, handles []zx.Handle) (Payload, error)
 }
 
@@ -77,9 +85,9 @@
 	return h.IsValid()
 }
 
-// Send sends the request payload over the channel with the specified ordinal
+// Send sends the request over the channel with the specified ordinal
 // without a response.
-func (p *ChannelProxy) Send(ordinal uint32, req Payload) error {
+func (p *ChannelProxy) SendNew(ordinal uint32, req Message) error {
 	respb := messageBytesPool.Get().([]byte)
 	resph := messageHandlesPool.Get().([]zx.Handle)
 
@@ -91,7 +99,7 @@
 		Txid:    0, // Txid == 0 for messages without a response.
 		Ordinal: ordinal,
 	}
-	nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+	nb, nh, err := marshalHeaderThenMessage(&header, req, respb[:], resph[:])
 	if err != nil {
 		return err
 	}
@@ -100,8 +108,8 @@
 	return p.Channel.Write(respb[:nb], resph[:nh], 0)
 }
 
-// Recv waits for an event and writes the response into the response payload.
-func (p *ChannelProxy) Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error {
+// Recv waits for an event and writes the response into the response.
+func (p *ChannelProxy) RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error {
 	respb := messageBytesPool.Get().([]byte)
 	resph := messageHandlesPool.Get().([]zx.Handle)
 
@@ -129,7 +137,7 @@
 
 	// Unmarshal the message.
 	var header MessageHeader
-	if err := UnmarshalMessage(respb[:nb], resph[:nh], &header, resp); err != nil {
+	if err := unmarshalHeaderThenMessage(respb[:nb], resph[:nh], &header, resp); err != nil {
 		return err
 	}
 	// TODO(FIDL-425): Remove temporary handling of two ordinals.
@@ -145,10 +153,10 @@
 	return nil
 }
 
-// Call sends the request payload over the channel with the specified ordinal
+// Call sends the request over the channel with the specified ordinal
 // and synchronously waits for a response. It then writes the response into the
-// response payload.
-func (p *ChannelProxy) Call(ordinal uint32, req Payload, resp Payload) error {
+// response.
+func (p *ChannelProxy) CallNew(ordinal uint32, req Message, resp Message) error {
 	respb := messageBytesPool.Get().([]byte)
 	resph := messageHandlesPool.Get().([]zx.Handle)
 
@@ -159,7 +167,7 @@
 	header := MessageHeader{
 		Ordinal: ordinal,
 	}
-	nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+	nb, nh, err := marshalHeaderThenMessage(&header, req, respb[:], resph[:])
 	if err != nil {
 		return err
 	}
@@ -171,7 +179,7 @@
 	}
 
 	// Unmarshal the message.
-	if err := UnmarshalMessage(respb[:cnb], resph[:cnh], &header, resp); err != nil {
+	if err := unmarshalHeaderThenMessage(respb[:cnb], resph[:cnh], &header, resp); err != nil {
 		return err
 	}
 	if header.Ordinal != ordinal {
@@ -195,9 +203,9 @@
 	return h.IsValid()
 }
 
-// Send sends the request payload over the socket control plane with the
+// Send sends the request over the socket control plane with the
 // specified ordinal without a response.
-func (p *SocketControlProxy) Send(ordinal uint32, req Payload) error {
+func (p *SocketControlProxy) SendNew(ordinal uint32, req Message) error {
 	respb := messageBytesPool.Get().([]byte)
 
 	defer messageBytesPool.Put(respb)
@@ -207,7 +215,7 @@
 		Txid:    0, // Txid == 0 for messages without a response.
 		Ordinal: ordinal,
 	}
-	nb, _, err := MarshalMessage(&header, req, respb[:], nil)
+	nb, _, err := marshalHeaderThenMessage(&header, req, respb[:], nil)
 	if err != nil {
 		return err
 	}
@@ -217,8 +225,8 @@
 	return err
 }
 
-// Recv waits for an event and writes the response into the response payload.
-func (p *SocketControlProxy) Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error {
+// Recv waits for an event and writes the response.
+func (p *SocketControlProxy) RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error {
 	respb := messageBytesPool.Get().([]byte)
 
 	defer messageBytesPool.Put(respb)
@@ -244,7 +252,7 @@
 
 	// Unmarshal the message.
 	var header MessageHeader
-	if err := UnmarshalMessage(respb[:nb], nil, &header, resp); err != nil {
+	if err := unmarshalHeaderThenMessage(respb[:nb], nil, &header, resp); err != nil {
 		return err
 	}
 	// TODO(FIDL-425): Remove temporary handling of two ordinals.
@@ -260,14 +268,13 @@
 	return nil
 }
 
-// Call sends the request payload over the socket control plane with the specified
-// ordinal and waits for a response. It then writes the response into the response
-// payload.
-func (p *SocketControlProxy) Call(ordinal uint32, req Payload, resp Payload) error {
-	if err := p.Send(ordinal, req); err != nil {
+// Call sends the request over the socket control plane with the specified
+// ordinal and waits for a response. It then writes the response into the response.
+func (p *SocketControlProxy) CallNew(ordinal uint32, req Message, resp Message) error {
+	if err := p.SendNew(ordinal, req); err != nil {
 		return err
 	}
-	if err := p.Recv(ordinal, resp); err != nil {
+	if err := p.RecvNew(ordinal, resp); err != nil {
 		return err
 	}
 	return nil
diff --git a/src/syscall/zx/fidl/message.go b/src/syscall/zx/fidl/message.go
index f4f16c0..3931b90 100644
--- a/src/syscall/zx/fidl/message.go
+++ b/src/syscall/zx/fidl/message.go
@@ -28,49 +28,44 @@
 	},
 }
 
-// MessageHeaderSize is the size of the encoded message header.
-const MessageHeaderSize int = 16
-
-// MessageHeader is a header information for a message. This struct
-// corresponds to the C type fidl_message_header_t.
+// MessageHeader represents a transactional message header.
 type MessageHeader struct {
+	_        struct{} `fidl2:"s,16,4"`
 	Txid     uint32
 	Reserved uint32
 	Flags    uint32
 	Ordinal  uint32
 }
 
-// Payload is an interface implemented by every FIDL structure.
-type Payload interface {
-	// InlineSize returns the inline size of the structure, without any
-	// out-of-line structures.
-	InlineSize() int
+var mMessageHeader = MustCreateMarshaler(MessageHeader{})
 
-	// InlineAlignment returns the alignment of the structure.
-	InlineAlignment() int
+func (msg *MessageHeader) Marshaler() Marshaler {
+	return mMessageHeader
 }
 
-// MarshalMessage is a convenience function for marshalling a full FIDL message,
-// that is, header and payload.
-func MarshalMessage(header *MessageHeader, s Payload, data []byte, handles []zx.Handle) (int, int, error) {
-	MarshalHeader(header, data[:MessageHeaderSize])
-	if s == nil {
+func marshalHeaderThenMessage(header *MessageHeader, msg Message, data []byte, handles []zx.Handle) (int, int, error) {
+	if _, _, err := MarshalNew(header, data[:MessageHeaderSize], nil); err != nil {
+		return 0, 0, err
+	}
+	if msg == nil {
 		return MessageHeaderSize, 0, nil
 	}
-	// TODO(pascallouis): switch to MarshalNew when ready.
-	nb, nh, err := Marshal(s, data[MessageHeaderSize:], handles[:])
-	return nb + MessageHeaderSize, nh, err
+	nb, nh, err := MarshalNew(msg, data[MessageHeaderSize:], handles[:])
+	if err != nil {
+		return 0, 0, err
+	}
+	return nb + MessageHeaderSize, nh, nil
 }
 
-// UnmarshalMessage is a convenience function for unmarshalling a full FIDL message,
-// that is, header and payload.
-func UnmarshalMessage(data []byte, handles []zx.Handle, header *MessageHeader, s Payload) error {
-	if err := UnmarshalHeader(data[:MessageHeaderSize], header); err != nil {
+func unmarshalHeaderThenMessage(data []byte, handles []zx.Handle, header *MessageHeader, msg Message) error {
+	if _, _, err := UnmarshalNew(data[:MessageHeaderSize], nil, header); err != nil {
 		return err
 	}
-	if s == nil {
+	if msg == nil {
 		return nil
 	}
-	// TODO(pascallouis): switch to MarshalNew when ready.
-	return Unmarshal(data[MessageHeaderSize:], handles[:], s)
+	if _, _, err := UnmarshalNew(data[MessageHeaderSize:], handles[:], msg); err != nil {
+		return err
+	}
+	return nil
 }