reflect/protoreflect: add alternative message reflection API

Added API:
	Message.Len
	Message.Range
	Message.Has
	Message.Clear
	Message.Get
	Message.Set
	Message.Mutable
	Message.NewMessage
	Message.WhichOneof
	Message.GetUnknown
	Message.SetUnknown

Deprecated API (to be removed in subsequent CL):
	Message.KnownFields
	Message.UnknownFields

The primary difference with the new API is that the top-level
Message methods are keyed by FieldDescriptor rather than FieldNumber
with the following semantics:
* For known fields, the FieldDescriptor must exactly match the
field descriptor known by the message.
* For extension fields, the FieldDescriptor must implement ExtensionType,
where ContainingMessage.FullName matches the message name, and
the field number is within the message's extension range.
When setting an extension field, it automatically stores
the extension type information.
* Extension fields are always considered nullable,
implying that repeated extension fields are nullable.
That is, you can distinguish between a unpopulated list and an empty list.
* Message.Get always returns a valid Value even if unpopulated.
The behavior is already well-defined for scalars, but for unpopulated
composite types, it now returns an empty read-only version of it.

Change-Id: Ia120630b4db221aeaaf743d0f64160e1a61a0f61
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/175458
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index c1ba55e..583ff33 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -5,19 +5,16 @@
 package impl_test
 
 import (
-	"bytes"
-	"math"
 	"reflect"
 	"sync"
 	"testing"
 
-	cmp "github.com/google/go-cmp/cmp"
-	cmpopts "github.com/google/go-cmp/cmp/cmpopts"
-	pack "google.golang.org/protobuf/internal/encoding/pack"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
 	pimpl "google.golang.org/protobuf/internal/impl"
 	pragma "google.golang.org/protobuf/internal/pragma"
 	ptype "google.golang.org/protobuf/internal/prototype"
-	scalar "google.golang.org/protobuf/internal/scalar"
+	"google.golang.org/protobuf/internal/scalar"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
 	piface "google.golang.org/protobuf/runtime/protoiface"
@@ -42,136 +39,6 @@
 	preg.GlobalTypes.Register(mt)
 }
 
-func TestLegacyUnknown(t *testing.T) {
-	rawOf := func(toks ...pack.Token) pref.RawFields {
-		return pref.RawFields(pack.Message(toks).Marshal())
-	}
-	raw1 := rawOf(pack.Tag{1, pack.BytesType}, pack.Bytes("1"))                      // 0a0131
-	raw1a := rawOf(pack.Tag{1, pack.VarintType}, pack.Svarint(-4321))                // 08c143
-	raw1b := rawOf(pack.Tag{1, pack.Fixed32Type}, pack.Uint32(0xdeadbeef))           // 0defbeadde
-	raw1c := rawOf(pack.Tag{1, pack.Fixed64Type}, pack.Float64(math.Pi))             // 09182d4454fb210940
-	raw2a := rawOf(pack.Tag{2, pack.BytesType}, pack.String("hello, world!"))        // 120d68656c6c6f2c20776f726c6421
-	raw2b := rawOf(pack.Tag{2, pack.VarintType}, pack.Uvarint(1234))                 // 10d209
-	raw3a := rawOf(pack.Tag{3, pack.StartGroupType}, pack.Tag{3, pack.EndGroupType}) // 1b1c
-	raw3b := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("\xde\xad\xbe\xef"))      // 1a04deadbeef
-
-	joinRaw := func(bs ...pref.RawFields) (out []byte) {
-		for _, b := range bs {
-			out = append(out, b...)
-		}
-		return out
-	}
-
-	m := new(legacyTestMessage)
-	fs := pimpl.Export{}.MessageOf(m).UnknownFields()
-
-	if got, want := fs.Len(), 0; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	fs.Set(1, raw1a)
-	fs.Set(1, append(fs.Get(1), raw1b...))
-	fs.Set(1, append(fs.Get(1), raw1c...))
-	if got, want := fs.Len(), 1; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	fs.Set(2, raw2a)
-	if got, want := fs.Len(), 2; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c, raw2a); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	if got, want := fs.Get(1), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
-		t.Errorf("Get(%d) = %x, want %x", 1, got, want)
-	}
-	if got, want := fs.Get(2), joinRaw(raw2a); !bytes.Equal(got, want) {
-		t.Errorf("Get(%d) = %x, want %x", 2, got, want)
-	}
-	if got, want := fs.Get(3), joinRaw(); !bytes.Equal(got, want) {
-		t.Errorf("Get(%d) = %x, want %x", 3, got, want)
-	}
-
-	fs.Set(1, nil) // remove field 1
-	if got, want := fs.Len(), 1; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw2a); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	// Simulate manual appending of raw field data.
-	m.XXX_unrecognized = append(m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw2b, raw3b, raw1c)...)
-	if got, want := fs.Len(), 3; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-
-	// Verify range iteration order.
-	var i int
-	want := []struct {
-		num pref.FieldNumber
-		raw pref.RawFields
-	}{
-		{2, joinRaw(raw2a, raw2b)},
-		{3, joinRaw(raw3a, raw3b)},
-		{1, joinRaw(raw1a, raw1b, raw1c)},
-	}
-	fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
-		if i < len(want) {
-			if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
-				t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
-			}
-		} else {
-			t.Errorf("unexpected Range iteration: %d", i)
-		}
-		i++
-		return true
-	})
-
-	fs.Set(2, fs.Get(2)) // moves field 2 to the end
-	if got, want := fs.Len(), 3; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw3b, raw1c, raw2a, raw2b); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-	fs.Set(1, nil) // remove field 1
-	if got, want := fs.Len(), 2; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw3b, raw2a, raw2b); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	// Remove all fields.
-	fs.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
-		fs.Set(n, nil)
-		return true
-	})
-	if got, want := fs.Len(), 0; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-
-	fs.Set(1, raw1)
-	if got, want := fs.Len(), 1; got != want {
-		t.Errorf("Len() = %d, want %d", got, want)
-	}
-	if got, want := m.XXX_unrecognized, joinRaw(raw1); !bytes.Equal(got, want) {
-		t.Errorf("data mismatch:\ngot:  %x\nwant: %x", got, want)
-	}
-}
-
 var (
 	testParentDesc    = pimpl.Export{}.MessageDescriptorOf((*legacyTestMessage)(nil))
 	testEnumV1Desc    = pimpl.Export{}.EnumDescriptorOf(proto2_20180125.Message_ChildEnum(0))
@@ -466,63 +333,41 @@
 		return x == y // pointer compare messages for object identity
 	})}
 
-	m := new(legacyTestMessage)
-	fs := pimpl.Export{}.MessageOf(m).KnownFields()
-	ts := fs.ExtensionTypes()
+	m := pimpl.Export{}.MessageOf(new(legacyTestMessage))
 
-	if n := fs.Len(); n != 0 {
+	if n := m.Len(); n != 0 {
 		t.Errorf("KnownFields.Len() = %v, want 0", n)
 	}
-	if n := ts.Len(); n != 0 {
-		t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
-	}
-
-	// Register all the extension types.
-	for _, xt := range extensionTypes {
-		ts.Register(xt)
-	}
 
 	// Check that getting the zero value returns the default value for scalars,
 	// nil for singular messages, and an empty list for repeated fields.
-	defaultValues := []interface{}{
-		bool(true),
-		int32(-12345),
-		uint32(3200),
-		float32(3.14159),
-		string("hello, \"world!\"\n"),
-		[]byte("dead\xde\xad\xbe\xefbeef"),
-		proto2_20180125.Message_ALPHA,
-		nil,
-		EnumProto2(0xdead),
-		nil,
-		new([]bool),
-		new([]int32),
-		new([]uint32),
-		new([]float32),
-		new([]string),
-		new([][]byte),
-		new([]proto2_20180125.Message_ChildEnum),
-		new([]*proto2_20180125.Message_ChildMessage),
-		new([]EnumProto2),
-		new([]*EnumMessages),
+	defaultValues := map[int]interface{}{
+		0: bool(true),
+		1: int32(-12345),
+		2: uint32(3200),
+		3: float32(3.14159),
+		4: string("hello, \"world!\"\n"),
+		5: []byte("dead\xde\xad\xbe\xefbeef"),
+		6: proto2_20180125.Message_ALPHA,
+		7: nil,
+		8: EnumProto2(0xdead),
+		9: nil,
 	}
 	for i, xt := range extensionTypes {
 		var got interface{}
-		num := xt.Descriptor().Number()
-		if v := fs.Get(num); v.IsValid() {
-			got = xt.InterfaceOf(v)
+		if !(xt.IsList() || xt.IsMap() || xt.Message() != nil) {
+			got = xt.InterfaceOf(m.Get(xt))
 		}
 		want := defaultValues[i]
 		if diff := cmp.Diff(want, got, opts); diff != "" {
-			t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", num, diff)
+			t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
 		}
 	}
 
 	// All fields should be unpopulated.
 	for _, xt := range extensionTypes {
-		num := xt.Descriptor().Number()
-		if fs.Has(num) {
-			t.Errorf("KnownFields.Has(%d) = true, want false", num)
+		if m.Has(xt) {
+			t.Errorf("Message.Has(%d) = true, want false", xt.Number())
 		}
 	}
 
@@ -531,102 +376,88 @@
 	m1b := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m2b")}
 	m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()}
 	m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()}
-	setValues := []interface{}{
-		bool(false),
-		int32(-54321),
-		uint32(6400),
-		float32(2.71828),
-		string("goodbye, \"world!\"\n"),
-		[]byte("live\xde\xad\xbe\xefchicken"),
-		proto2_20180125.Message_CHARLIE,
-		m1a,
-		EnumProto2(0xbeef),
-		m2a,
-		&[]bool{true},
-		&[]int32{-1000},
-		&[]uint32{1280},
-		&[]float32{1.6180},
-		&[]string{"zero"},
-		&[][]byte{[]byte("zero")},
-		&[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
-		&[]*proto2_20180125.Message_ChildMessage{m1b},
-		&[]EnumProto2{0xdead},
-		&[]*EnumMessages{m2b},
+	setValues := map[int]interface{}{
+		0:  bool(false),
+		1:  int32(-54321),
+		2:  uint32(6400),
+		3:  float32(2.71828),
+		4:  string("goodbye, \"world!\"\n"),
+		5:  []byte("live\xde\xad\xbe\xefchicken"),
+		6:  proto2_20180125.Message_CHARLIE,
+		7:  m1a,
+		8:  EnumProto2(0xbeef),
+		9:  m2a,
+		10: &[]bool{true},
+		11: &[]int32{-1000},
+		12: &[]uint32{1280},
+		13: &[]float32{1.6180},
+		14: &[]string{"zero"},
+		15: &[][]byte{[]byte("zero")},
+		16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
+		17: &[]*proto2_20180125.Message_ChildMessage{m1b},
+		18: &[]EnumProto2{0xdead},
+		19: &[]*EnumMessages{m2b},
 	}
 	for i, xt := range extensionTypes {
-		fs.Set(xt.Descriptor().Number(), xt.ValueOf(setValues[i]))
+		m.Set(xt, xt.ValueOf(setValues[i]))
 	}
 	for i, xt := range extensionTypes[len(extensionTypes)/2:] {
 		v := extensionTypes[i].ValueOf(setValues[i])
-		fs.Get(xt.Descriptor().Number()).List().Append(v)
+		m.Get(xt).List().Append(v)
 	}
 
 	// Get the values and check for equality.
-	getValues := []interface{}{
-		bool(false),
-		int32(-54321),
-		uint32(6400),
-		float32(2.71828),
-		string("goodbye, \"world!\"\n"),
-		[]byte("live\xde\xad\xbe\xefchicken"),
-		proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
-		m1a,
-		EnumProto2(0xbeef),
-		m2a,
-		&[]bool{true, false},
-		&[]int32{-1000, -54321},
-		&[]uint32{1280, 6400},
-		&[]float32{1.6180, 2.71828},
-		&[]string{"zero", "goodbye, \"world!\"\n"},
-		&[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
-		&[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
-		&[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
-		&[]EnumProto2{0xdead, 0xbeef},
-		&[]*EnumMessages{m2b, m2a},
+	getValues := map[int]interface{}{
+		0:  bool(false),
+		1:  int32(-54321),
+		2:  uint32(6400),
+		3:  float32(2.71828),
+		4:  string("goodbye, \"world!\"\n"),
+		5:  []byte("live\xde\xad\xbe\xefchicken"),
+		6:  proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
+		7:  m1a,
+		8:  EnumProto2(0xbeef),
+		9:  m2a,
+		10: &[]bool{true, false},
+		11: &[]int32{-1000, -54321},
+		12: &[]uint32{1280, 6400},
+		13: &[]float32{1.6180, 2.71828},
+		14: &[]string{"zero", "goodbye, \"world!\"\n"},
+		15: &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
+		16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
+		17: &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
+		18: &[]EnumProto2{0xdead, 0xbeef},
+		19: &[]*EnumMessages{m2b, m2a},
 	}
 	for i, xt := range extensionTypes {
-		num := xt.Descriptor().Number()
-		got := xt.InterfaceOf(fs.Get(num))
+		got := xt.InterfaceOf(m.Get(xt))
 		want := getValues[i]
 		if diff := cmp.Diff(want, got, opts); diff != "" {
-			t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", num, diff)
+			t.Errorf("Message.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
 		}
 	}
 
-	if n := fs.Len(); n != 20 {
-		t.Errorf("KnownFields.Len() = %v, want 0", n)
-	}
-	if n := ts.Len(); n != 20 {
-		t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
+	if n := m.Len(); n != 20 {
+		t.Errorf("Message.Len() = %v, want 0", n)
 	}
 
-	// Clear the field for all extension types.
+	// Clear all singular fields and truncate all repeated fields.
 	for _, xt := range extensionTypes[:len(extensionTypes)/2] {
-		fs.Clear(xt.Descriptor().Number())
+		m.Clear(xt)
 	}
-	for i, xt := range extensionTypes[len(extensionTypes)/2:] {
-		if i%2 == 0 {
-			fs.Clear(xt.Descriptor().Number())
-		} else {
-			fs.Get(xt.Descriptor().Number()).List().Truncate(0)
-		}
+	for _, xt := range extensionTypes[len(extensionTypes)/2:] {
+		m.Get(xt).List().Truncate(0)
 	}
-	if n := fs.Len(); n != 0 {
-		t.Errorf("KnownFields.Len() = %v, want 0", n)
-	}
-	if n := ts.Len(); n != 20 {
-		t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
+	if n := m.Len(); n != 10 {
+		t.Errorf("Message.Len() = %v, want 10", n)
 	}
 
-	// De-register all extension types.
-	for _, xt := range extensionTypes {
-		ts.Remove(xt)
+	// Clear all repeated fields.
+	for _, xt := range extensionTypes[len(extensionTypes)/2:] {
+		m.Clear(xt)
 	}
-	if n := fs.Len(); n != 0 {
-		t.Errorf("KnownFields.Len() = %v, want 0", n)
-	}
-	if n := ts.Len(); n != 0 {
-		t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
+	if n := m.Len(); n != 0 {
+		t.Errorf("Message.Len() = %v, want 0", n)
 	}
 }
 
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 6db60f1..c416440 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -40,12 +40,17 @@
 
 	oneofs map[pref.Name]*oneofInfo
 
+	getUnknown func(pointer) pref.RawFields
+	setUnknown func(pointer, pref.RawFields)
+
+	extensionMap func(pointer) *extensionMap
+
 	unknownFields   func(*messageDataType) pref.UnknownFields
 	extensionFields func(*messageDataType) pref.KnownFields
 	methods         piface.Methods
 
-	extensionOffset       offset
 	sizecacheOffset       offset
+	extensionOffset       offset
 	unknownOffset         offset
 	extensionFieldInfosMu sync.RWMutex
 	extensionFieldInfos   map[pref.ExtensionType]*extensionFieldInfo
@@ -106,23 +111,33 @@
 	atomic.StoreUint32(&mi.initDone, 1)
 }
 
-var sizecacheType = reflect.TypeOf(int32(0))
+type (
+	SizeCache       = int32
+	UnknownFields   = []byte
+	ExtensionFields = map[int32]ExtensionField
+)
+
+var (
+	sizecacheType       = reflect.TypeOf(SizeCache(0))
+	unknownFieldsType   = reflect.TypeOf(UnknownFields(nil))
+	extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
+)
 
 func (mi *MessageInfo) makeMethods(t reflect.Type) {
-	mi.extensionOffset = invalidOffset
-	if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extType {
-		mi.extensionOffset = offsetOf(fx)
-	} else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extType {
-		mi.extensionOffset = offsetOf(fx)
-	}
 	mi.sizecacheOffset = invalidOffset
 	if fx, _ := t.FieldByName("XXX_sizecache"); fx.Type == sizecacheType {
 		mi.sizecacheOffset = offsetOf(fx)
 	}
 	mi.unknownOffset = invalidOffset
-	if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == bytesType {
+	if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == unknownFieldsType {
 		mi.unknownOffset = offsetOf(fx)
 	}
+	mi.extensionOffset = invalidOffset
+	if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extensionFieldsType {
+		mi.extensionOffset = offsetOf(fx)
+	} else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extensionFieldsType {
+		mi.extensionOffset = offsetOf(fx)
+	}
 	mi.methods.Flags = piface.MethodFlagDeterministicMarshal
 	mi.methods.MarshalAppend = mi.marshalAppend
 	mi.methods.Size = mi.size
@@ -231,22 +246,56 @@
 }
 
 func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type) {
-	if f := makeLegacyUnknownFieldsFunc(t); f != nil {
-		mi.unknownFields = f
-		return
-	}
-	mi.unknownFields = func(*messageDataType) pref.UnknownFields {
-		return emptyUnknownFields{}
+	mi.unknownFields = makeLegacyUnknownFieldsFunc(t)
+
+	mi.getUnknown = func(pointer) pref.RawFields { return nil }
+	mi.setUnknown = func(pointer, pref.RawFields) { return }
+	fu, _ := t.FieldByName("XXX_unrecognized")
+	if fu.Type == unknownFieldsType {
+		fieldOffset := offsetOf(fu)
+		mi.getUnknown = func(p pointer) pref.RawFields {
+			if p.IsNil() {
+				return nil
+			}
+			rv := p.Apply(fieldOffset).AsValueOf(unknownFieldsType)
+			return pref.RawFields(*rv.Interface().(*[]byte))
+		}
+		mi.setUnknown = func(p pointer, b pref.RawFields) {
+			if p.IsNil() {
+				panic("invalid SetUnknown on nil Message")
+			}
+			rv := p.Apply(fieldOffset).AsValueOf(unknownFieldsType)
+			*rv.Interface().(*[]byte) = []byte(b)
+		}
+	} else {
+		mi.getUnknown = func(pointer) pref.RawFields {
+			return nil
+		}
+		mi.setUnknown = func(p pointer, _ pref.RawFields) {
+			if p.IsNil() {
+				panic("invalid SetUnknown on nil Message")
+			}
+		}
 	}
 }
 
 func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type) {
-	if f := makeLegacyExtensionFieldsFunc(t); f != nil {
-		mi.extensionFields = f
-		return
+	mi.extensionFields = makeLegacyExtensionFieldsFunc(t)
+
+	fx, _ := t.FieldByName("XXX_extensions")
+	if fx.Type != extensionFieldsType {
+		fx, _ = t.FieldByName("XXX_InternalExtensions")
 	}
-	mi.extensionFields = func(*messageDataType) pref.KnownFields {
-		return emptyExtensionFields{}
+	if fx.Type == extensionFieldsType {
+		fieldOffset := offsetOf(fx)
+		mi.extensionMap = func(p pointer) *extensionMap {
+			v := p.Apply(fieldOffset).AsValueOf(extensionFieldsType)
+			return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
+		}
+	} else {
+		mi.extensionMap = func(pointer) *extensionMap {
+			return (*extensionMap)(nil)
+		}
 	}
 }
 
@@ -295,21 +344,9 @@
 
 type messageReflectWrapper messageDataType
 
-// TODO: Remove this.
-func (m *messageReflectWrapper) Type() pref.MessageType {
-	return m.mi.PBType
-}
 func (m *messageReflectWrapper) Descriptor() pref.MessageDescriptor {
 	return m.mi.PBType.Descriptor()
 }
-func (m *messageReflectWrapper) KnownFields() pref.KnownFields {
-	m.mi.init()
-	return (*knownFields)(m)
-}
-func (m *messageReflectWrapper) UnknownFields() pref.UnknownFields {
-	m.mi.init()
-	return m.mi.unknownFields((*messageDataType)(m))
-}
 func (m *messageReflectWrapper) New() pref.Message {
 	return m.mi.PBType.New()
 }
@@ -323,6 +360,170 @@
 	return m.p.AsIfaceOf(m.mi.GoType.Elem())
 }
 
+func (m *messageReflectWrapper) Len() (cnt int) {
+	m.mi.init()
+	for _, fi := range m.mi.fields {
+		if fi.has(m.p) {
+			cnt++
+		}
+	}
+	return cnt + m.mi.extensionMap(m.p).Len()
+}
+func (m *messageReflectWrapper) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
+	m.mi.init()
+	for _, fi := range m.mi.fields {
+		if fi.has(m.p) {
+			if !f(fi.fieldDesc, fi.get(m.p)) {
+				return
+			}
+		}
+	}
+	m.mi.extensionMap(m.p).Range(f)
+}
+func (m *messageReflectWrapper) Has(fd pref.FieldDescriptor) bool {
+	if fi, xt := m.checkField(fd); fi != nil {
+		return fi.has(m.p)
+	} else {
+		return m.mi.extensionMap(m.p).Has(xt)
+	}
+}
+func (m *messageReflectWrapper) Clear(fd pref.FieldDescriptor) {
+	if fi, xt := m.checkField(fd); fi != nil {
+		fi.clear(m.p)
+	} else {
+		m.mi.extensionMap(m.p).Clear(xt)
+	}
+}
+func (m *messageReflectWrapper) Get(fd pref.FieldDescriptor) pref.Value {
+	if fi, xt := m.checkField(fd); fi != nil {
+		return fi.get(m.p)
+	} else {
+		return m.mi.extensionMap(m.p).Get(xt)
+	}
+}
+func (m *messageReflectWrapper) Set(fd pref.FieldDescriptor, v pref.Value) {
+	if fi, xt := m.checkField(fd); fi != nil {
+		fi.set(m.p, v)
+	} else {
+		m.mi.extensionMap(m.p).Set(xt, v)
+	}
+}
+func (m *messageReflectWrapper) Mutable(fd pref.FieldDescriptor) pref.Value {
+	if fi, xt := m.checkField(fd); fi != nil {
+		return fi.mutable(m.p)
+	} else {
+		return m.mi.extensionMap(m.p).Mutable(xt)
+	}
+}
+func (m *messageReflectWrapper) NewMessage(fd pref.FieldDescriptor) pref.Message {
+	if fi, xt := m.checkField(fd); fi != nil {
+		return fi.newMessage()
+	} else {
+		return xt.New().Message()
+	}
+}
+func (m *messageReflectWrapper) WhichOneof(od pref.OneofDescriptor) pref.FieldDescriptor {
+	m.mi.init()
+	if oi := m.mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od {
+		return od.Fields().ByNumber(oi.which(m.p))
+	}
+	panic("invalid oneof descriptor")
+}
+func (m *messageReflectWrapper) GetUnknown() pref.RawFields {
+	m.mi.init()
+	return m.mi.getUnknown(m.p)
+}
+func (m *messageReflectWrapper) SetUnknown(b pref.RawFields) {
+	m.mi.init()
+	m.mi.setUnknown(m.p, b)
+}
+
+// checkField verifies that the provided field descriptor is valid.
+// Exactly one of the returned values is populated.
+func (m *messageReflectWrapper) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
+	m.mi.init()
+	if fi := m.mi.fields[fd.Number()]; fi != nil {
+		if fi.fieldDesc != fd {
+			panic("mismatching field descriptor")
+		}
+		return fi, nil
+	}
+	if fd.IsExtension() {
+		if fd.ContainingMessage().FullName() != m.mi.PBType.FullName() {
+			// TODO: Should this be exact containing message descriptor match?
+			panic("mismatching containing message")
+		}
+		if !m.mi.PBType.ExtensionRanges().Has(fd.Number()) {
+			panic("invalid extension field")
+		}
+		return nil, fd.(pref.ExtensionType)
+	}
+	panic("invalid field descriptor")
+}
+
+type extensionMap map[int32]ExtensionField
+
+func (m *extensionMap) Len() int {
+	if m != nil {
+		return len(*m)
+	}
+	return 0
+}
+func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
+	if m != nil {
+		for _, x := range *m {
+			xt := x.GetType()
+			if !f(xt, xt.ValueOf(x.GetValue())) {
+				return
+			}
+		}
+	}
+}
+func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
+	if m != nil {
+		_, ok = (*m)[int32(xt.Number())]
+	}
+	return ok
+}
+func (m *extensionMap) Clear(xt pref.ExtensionType) {
+	delete(*m, int32(xt.Number()))
+}
+func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
+	if m != nil {
+		if x, ok := (*m)[int32(xt.Number())]; ok {
+			return xt.ValueOf(x.GetValue())
+		}
+	}
+	if !isComposite(xt) {
+		return defaultValueOf(xt)
+	}
+	return frozenValueOf(xt.New())
+}
+func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
+	if *m == nil {
+		*m = make(map[int32]ExtensionField)
+	}
+	var x ExtensionField
+	x.SetType(xt)
+	x.SetEagerValue(xt.InterfaceOf(v))
+	(*m)[int32(xt.Number())] = x
+}
+func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
+	if !isComposite(xt) {
+		panic("invalid Mutable on field with non-composite type")
+	}
+	if x, ok := (*m)[int32(xt.Number())]; ok {
+		return xt.ValueOf(x.GetValue())
+	}
+	v := xt.New()
+	m.Set(xt, v)
+	return v
+}
+
+func isComposite(fd pref.FieldDescriptor) bool {
+	return fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind || fd.IsList() || fd.IsMap()
+}
+
 var _ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
 
 type messageIfaceWrapper messageDataType
@@ -348,109 +549,3 @@
 func (m *messageIfaceWrapper) size(msg pref.ProtoMessage) (size int) {
 	return m.mi.sizePointer(m.p, 0)
 }
-
-type knownFields messageDataType
-
-func (fs *knownFields) Len() (cnt int) {
-	for _, fi := range fs.mi.fields {
-		if fi.has(fs.p) {
-			cnt++
-		}
-	}
-	return cnt + fs.extensionFields().Len()
-}
-func (fs *knownFields) Has(n pref.FieldNumber) bool {
-	if fi := fs.mi.fields[n]; fi != nil {
-		return fi.has(fs.p)
-	}
-	return fs.extensionFields().Has(n)
-}
-func (fs *knownFields) Get(n pref.FieldNumber) pref.Value {
-	if fi := fs.mi.fields[n]; fi != nil {
-		return fi.get(fs.p)
-	}
-	return fs.extensionFields().Get(n)
-}
-func (fs *knownFields) Set(n pref.FieldNumber, v pref.Value) {
-	if fi := fs.mi.fields[n]; fi != nil {
-		fi.set(fs.p, v)
-		return
-	}
-	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
-		fs.extensionFields().Set(n, v)
-		return
-	}
-	panic(fmt.Sprintf("invalid field: %d", n))
-}
-func (fs *knownFields) Clear(n pref.FieldNumber) {
-	if fi := fs.mi.fields[n]; fi != nil {
-		fi.clear(fs.p)
-		return
-	}
-	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
-		fs.extensionFields().Clear(n)
-		return
-	}
-}
-func (fs *knownFields) WhichOneof(s pref.Name) pref.FieldNumber {
-	if oi := fs.mi.oneofs[s]; oi != nil {
-		return oi.which(fs.p)
-	}
-	return 0
-}
-func (fs *knownFields) Range(f func(pref.FieldNumber, pref.Value) bool) {
-	for n, fi := range fs.mi.fields {
-		if fi.has(fs.p) {
-			if !f(n, fi.get(fs.p)) {
-				return
-			}
-		}
-	}
-	fs.extensionFields().Range(f)
-}
-func (fs *knownFields) NewMessage(n pref.FieldNumber) pref.Message {
-	if fi := fs.mi.fields[n]; fi != nil {
-		return fi.newMessage()
-	}
-	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
-		return fs.extensionFields().NewMessage(n)
-	}
-	panic(fmt.Sprintf("invalid field: %d", n))
-}
-func (fs *knownFields) ExtensionTypes() pref.ExtensionFieldTypes {
-	return fs.extensionFields().ExtensionTypes()
-}
-func (fs *knownFields) extensionFields() pref.KnownFields {
-	return fs.mi.extensionFields((*messageDataType)(fs))
-}
-
-type emptyUnknownFields struct{}
-
-func (emptyUnknownFields) Len() int                                          { return 0 }
-func (emptyUnknownFields) Get(pref.FieldNumber) pref.RawFields               { return nil }
-func (emptyUnknownFields) Set(pref.FieldNumber, pref.RawFields)              { return } // noop
-func (emptyUnknownFields) Range(func(pref.FieldNumber, pref.RawFields) bool) { return }
-func (emptyUnknownFields) IsSupported() bool                                 { return false }
-
-type emptyExtensionFields struct{}
-
-func (emptyExtensionFields) Len() int                                      { return 0 }
-func (emptyExtensionFields) Has(pref.FieldNumber) bool                     { return false }
-func (emptyExtensionFields) Get(pref.FieldNumber) pref.Value               { return pref.Value{} }
-func (emptyExtensionFields) Set(pref.FieldNumber, pref.Value)              { panic("extensions not supported") }
-func (emptyExtensionFields) Clear(pref.FieldNumber)                        { return } // noop
-func (emptyExtensionFields) WhichOneof(pref.Name) pref.FieldNumber         { return 0 }
-func (emptyExtensionFields) Range(func(pref.FieldNumber, pref.Value) bool) { return }
-func (emptyExtensionFields) NewMessage(pref.FieldNumber) pref.Message {
-	panic("extensions not supported")
-}
-func (emptyExtensionFields) ExtensionTypes() pref.ExtensionFieldTypes { return emptyExtensionTypes{} }
-
-type emptyExtensionTypes struct{}
-
-func (emptyExtensionTypes) Len() int                                     { return 0 }
-func (emptyExtensionTypes) Register(pref.ExtensionType)                  { panic("extensions not supported") }
-func (emptyExtensionTypes) Remove(pref.ExtensionType)                    { return } // noop
-func (emptyExtensionTypes) ByNumber(pref.FieldNumber) pref.ExtensionType { return nil }
-func (emptyExtensionTypes) ByName(pref.FullName) pref.ExtensionType      { return nil }
-func (emptyExtensionTypes) Range(func(pref.ExtensionType) bool)          { return }
diff --git a/internal/impl/message_deprecated.go b/internal/impl/message_deprecated.go
new file mode 100644
index 0000000..7391c1b
--- /dev/null
+++ b/internal/impl/message_deprecated.go
@@ -0,0 +1,148 @@
+// 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.
+
+package impl
+
+import (
+	"fmt"
+
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// TODO: Remove this file.
+
+// TODO: Remove this.
+func (m *messageReflectWrapper) Type() pref.MessageType {
+	return m.mi.PBType
+}
+
+// TODO: Remove this.
+func (m *messageReflectWrapper) KnownFields() pref.KnownFields {
+	m.mi.init()
+	return (*knownFields)(m)
+}
+
+// TODO: Remove this.
+func (m *messageReflectWrapper) UnknownFields() pref.UnknownFields {
+	m.mi.init()
+	return m.mi.unknownFields((*messageDataType)(m))
+}
+
+// TODO: Remove this.
+type knownFields messageDataType
+
+func (fs *knownFields) Len() (cnt int) {
+	for _, fi := range fs.mi.fields {
+		if fi.has(fs.p) {
+			cnt++
+		}
+	}
+	return cnt + fs.extensionFields().Len()
+}
+func (fs *knownFields) Has(n pref.FieldNumber) bool {
+	if fi := fs.mi.fields[n]; fi != nil {
+		return fi.has(fs.p)
+	}
+	return fs.extensionFields().Has(n)
+}
+func (fs *knownFields) Get(n pref.FieldNumber) pref.Value {
+	if fi := fs.mi.fields[n]; fi != nil {
+		if !fi.has(fs.p) && isComposite(fi.fieldDesc) {
+			if fi.newMessage != nil {
+				return pref.Value{}
+			}
+			if !fs.p.IsNil() {
+				return fi.mutable(fs.p)
+			}
+		}
+		return fi.get(fs.p)
+	}
+	return fs.extensionFields().Get(n)
+}
+func (fs *knownFields) Set(n pref.FieldNumber, v pref.Value) {
+	if fi := fs.mi.fields[n]; fi != nil {
+		fi.set(fs.p, v)
+		return
+	}
+	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
+		fs.extensionFields().Set(n, v)
+		return
+	}
+	panic(fmt.Sprintf("invalid field: %d", n))
+}
+func (fs *knownFields) Clear(n pref.FieldNumber) {
+	if fi := fs.mi.fields[n]; fi != nil {
+		fi.clear(fs.p)
+		return
+	}
+	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
+		fs.extensionFields().Clear(n)
+		return
+	}
+}
+func (fs *knownFields) WhichOneof(s pref.Name) pref.FieldNumber {
+	if oi := fs.mi.oneofs[s]; oi != nil {
+		return oi.which(fs.p)
+	}
+	return 0
+}
+func (fs *knownFields) Range(f func(pref.FieldNumber, pref.Value) bool) {
+	for n, fi := range fs.mi.fields {
+		if fi.has(fs.p) {
+			if !f(n, fi.get(fs.p)) {
+				return
+			}
+		}
+	}
+	fs.extensionFields().Range(f)
+}
+func (fs *knownFields) NewMessage(n pref.FieldNumber) pref.Message {
+	if fi := fs.mi.fields[n]; fi != nil {
+		return fi.newMessage()
+	}
+	if fs.mi.PBType.Descriptor().ExtensionRanges().Has(n) {
+		return fs.extensionFields().NewMessage(n)
+	}
+	panic(fmt.Sprintf("invalid field: %d", n))
+}
+func (fs *knownFields) ExtensionTypes() pref.ExtensionFieldTypes {
+	return fs.extensionFields().ExtensionTypes()
+}
+func (fs *knownFields) extensionFields() pref.KnownFields {
+	return fs.mi.extensionFields((*messageDataType)(fs))
+}
+
+// TODO: Remove this.
+type emptyUnknownFields struct{}
+
+func (emptyUnknownFields) Len() int                                          { return 0 }
+func (emptyUnknownFields) Get(pref.FieldNumber) pref.RawFields               { return nil }
+func (emptyUnknownFields) Set(pref.FieldNumber, pref.RawFields)              { return } // noop
+func (emptyUnknownFields) Range(func(pref.FieldNumber, pref.RawFields) bool) { return }
+func (emptyUnknownFields) IsSupported() bool                                 { return false }
+
+// TODO: Remove this.
+type emptyExtensionFields struct{}
+
+func (emptyExtensionFields) Len() int                                      { return 0 }
+func (emptyExtensionFields) Has(pref.FieldNumber) bool                     { return false }
+func (emptyExtensionFields) Get(pref.FieldNumber) pref.Value               { return pref.Value{} }
+func (emptyExtensionFields) Set(pref.FieldNumber, pref.Value)              { panic("extensions not supported") }
+func (emptyExtensionFields) Clear(pref.FieldNumber)                        { return } // noop
+func (emptyExtensionFields) WhichOneof(pref.Name) pref.FieldNumber         { return 0 }
+func (emptyExtensionFields) Range(func(pref.FieldNumber, pref.Value) bool) { return }
+func (emptyExtensionFields) NewMessage(pref.FieldNumber) pref.Message {
+	panic("extensions not supported")
+}
+func (emptyExtensionFields) ExtensionTypes() pref.ExtensionFieldTypes { return emptyExtensionTypes{} }
+
+// TODO: Remove this.
+type emptyExtensionTypes struct{}
+
+func (emptyExtensionTypes) Len() int                                     { return 0 }
+func (emptyExtensionTypes) Register(pref.ExtensionType)                  { panic("extensions not supported") }
+func (emptyExtensionTypes) Remove(pref.ExtensionType)                    { return } // noop
+func (emptyExtensionTypes) ByNumber(pref.FieldNumber) pref.ExtensionType { return nil }
+func (emptyExtensionTypes) ByName(pref.FullName) pref.ExtensionType      { return nil }
+func (emptyExtensionTypes) Range(func(pref.ExtensionType) bool)          { return }
diff --git a/internal/impl/message_field.go b/internal/impl/message_field.go
index 28fc7d1..4f13256 100644
--- a/internal/impl/message_field.go
+++ b/internal/impl/message_field.go
@@ -16,11 +16,14 @@
 )
 
 type fieldInfo struct {
+	fieldDesc pref.FieldDescriptor
+
 	// These fields are used for protobuf reflection support.
 	has        func(pointer) bool
+	clear      func(pointer)
 	get        func(pointer) pref.Value
 	set        func(pointer, pref.Value)
-	clear      func(pointer)
+	mutable    func(pointer) pref.Value
 	newMessage func() pref.Message
 
 	// These fields are used for fast-path functions.
@@ -44,13 +47,19 @@
 		panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
 	}
 	conv, _ := newConverter(ot.Field(0).Type, fd.Kind())
-	fieldOffset := offsetOf(fs)
+	var frozenEmpty pref.Value
+	if conv.NewMessage != nil {
+		frozenEmpty = pref.ValueOf(frozenMessage{conv.NewMessage()})
+	}
+
 	// TODO: Implement unsafe fast path?
+	fieldOffset := offsetOf(fs)
 	return fieldInfo{
 		// NOTE: The logic below intentionally assumes that oneof fields are
 		// well-formatted. That is, the oneof interface never contains a
 		// typed nil pointer to one of the wrapper structs.
 
+		fieldDesc: fd,
 		has: func(p pointer) bool {
 			if p.IsNil() {
 				return false
@@ -61,12 +70,25 @@
 			}
 			return true
 		},
+		clear: func(p pointer) {
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+				return
+			}
+			rv.Set(reflect.Zero(rv.Type()))
+		},
 		get: func(p pointer) pref.Value {
 			if p.IsNil() {
+				if frozenEmpty.IsValid() {
+					return frozenEmpty
+				}
 				return defaultValueOf(fd)
 			}
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+				if frozenEmpty.IsValid() {
+					return frozenEmpty
+				}
 				return defaultValueOf(fd)
 			}
 			rv = rv.Elem().Elem().Field(0)
@@ -80,12 +102,19 @@
 			rv = rv.Elem().Elem().Field(0)
 			rv.Set(conv.GoValueOf(v))
 		},
-		clear: func(p pointer) {
+		mutable: func(p pointer) pref.Value {
+			if conv.NewMessage == nil {
+				panic("invalid Mutable on field with non-composite type")
+			}
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			if rv.IsNil() || rv.Elem().Type().Elem() != ot {
-				return
+				rv.Set(reflect.New(ot))
 			}
-			rv.Set(reflect.Zero(rv.Type()))
+			rv = rv.Elem().Elem().Field(0)
+			if rv.IsNil() {
+				rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
+			}
+			return conv.PBValueOf(rv)
 		},
 		newMessage: conv.NewMessage,
 		offset:     fieldOffset,
@@ -101,9 +130,14 @@
 	keyConv, _ := newConverter(ft.Key(), fd.MapKey().Kind())
 	valConv, _ := newConverter(ft.Elem(), fd.MapValue().Kind())
 	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
-	fieldOffset := offsetOf(fs)
+	frozenEmpty := pref.ValueOf(frozenMap{
+		pvalue.MapOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), keyConv, valConv),
+	})
+
 	// TODO: Implement unsafe fast path?
+	fieldOffset := offsetOf(fs)
 	return fieldInfo{
+		fieldDesc: fd,
 		has: func(p pointer) bool {
 			if p.IsNil() {
 				return false
@@ -111,21 +145,27 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			return rv.Len() > 0
 		},
+		clear: func(p pointer) {
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			rv.Set(reflect.Zero(rv.Type()))
+		},
 		get: func(p pointer) pref.Value {
 			if p.IsNil() {
-				v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
-				return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
+				return frozenEmpty
 			}
-			v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
-			return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			if rv.IsNil() {
+				return frozenEmpty
+			}
+			return pref.ValueOf(pvalue.MapOf(rv.Addr().Interface(), keyConv, valConv))
 		},
 		set: func(p pointer, v pref.Value) {
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
 		},
-		clear: func(p pointer) {
-			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
-			rv.Set(reflect.Zero(rv.Type()))
+		mutable: func(p pointer) pref.Value {
+			v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
+			return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
 		},
 		funcs:     encoderFuncsForMap(fd, ft),
 		offset:    fieldOffset,
@@ -147,9 +187,14 @@
 	} else {
 		wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
 	}
-	fieldOffset := offsetOf(fs)
+	frozenEmpty := pref.ValueOf(frozenList{
+		pvalue.ListOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), conv),
+	})
+
 	// TODO: Implement unsafe fast path?
+	fieldOffset := offsetOf(fs)
 	return fieldInfo{
+		fieldDesc: fd,
 		has: func(p pointer) bool {
 			if p.IsNil() {
 				return false
@@ -157,21 +202,27 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			return rv.Len() > 0
 		},
+		clear: func(p pointer) {
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			rv.Set(reflect.Zero(rv.Type()))
+		},
 		get: func(p pointer) pref.Value {
 			if p.IsNil() {
-				v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
-				return pref.ValueOf(pvalue.ListOf(v, conv))
+				return frozenEmpty
 			}
-			v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
-			return pref.ValueOf(pvalue.ListOf(v, conv))
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			if rv.Len() == 0 {
+				return frozenEmpty
+			}
+			return pref.ValueOf(pvalue.ListOf(rv.Addr().Interface(), conv))
 		},
 		set: func(p pointer, v pref.Value) {
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
 		},
-		clear: func(p pointer) {
-			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
-			rv.Set(reflect.Zero(rv.Type()))
+		mutable: func(p pointer) pref.Value {
+			v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
+			return pref.ValueOf(pvalue.ListOf(v, conv))
 		},
 		funcs:     fieldCoder(fd, ft),
 		offset:    fieldOffset,
@@ -196,10 +247,12 @@
 		}
 	}
 	conv, _ := newConverter(ft, fd.Kind())
-	fieldOffset := offsetOf(fs)
 	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
+
 	// TODO: Implement unsafe fast path?
+	fieldOffset := offsetOf(fs)
 	return fieldInfo{
+		fieldDesc: fd,
 		has: func(p pointer) bool {
 			if p.IsNil() {
 				return false
@@ -223,6 +276,10 @@
 				panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
 			}
 		},
+		clear: func(p pointer) {
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			rv.Set(reflect.Zero(rv.Type()))
+		},
 		get: func(p pointer) pref.Value {
 			if p.IsNil() {
 				return defaultValueOf(fd)
@@ -251,10 +308,6 @@
 				rv.Set(emptyBytes)
 			}
 		},
-		clear: func(p pointer) {
-			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
-			rv.Set(reflect.Zero(rv.Type()))
-		},
 		funcs:     funcs,
 		offset:    fieldOffset,
 		isPointer: nullable,
@@ -266,10 +319,13 @@
 func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
 	ft := fs.Type
 	conv, _ := newConverter(ft, fd.Kind())
-	fieldOffset := offsetOf(fs)
-	// TODO: Implement unsafe fast path?
 	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
+	frozenEmpty := pref.ValueOf(frozenMessage{conv.NewMessage()})
+
+	// TODO: Implement unsafe fast path?
+	fieldOffset := offsetOf(fs)
 	return fieldInfo{
+		fieldDesc: fd,
 		has: func(p pointer) bool {
 			if p.IsNil() {
 				return false
@@ -277,13 +333,17 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			return !rv.IsNil()
 		},
+		clear: func(p pointer) {
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			rv.Set(reflect.Zero(rv.Type()))
+		},
 		get: func(p pointer) pref.Value {
 			if p.IsNil() {
-				return pref.Value{}
+				return frozenEmpty
 			}
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			if rv.IsNil() {
-				return pref.Value{}
+				return frozenEmpty
 			}
 			return conv.PBValueOf(rv)
 		},
@@ -294,9 +354,12 @@
 				panic("invalid nil pointer")
 			}
 		},
-		clear: func(p pointer) {
+		mutable: func(p pointer) pref.Value {
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
-			rv.Set(reflect.Zero(rv.Type()))
+			if rv.IsNil() {
+				rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
+			}
+			return conv.PBValueOf(rv)
 		},
 		newMessage: conv.NewMessage,
 		funcs:      fieldCoder(fd, ft),
@@ -307,25 +370,15 @@
 	}
 }
 
-// defaultValueOf returns the default value for the field.
-func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
-	if fd == nil {
-		return pref.Value{}
-	}
-	pv := fd.Default() // invalid Value for messages and repeated fields
-	if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
-		return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
-	}
-	return pv
-}
-
 type oneofInfo struct {
-	which func(pointer) pref.FieldNumber
+	oneofDesc pref.OneofDescriptor
+	which     func(pointer) pref.FieldNumber
 }
 
 func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
 	fieldOffset := offsetOf(fs)
 	return &oneofInfo{
+		oneofDesc: od,
 		which: func(p pointer) pref.FieldNumber {
 			if p.IsNil() {
 				return 0
@@ -388,3 +441,76 @@
 	}
 	return pvalue.NewConverter(t, k), false
 }
+
+// defaultValueOf returns the default value for the field.
+func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
+	if fd == nil {
+		return pref.Value{}
+	}
+	pv := fd.Default() // invalid Value for messages and repeated fields
+	if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
+		return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
+	}
+	return pv
+}
+
+// frozenValueOf returns a frozen version of any composite value.
+func frozenValueOf(v pref.Value) pref.Value {
+	switch v := v.Interface().(type) {
+	case pref.Message:
+		if _, ok := v.(frozenMessage); !ok {
+			return pref.ValueOf(frozenMessage{v})
+		}
+	case pref.List:
+		if _, ok := v.(frozenList); !ok {
+			return pref.ValueOf(frozenList{v})
+		}
+	case pref.Map:
+		if _, ok := v.(frozenMap); !ok {
+			return pref.ValueOf(frozenMap{v})
+		}
+	}
+	return v
+}
+
+type frozenMessage struct{ pref.Message }
+
+func (m frozenMessage) ProtoReflect() pref.Message   { return m }
+func (m frozenMessage) Interface() pref.ProtoMessage { return m }
+func (m frozenMessage) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
+	m.Message.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
+		return f(fd, frozenValueOf(v))
+	})
+}
+func (m frozenMessage) Get(fd pref.FieldDescriptor) pref.Value {
+	v := m.Message.Get(fd)
+	return frozenValueOf(v)
+}
+func (frozenMessage) Clear(pref.FieldDescriptor)              { panic("invalid on read-only Message") }
+func (frozenMessage) Set(pref.FieldDescriptor, pref.Value)    { panic("invalid on read-only Message") }
+func (frozenMessage) Mutable(pref.FieldDescriptor) pref.Value { panic("invalid on read-only Message") }
+func (frozenMessage) SetUnknown(pref.RawFields)               { panic("invalid on read-only Message") }
+
+type frozenList struct{ pref.List }
+
+func (ls frozenList) Get(i int) pref.Value {
+	v := ls.List.Get(i)
+	return frozenValueOf(v)
+}
+func (frozenList) Set(i int, v pref.Value) { panic("invalid on read-only List") }
+func (frozenList) Append(v pref.Value)     { panic("invalid on read-only List") }
+func (frozenList) Truncate(i int)          { panic("invalid on read-only List") }
+
+type frozenMap struct{ pref.Map }
+
+func (ms frozenMap) Get(k pref.MapKey) pref.Value {
+	v := ms.Map.Get(k)
+	return frozenValueOf(v)
+}
+func (ms frozenMap) Range(f func(pref.MapKey, pref.Value) bool) {
+	ms.Map.Range(func(k pref.MapKey, v pref.Value) bool {
+		return f(k, frozenValueOf(v))
+	})
+}
+func (frozenMap) Set(k pref.MapKey, v pref.Value) { panic("invalid n read-only Map") }
+func (frozenMap) Clear(k pref.MapKey)             { panic("invalid on read-only Map") }
diff --git a/internal/impl/message_field_extension.go b/internal/impl/message_field_extension.go
index b537775..00c8573 100644
--- a/internal/impl/message_field_extension.go
+++ b/internal/impl/message_field_extension.go
@@ -10,10 +10,16 @@
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
+// TODO: Remove this file.
+
+var extType = reflect.TypeOf(map[int32]ExtensionField(nil))
+
 func makeLegacyExtensionFieldsFunc(t reflect.Type) func(p *messageDataType) pref.KnownFields {
 	f := makeLegacyExtensionMapFunc(t)
 	if f == nil {
-		return nil
+		return func(*messageDataType) pref.KnownFields {
+			return emptyExtensionFields{}
+		}
 	}
 	return func(p *messageDataType) pref.KnownFields {
 		if p.p.IsNil() {
@@ -23,8 +29,6 @@
 	}
 }
 
-var extType = reflect.TypeOf(map[int32]ExtensionField{})
-
 func makeLegacyExtensionMapFunc(t reflect.Type) func(*messageDataType) *legacyExtensionMap {
 	fx, _ := t.FieldByName("XXX_extensions")
 	if fx.Type != extType {
diff --git a/internal/impl/message_field_unknown.go b/internal/impl/message_field_unknown.go
index 6dc88f6..c34661d 100644
--- a/internal/impl/message_field_unknown.go
+++ b/internal/impl/message_field_unknown.go
@@ -12,12 +12,16 @@
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
+// TODO: Remove this file.
+
 var bytesType = reflect.TypeOf([]byte(nil))
 
 func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
 	fu, ok := t.FieldByName("XXX_unrecognized")
 	if !ok || fu.Type != bytesType {
-		return nil
+		return func(*messageDataType) pref.UnknownFields {
+			return emptyUnknownFields{}
+		}
 	}
 	fieldOffset := offsetOf(fu)
 	return func(p *messageDataType) pref.UnknownFields {
diff --git a/internal/impl/message_test.go b/internal/impl/message_test.go
index e1fc1ce..bb10ead 100644
--- a/internal/impl/message_test.go
+++ b/internal/impl/message_test.go
@@ -17,7 +17,6 @@
 	pimpl "google.golang.org/protobuf/internal/impl"
 	ptype "google.golang.org/protobuf/internal/prototype"
 	scalar "google.golang.org/protobuf/internal/scalar"
-	pvalue "google.golang.org/protobuf/internal/value"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/prototype"
 
@@ -52,25 +51,31 @@
 	// check for the presence of specific oneof member fields.
 	whichOneofs map[pref.Name]pref.FieldNumber
 	// apply messageOps on each specified message field
-	messageFields map[pref.FieldNumber]messageOps
+	messageFields        map[pref.FieldNumber]messageOps
+	messageFieldsMutable map[pref.FieldNumber]messageOps
 	// apply listOps on each specified list field
-	listFields map[pref.FieldNumber]listOps
+	listFields        map[pref.FieldNumber]listOps
+	listFieldsMutable map[pref.FieldNumber]listOps
 	// apply mapOps on each specified map fields
-	mapFields map[pref.FieldNumber]mapOps
+	mapFields        map[pref.FieldNumber]mapOps
+	mapFieldsMutable map[pref.FieldNumber]mapOps
 	// range through all fields and check that they match
 	rangeFields map[pref.FieldNumber]pref.Value
 )
 
-func (equalMessage) isMessageOp()  {}
-func (hasFields) isMessageOp()     {}
-func (getFields) isMessageOp()     {}
-func (setFields) isMessageOp()     {}
-func (clearFields) isMessageOp()   {}
-func (whichOneofs) isMessageOp()   {}
-func (messageFields) isMessageOp() {}
-func (listFields) isMessageOp()    {}
-func (mapFields) isMessageOp()     {}
-func (rangeFields) isMessageOp()   {}
+func (equalMessage) isMessageOp()         {}
+func (hasFields) isMessageOp()            {}
+func (getFields) isMessageOp()            {}
+func (setFields) isMessageOp()            {}
+func (clearFields) isMessageOp()          {}
+func (whichOneofs) isMessageOp()          {}
+func (messageFields) isMessageOp()        {}
+func (messageFieldsMutable) isMessageOp() {}
+func (listFields) isMessageOp()           {}
+func (listFieldsMutable) isMessageOp()    {}
+func (mapFields) isMessageOp()            {}
+func (mapFieldsMutable) isMessageOp()     {}
+func (rangeFields) isMessageOp()          {}
 
 // Test operations performed on a list.
 type (
@@ -221,27 +226,14 @@
 		},
 	}),
 	NewMessage: func() pref.Message {
-		return new(ScalarProto2)
+		return pref.ProtoMessage(new(ScalarProto2)).ProtoReflect()
 	},
 }}
 
-// TODO: Remove this.
-func (m *ScalarProto2) Type() pref.MessageType { return scalarProto2Type.PBType }
-func (m *ScalarProto2) Descriptor() pref.MessageDescriptor {
-	return scalarProto2Type.PBType.Descriptor()
-}
-func (m *ScalarProto2) KnownFields() pref.KnownFields {
-	return scalarProto2Type.MessageOf(m).KnownFields()
-}
-func (m *ScalarProto2) UnknownFields() pref.UnknownFields {
-	return scalarProto2Type.MessageOf(m).UnknownFields()
-}
-func (m *ScalarProto2) New() pref.Message            { return new(ScalarProto2) }
-func (m *ScalarProto2) Interface() pref.ProtoMessage { return m }
-func (m *ScalarProto2) ProtoReflect() pref.Message   { return m }
+func (m *ScalarProto2) ProtoReflect() pref.Message { return scalarProto2Type.MessageOf(m) }
 
 func TestScalarProto2(t *testing.T) {
-	testMessage(t, nil, &ScalarProto2{}, messageOps{
+	testMessage(t, nil, new(ScalarProto2).ProtoReflect(), messageOps{
 		hasFields{
 			1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
 			12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
@@ -258,16 +250,16 @@
 			1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
 			12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
 		},
-		equalMessage{&ScalarProto2{
+		equalMessage{(&ScalarProto2{
 			new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string),
 			new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString),
-		}},
+		}).ProtoReflect()},
 		clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
-		equalMessage{&ScalarProto2{}},
+		equalMessage{new(ScalarProto2).ProtoReflect()},
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*ScalarProto2)(nil), messageOps{
+	testMessage(t, nil, (*ScalarProto2)(nil).ProtoReflect(), messageOps{
 		hasFields{
 			1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
 			12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
@@ -336,27 +328,14 @@
 		},
 	}),
 	NewMessage: func() pref.Message {
-		return new(ScalarProto3)
+		return pref.ProtoMessage(new(ScalarProto3)).ProtoReflect()
 	},
 }}
 
-// TODO: Remove this.
-func (m *ScalarProto3) Type() pref.MessageType { return scalarProto3Type.PBType }
-func (m *ScalarProto3) Descriptor() pref.MessageDescriptor {
-	return scalarProto3Type.PBType.Descriptor()
-}
-func (m *ScalarProto3) KnownFields() pref.KnownFields {
-	return scalarProto3Type.MessageOf(m).KnownFields()
-}
-func (m *ScalarProto3) UnknownFields() pref.UnknownFields {
-	return scalarProto3Type.MessageOf(m).UnknownFields()
-}
-func (m *ScalarProto3) New() pref.Message            { return new(ScalarProto3) }
-func (m *ScalarProto3) Interface() pref.ProtoMessage { return m }
-func (m *ScalarProto3) ProtoReflect() pref.Message   { return m }
+func (m *ScalarProto3) ProtoReflect() pref.Message { return scalarProto3Type.MessageOf(m) }
 
 func TestScalarProto3(t *testing.T) {
-	testMessage(t, nil, &ScalarProto3{}, messageOps{
+	testMessage(t, nil, new(ScalarProto3).ProtoReflect(), messageOps{
 		hasFields{
 			1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
 			12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
@@ -373,7 +352,7 @@
 			1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
 			12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
 		},
-		equalMessage{&ScalarProto3{}},
+		equalMessage{new(ScalarProto3).ProtoReflect()},
 		setFields{
 			1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
 			12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
@@ -382,10 +361,10 @@
 			1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
 			12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
 		},
-		equalMessage{&ScalarProto3{
+		equalMessage{(&ScalarProto3{
 			true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11",
 			true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22",
-		}},
+		}).ProtoReflect()},
 		setFields{
 			2: V(int32(-2)), 3: V(int64(-3)), 6: V(float32(math.Inf(-1))), 7: V(float64(math.NaN())),
 		},
@@ -393,7 +372,7 @@
 			2: true, 3: true, 6: true, 7: true,
 		},
 		clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
-		equalMessage{&ScalarProto3{}},
+		equalMessage{new(ScalarProto3).ProtoReflect()},
 
 		// Verify that -0 triggers proper Has behavior.
 		hasFields{6: false, 7: false},
@@ -402,7 +381,7 @@
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*ScalarProto3)(nil), messageOps{
+	testMessage(t, nil, (*ScalarProto3)(nil).ProtoReflect(), messageOps{
 		hasFields{
 			1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
 			12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
@@ -467,28 +446,15 @@
 		},
 	}),
 	NewMessage: func() pref.Message {
-		return new(ListScalars)
+		return pref.ProtoMessage(new(ListScalars)).ProtoReflect()
 	},
 }}
 
-// TODO: Remove this.
-func (m *ListScalars) Type() pref.MessageType             { return listScalarsType.PBType }
-func (m *ListScalars) Descriptor() pref.MessageDescriptor { return listScalarsType.PBType.Descriptor() }
-func (m *ListScalars) KnownFields() pref.KnownFields {
-	return listScalarsType.MessageOf(m).KnownFields()
-}
-func (m *ListScalars) UnknownFields() pref.UnknownFields {
-	return listScalarsType.MessageOf(m).UnknownFields()
-}
-func (m *ListScalars) New() pref.Message            { return new(ListScalars) }
-func (m *ListScalars) Interface() pref.ProtoMessage { return m }
-func (m *ListScalars) ProtoReflect() pref.Message   { return m }
+func (m *ListScalars) ProtoReflect() pref.Message { return listScalarsType.MessageOf(m) }
 
 func TestListScalars(t *testing.T) {
-	empty := &ListScalars{}
-	emptyFS := empty.KnownFields()
-
-	want := &ListScalars{
+	empty := new(ListScalars).ProtoReflect()
+	want := (&ListScalars{
 		Bools:    []bool{true, false, true},
 		Int32s:   []int32{2, math.MinInt32, math.MaxInt32},
 		Int64s:   []int64{3, math.MinInt64, math.MaxInt64},
@@ -510,19 +476,18 @@
 		MyStrings4: ListBytes{[]byte("17"), nil, []byte("seventeen")},
 		MyBytes3:   ListBytes{[]byte("18"), nil, []byte("eighteen")},
 		MyBytes4:   ListStrings{"19", "", "nineteen"},
-	}
-	wantFS := want.KnownFields()
+	}).ProtoReflect()
 
-	testMessage(t, nil, &ListScalars{}, messageOps{
+	testMessage(t, nil, new(ListScalars).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false},
-		getFields{1: emptyFS.Get(1), 3: emptyFS.Get(3), 5: emptyFS.Get(5), 7: emptyFS.Get(7), 9: emptyFS.Get(9), 11: emptyFS.Get(11), 13: emptyFS.Get(13), 15: emptyFS.Get(15), 17: emptyFS.Get(17), 19: emptyFS.Get(19)},
-		setFields{1: wantFS.Get(1), 3: wantFS.Get(3), 5: wantFS.Get(5), 7: wantFS.Get(7), 9: wantFS.Get(9), 11: wantFS.Get(11), 13: wantFS.Get(13), 15: wantFS.Get(15), 17: wantFS.Get(17), 19: wantFS.Get(19)},
-		listFields{
+		getFields{1: getField(empty, 1), 3: getField(empty, 3), 5: getField(empty, 5), 7: getField(empty, 7), 9: getField(empty, 9), 11: getField(empty, 11), 13: getField(empty, 13), 15: getField(empty, 15), 17: getField(empty, 17), 19: getField(empty, 19)},
+		setFields{1: getField(want, 1), 3: getField(want, 3), 5: getField(want, 5), 7: getField(want, 7), 9: getField(want, 9), 11: getField(want, 11), 13: getField(want, 13), 15: getField(want, 15), 17: getField(want, 17), 19: getField(want, 19)},
+		listFieldsMutable{
 			2: {
 				lenList(0),
 				appendList{V(int32(2)), V(int32(math.MinInt32)), V(int32(math.MaxInt32))},
 				getList{0: V(int32(2)), 1: V(int32(math.MinInt32)), 2: V(int32(math.MaxInt32))},
-				equalList{wantFS.Get(2).List()},
+				equalList{getField(want, 2).List()},
 			},
 			4: {
 				appendList{V(uint32(0)), V(uint32(0)), V(uint32(0))},
@@ -531,39 +496,39 @@
 			},
 			6: {
 				appendList{V(float32(6)), V(float32(math.SmallestNonzeroFloat32)), V(float32(math.NaN())), V(float32(math.MaxFloat32))},
-				equalList{wantFS.Get(6).List()},
+				equalList{getField(want, 6).List()},
 			},
 			8: {
 				appendList{V(""), V(""), V(""), V(""), V(""), V("")},
 				lenList(6),
 				setList{0: V("8"), 2: V("eight")},
 				truncList(3),
-				equalList{wantFS.Get(8).List()},
+				equalList{getField(want, 8).List()},
 			},
 			10: {
 				appendList{V([]byte(nil)), V([]byte(nil))},
 				setList{0: V([]byte("10"))},
 				appendList{V([]byte("wrong"))},
 				setList{2: V([]byte("ten"))},
-				equalList{wantFS.Get(10).List()},
+				equalList{getField(want, 10).List()},
 			},
 			12: {
 				appendList{V("12"), V("wrong"), V("twelve")},
 				setList{1: V("")},
-				equalList{wantFS.Get(12).List()},
+				equalList{getField(want, 12).List()},
 			},
 			14: {
 				appendList{V([]byte("14")), V([]byte(nil)), V([]byte("fourteen"))},
-				equalList{wantFS.Get(14).List()},
+				equalList{getField(want, 14).List()},
 			},
 			16: {
 				appendList{V("16"), V(""), V("sixteen"), V("extra")},
 				truncList(3),
-				equalList{wantFS.Get(16).List()},
+				equalList{getField(want, 16).List()},
 			},
 			18: {
 				appendList{V([]byte("18")), V([]byte(nil)), V([]byte("eighteen"))},
-				equalList{wantFS.Get(18).List()},
+				equalList{getField(want, 18).List()},
 			},
 		},
 		hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true},
@@ -573,7 +538,7 @@
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*ListScalars)(nil), messageOps{
+	testMessage(t, nil, (*ListScalars)(nil).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false},
 		listFields{2: {lenList(0)}, 4: {lenList(0)}, 6: {lenList(0)}, 8: {lenList(0)}, 10: {lenList(0)}, 12: {lenList(0)}, 14: {lenList(0)}, 16: {lenList(0)}, 18: {lenList(0)}},
 	})
@@ -665,28 +630,15 @@
 		},
 	}),
 	NewMessage: func() pref.Message {
-		return new(MapScalars)
+		return pref.ProtoMessage(new(MapScalars)).ProtoReflect()
 	},
 }}
 
-// TODO: Remove this.
-func (m *MapScalars) Type() pref.MessageType             { return mapScalarsType.PBType }
-func (m *MapScalars) Descriptor() pref.MessageDescriptor { return mapScalarsType.PBType.Descriptor() }
-func (m *MapScalars) KnownFields() pref.KnownFields {
-	return mapScalarsType.MessageOf(m).KnownFields()
-}
-func (m *MapScalars) UnknownFields() pref.UnknownFields {
-	return mapScalarsType.MessageOf(m).UnknownFields()
-}
-func (m *MapScalars) New() pref.Message            { return new(MapScalars) }
-func (m *MapScalars) Interface() pref.ProtoMessage { return m }
-func (m *MapScalars) ProtoReflect() pref.Message   { return m }
+func (m *MapScalars) ProtoReflect() pref.Message { return mapScalarsType.MessageOf(m) }
 
 func TestMapScalars(t *testing.T) {
-	empty := &MapScalars{}
-	emptyFS := empty.KnownFields()
-
-	want := &MapScalars{
+	empty := new(MapScalars).ProtoReflect()
+	want := (&MapScalars{
 		KeyBools:   map[bool]string{true: "true", false: "false"},
 		KeyInt32s:  map[int32]string{0: "zero", -1: "one", 2: "two"},
 		KeyInt64s:  map[int64]string{0: "zero", -10: "ten", 20: "twenty"},
@@ -715,14 +667,13 @@
 		MyStrings4: MapBytes{"s1": []byte("s1"), "s2": []byte("s2")},
 		MyBytes3:   MapBytes{"s1": []byte("s1"), "s2": []byte("s2")},
 		MyBytes4:   MapStrings{"s1": "s1", "s2": "s2"},
-	}
-	wantFS := want.KnownFields()
+	}).ProtoReflect()
 
-	testMessage(t, nil, &MapScalars{}, messageOps{
+	testMessage(t, nil, new(MapScalars).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, 23: false, 24: false, 25: false},
-		getFields{1: emptyFS.Get(1), 3: emptyFS.Get(3), 5: emptyFS.Get(5), 7: emptyFS.Get(7), 9: emptyFS.Get(9), 11: emptyFS.Get(11), 13: emptyFS.Get(13), 15: emptyFS.Get(15), 17: emptyFS.Get(17), 19: emptyFS.Get(19), 21: emptyFS.Get(21), 23: emptyFS.Get(23), 25: emptyFS.Get(25)},
-		setFields{1: wantFS.Get(1), 3: wantFS.Get(3), 5: wantFS.Get(5), 7: wantFS.Get(7), 9: wantFS.Get(9), 11: wantFS.Get(11), 13: wantFS.Get(13), 15: wantFS.Get(15), 17: wantFS.Get(17), 19: wantFS.Get(19), 21: wantFS.Get(21), 23: wantFS.Get(23), 25: wantFS.Get(25)},
-		mapFields{
+		getFields{1: getField(empty, 1), 3: getField(empty, 3), 5: getField(empty, 5), 7: getField(empty, 7), 9: getField(empty, 9), 11: getField(empty, 11), 13: getField(empty, 13), 15: getField(empty, 15), 17: getField(empty, 17), 19: getField(empty, 19), 21: getField(empty, 21), 23: getField(empty, 23), 25: getField(empty, 25)},
+		setFields{1: getField(want, 1), 3: getField(want, 3), 5: getField(want, 5), 7: getField(want, 7), 9: getField(want, 9), 11: getField(want, 11), 13: getField(want, 13), 15: getField(want, 15), 17: getField(want, 17), 19: getField(want, 19), 21: getField(want, 21), 23: getField(want, 23), 25: getField(want, 25)},
+		mapFieldsMutable{
 			2: {
 				lenMap(0),
 				hasMap{int32(0): false, int32(-1): false, int32(2): false},
@@ -738,7 +689,7 @@
 			},
 			4: {
 				setMap{uint32(0): V("zero"), uint32(1): V("one"), uint32(2): V("two")},
-				equalMap{wantFS.Get(4).Map()},
+				equalMap{getField(want, 4).Map()},
 			},
 			6: {
 				clearMap{"noexist"},
@@ -749,13 +700,13 @@
 				clearMap{"extra", "noexist"},
 			},
 			8: {
-				equalMap{emptyFS.Get(8).Map()},
+				equalMap{getField(empty, 8).Map()},
 				setMap{"one": V(int32(1)), "two": V(int32(2)), "three": V(int32(3))},
 			},
 			10: {
 				setMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead))},
 				lenMap(3),
-				equalMap{wantFS.Get(10).Map()},
+				equalMap{getField(want, 10).Map()},
 				getMap{"0x00": V(uint32(0x00)), "0xff": V(uint32(0xff)), "0xdead": V(uint32(0xdead)), "0xdeadbeef": V(nil)},
 			},
 			12: {
@@ -764,12 +715,12 @@
 				rangeMap{"nan": V(float32(math.NaN())), "pi": V(float32(math.Pi))},
 			},
 			14: {
-				equalMap{emptyFS.Get(14).Map()},
+				equalMap{getField(empty, 14).Map()},
 				setMap{"s1": V("s1"), "s2": V("s2")},
 			},
 			16: {
 				setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
-				equalMap{wantFS.Get(16).Map()},
+				equalMap{getField(want, 16).Map()},
 			},
 			18: {
 				hasMap{"s1": false, "s2": false, "s3": false},
@@ -777,7 +728,7 @@
 				hasMap{"s1": true, "s2": true, "s3": false},
 			},
 			20: {
-				equalMap{emptyFS.Get(20).Map()},
+				equalMap{getField(empty, 20).Map()},
 				setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
 			},
 			22: {
@@ -788,7 +739,7 @@
 			},
 			24: {
 				setMap{"s1": V([]byte("s1")), "s2": V([]byte("s2"))},
-				equalMap{wantFS.Get(24).Map()},
+				equalMap{getField(want, 24).Map()},
 			},
 		},
 		hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true, 23: true, 24: true, 25: true},
@@ -798,7 +749,7 @@
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*MapScalars)(nil), messageOps{
+	testMessage(t, nil, (*MapScalars)(nil).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, 23: false, 24: false, 25: false},
 		mapFields{2: {lenMap(0)}, 4: {lenMap(0)}, 6: {lenMap(0)}, 8: {lenMap(0)}, 10: {lenMap(0)}, 12: {lenMap(0)}, 14: {lenMap(0)}, 16: {lenMap(0)}, 18: {lenMap(0)}, 20: {lenMap(0)}, 22: {lenMap(0)}, 24: {lenMap(0)}},
 	})
@@ -830,24 +781,11 @@
 		Oneofs: []ptype.Oneof{{Name: "union"}},
 	}),
 	NewMessage: func() pref.Message {
-		return new(OneofScalars)
+		return pref.ProtoMessage(new(OneofScalars)).ProtoReflect()
 	},
 }}
 
-// TODO: Remove this.
-func (m *OneofScalars) Type() pref.MessageType { return oneofScalarsType.PBType }
-func (m *OneofScalars) Descriptor() pref.MessageDescriptor {
-	return oneofScalarsType.PBType.Descriptor()
-}
-func (m *OneofScalars) KnownFields() pref.KnownFields {
-	return oneofScalarsType.MessageOf(m).KnownFields()
-}
-func (m *OneofScalars) UnknownFields() pref.UnknownFields {
-	return oneofScalarsType.MessageOf(m).UnknownFields()
-}
-func (m *OneofScalars) New() pref.Message            { return new(OneofScalars) }
-func (m *OneofScalars) Interface() pref.ProtoMessage { return m }
-func (m *OneofScalars) ProtoReflect() pref.Message   { return m }
+func (m *OneofScalars) ProtoReflect() pref.Message { return oneofScalarsType.MessageOf(m) }
 
 func (*OneofScalars) XXX_OneofWrappers() []interface{} {
 	return []interface{}{
@@ -942,41 +880,41 @@
 	want12 := &OneofScalars{Union: &OneofScalars_BytesA{string("120")}}
 	want13 := &OneofScalars{Union: &OneofScalars_BytesB{MyBytes("130")}}
 
-	testMessage(t, nil, &OneofScalars{}, messageOps{
+	testMessage(t, nil, new(OneofScalars).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
 		getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("13"))},
-		whichOneofs{"union": 0, "Union": 0},
+		whichOneofs{"union": 0},
 
-		setFields{1: V(bool(true))}, hasFields{1: true}, equalMessage{want1},
-		setFields{2: V(int32(20))}, hasFields{2: true}, equalMessage{want2},
-		setFields{3: V(int64(30))}, hasFields{3: true}, equalMessage{want3},
-		setFields{4: V(uint32(40))}, hasFields{4: true}, equalMessage{want4},
-		setFields{5: V(uint64(50))}, hasFields{5: true}, equalMessage{want5},
-		setFields{6: V(float32(60))}, hasFields{6: true}, equalMessage{want6},
-		setFields{7: V(float64(70))}, hasFields{7: true}, equalMessage{want7},
+		setFields{1: V(bool(true))}, hasFields{1: true}, equalMessage{want1.ProtoReflect()},
+		setFields{2: V(int32(20))}, hasFields{2: true}, equalMessage{want2.ProtoReflect()},
+		setFields{3: V(int64(30))}, hasFields{3: true}, equalMessage{want3.ProtoReflect()},
+		setFields{4: V(uint32(40))}, hasFields{4: true}, equalMessage{want4.ProtoReflect()},
+		setFields{5: V(uint64(50))}, hasFields{5: true}, equalMessage{want5.ProtoReflect()},
+		setFields{6: V(float32(60))}, hasFields{6: true}, equalMessage{want6.ProtoReflect()},
+		setFields{7: V(float64(70))}, hasFields{7: true}, equalMessage{want7.ProtoReflect()},
 
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: true, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
-		whichOneofs{"union": 7, "Union": 0},
+		whichOneofs{"union": 7},
 
-		setFields{8: V(string("80"))}, hasFields{8: true}, equalMessage{want8},
-		setFields{9: V(string("90"))}, hasFields{9: true}, equalMessage{want9},
-		setFields{10: V(string("100"))}, hasFields{10: true}, equalMessage{want10},
-		setFields{11: V([]byte("110"))}, hasFields{11: true}, equalMessage{want11},
-		setFields{12: V([]byte("120"))}, hasFields{12: true}, equalMessage{want12},
-		setFields{13: V([]byte("130"))}, hasFields{13: true}, equalMessage{want13},
+		setFields{8: V(string("80"))}, hasFields{8: true}, equalMessage{want8.ProtoReflect()},
+		setFields{9: V(string("90"))}, hasFields{9: true}, equalMessage{want9.ProtoReflect()},
+		setFields{10: V(string("100"))}, hasFields{10: true}, equalMessage{want10.ProtoReflect()},
+		setFields{11: V([]byte("110"))}, hasFields{11: true}, equalMessage{want11.ProtoReflect()},
+		setFields{12: V([]byte("120"))}, hasFields{12: true}, equalMessage{want12.ProtoReflect()},
+		setFields{13: V([]byte("130"))}, hasFields{13: true}, equalMessage{want13.ProtoReflect()},
 
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: true},
 		getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("130"))},
 		clearFields{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
-		whichOneofs{"union": 13, "Union": 0},
-		equalMessage{want13},
+		whichOneofs{"union": 13},
+		equalMessage{want13.ProtoReflect()},
 		clearFields{13},
-		whichOneofs{"union": 0, "Union": 0},
-		equalMessage{empty},
+		whichOneofs{"union": 0},
+		equalMessage{empty.ProtoReflect()},
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*OneofScalars)(nil), messageOps{
+	testMessage(t, nil, (*OneofScalars)(nil).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false},
 		getFields{1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V(string("10")), 11: V([]byte("11")), 12: V([]byte("12")), 13: V([]byte("13"))},
 	})
@@ -1053,7 +991,7 @@
 		Oneofs: []ptype.Oneof{{Name: "union"}},
 	}),
 	NewMessage: func() pref.Message {
-		return new(EnumMessages)
+		return pref.ProtoMessage(new(EnumMessages)).ProtoReflect()
 	},
 }}
 
@@ -1079,20 +1017,7 @@
 	IsMapEntry: true,
 })
 
-// TODO: Remove this.
-func (m *EnumMessages) Type() pref.MessageType { return enumMessagesType.PBType }
-func (m *EnumMessages) Descriptor() pref.MessageDescriptor {
-	return enumMessagesType.PBType.Descriptor()
-}
-func (m *EnumMessages) KnownFields() pref.KnownFields {
-	return enumMessagesType.MessageOf(m).KnownFields()
-}
-func (m *EnumMessages) UnknownFields() pref.UnknownFields {
-	return enumMessagesType.MessageOf(m).UnknownFields()
-}
-func (m *EnumMessages) New() pref.Message            { return new(EnumMessages) }
-func (m *EnumMessages) Interface() pref.ProtoMessage { return m }
-func (m *EnumMessages) ProtoReflect() pref.Message   { return m }
+func (m *EnumMessages) ProtoReflect() pref.Message { return enumMessagesType.MessageOf(m) }
 
 func (*EnumMessages) XXX_OneofWrappers() []interface{} {
 	return []interface{}{
@@ -1127,22 +1052,27 @@
 func (*EnumMessages_OneofM3) isEnumMessages_Union() {}
 
 func TestEnumMessages(t *testing.T) {
+	emptyL := pimpl.Export{}.MessageOf(new(proto2_20180125.Message))
+	emptyM := new(EnumMessages).ProtoReflect()
+	emptyM2 := new(ScalarProto2).ProtoReflect()
+	emptyM3 := new(ScalarProto3).ProtoReflect()
+
 	wantL := pimpl.Export{}.MessageOf(&proto2_20180125.Message{OptionalFloat: scalar.Float32(math.E)})
-	wantM := &EnumMessages{EnumP2: EnumProto2(1234).Enum()}
+	wantM := (&EnumMessages{EnumP2: EnumProto2(1234).Enum()}).ProtoReflect()
 	wantM2a := &ScalarProto2{Float32: scalar.Float32(math.Pi)}
 	wantM2b := &ScalarProto2{Float32: scalar.Float32(math.Phi)}
 	wantM3a := &ScalarProto3{Float32: math.Pi}
 	wantM3b := &ScalarProto3{Float32: math.Ln2}
 
-	wantList5 := (&EnumMessages{EnumList: []EnumProto2{333, 222}}).KnownFields().Get(5)
-	wantList6 := (&EnumMessages{MessageList: []*ScalarProto2{wantM2a, wantM2b}}).KnownFields().Get(6)
+	wantList5 := getField((&EnumMessages{EnumList: []EnumProto2{333, 222}}).ProtoReflect(), 5)
+	wantList6 := getField((&EnumMessages{MessageList: []*ScalarProto2{wantM2a, wantM2b}}).ProtoReflect(), 6)
 
-	wantMap7 := (&EnumMessages{EnumMap: map[string]EnumProto3{"one": 1, "two": 2}}).KnownFields().Get(7)
-	wantMap8 := (&EnumMessages{MessageMap: map[string]*ScalarProto3{"pi": wantM3a, "ln2": wantM3b}}).KnownFields().Get(8)
+	wantMap7 := getField((&EnumMessages{EnumMap: map[string]EnumProto3{"one": 1, "two": 2}}).ProtoReflect(), 7)
+	wantMap8 := getField((&EnumMessages{MessageMap: map[string]*ScalarProto3{"pi": wantM3a, "ln2": wantM3b}}).ProtoReflect(), 8)
 
-	testMessage(t, nil, &EnumMessages{}, messageOps{
+	testMessage(t, nil, new(EnumMessages).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false},
-		getFields{1: VE(0xbeef), 2: VE(1), 3: V(nil), 4: V(nil), 9: VE(0xbeef), 10: VE(1)},
+		getFields{1: VE(0xbeef), 2: VE(1), 3: V(emptyL), 4: V(emptyM), 9: VE(0xbeef), 10: VE(1)},
 
 		// Test singular enums.
 		setFields{1: VE(0xdead), 2: VE(0)},
@@ -1150,8 +1080,8 @@
 		hasFields{1: true, 2: true},
 
 		// Test singular messages.
-		messageFields{3: messageOps{setFields{109: V(float32(math.E))}}},
-		messageFields{4: messageOps{setFields{1: VE(1234)}}},
+		messageFieldsMutable{3: messageOps{setFields{109: V(float32(math.E))}}},
+		messageFieldsMutable{4: messageOps{setFields{1: VE(1234)}}},
 		getFields{3: V(wantL), 4: V(wantM)},
 		clearFields{3, 4},
 		hasFields{3: false, 4: false},
@@ -1159,7 +1089,7 @@
 		hasFields{3: true, 4: true},
 
 		// Test list of enums and messages.
-		listFields{
+		listFieldsMutable{
 			5: listOps{
 				appendList{VE(111), VE(222)},
 				setList{0: VE(333)},
@@ -1169,8 +1099,8 @@
 			6: listOps{
 				appendMessageList{setFields{4: V(uint32(1e6))}},
 				appendMessageList{setFields{6: V(float32(math.Phi))}},
-				setList{0: V(wantM2a)},
-				getList{0: V(wantM2a), 1: V(wantM2b)},
+				setList{0: V(wantM2a.ProtoReflect())},
+				getList{0: V(wantM2a.ProtoReflect()), 1: V(wantM2b.ProtoReflect())},
 			},
 		},
 		getFields{5: wantList5, 6: wantList6},
@@ -1179,7 +1109,7 @@
 		hasFields{5: false, 6: true},
 
 		// Test maps of enums and messages.
-		mapFields{
+		mapFieldsMutable{
 			7: mapOps{
 				setMap{"one": VE(1), "two": VE(2)},
 				hasMap{"one": true, "two": true, "three": false},
@@ -1187,8 +1117,8 @@
 			},
 			8: mapOps{
 				messageMap{"pi": messageOps{setFields{6: V(float32(math.Pi))}}},
-				setMap{"ln2": V(wantM3b)},
-				getMap{"pi": V(wantM3a), "ln2": V(wantM3b), "none": V(nil)},
+				setMap{"ln2": V(wantM3b.ProtoReflect())},
+				getMap{"pi": V(wantM3a.ProtoReflect()), "ln2": V(wantM3b.ProtoReflect()), "none": V(nil)},
 				lenMap(2),
 			},
 		},
@@ -1202,32 +1132,32 @@
 		hasFields{1: true, 2: true, 9: true, 10: false, 11: false, 12: false},
 		setFields{10: VE(0)},
 		hasFields{1: true, 2: true, 9: false, 10: true, 11: false, 12: false},
-		messageFields{11: messageOps{setFields{6: V(float32(math.Pi))}}},
-		getFields{11: V(wantM2a)},
+		messageFieldsMutable{11: messageOps{setFields{6: V(float32(math.Pi))}}},
+		getFields{11: V(wantM2a.ProtoReflect())},
 		hasFields{1: true, 2: true, 9: false, 10: false, 11: true, 12: false},
-		messageFields{12: messageOps{setFields{6: V(float32(math.Pi))}}},
-		getFields{12: V(wantM3a)},
+		messageFieldsMutable{12: messageOps{setFields{6: V(float32(math.Pi))}}},
+		getFields{12: V(wantM3a.ProtoReflect())},
 		hasFields{1: true, 2: true, 9: false, 10: false, 11: false, 12: true},
 
 		// Check entire message.
-		rangeFields{1: VE(0xdead), 2: VE(0), 3: V(wantL), 4: V(wantM), 6: wantList6, 7: wantMap7, 12: V(wantM3a)},
-		equalMessage{&EnumMessages{
+		rangeFields{1: VE(0xdead), 2: VE(0), 3: V(wantL), 4: V(wantM), 6: wantList6, 7: wantMap7, 12: V(wantM3a.ProtoReflect())},
+		equalMessage{(&EnumMessages{
 			EnumP2:        EnumProto2(0xdead).Enum(),
 			EnumP3:        EnumProto3(0).Enum(),
 			MessageLegacy: &proto2_20180125.Message{OptionalFloat: scalar.Float32(math.E)},
-			MessageCycle:  wantM,
+			MessageCycle:  wantM.Interface().(*EnumMessages),
 			MessageList:   []*ScalarProto2{wantM2a, wantM2b},
 			EnumMap:       map[string]EnumProto3{"one": 1, "two": 2},
 			Union:         &EnumMessages_OneofM3{wantM3a},
-		}},
+		}).ProtoReflect()},
 		clearFields{1, 2, 3, 4, 6, 7, 12},
-		equalMessage{&EnumMessages{}},
+		equalMessage{new(EnumMessages).ProtoReflect()},
 	})
 
 	// Test read-only operations on nil message.
-	testMessage(t, nil, (*EnumMessages)(nil), messageOps{
+	testMessage(t, nil, (*EnumMessages)(nil).ProtoReflect(), messageOps{
 		hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false},
-		getFields{1: VE(0xbeef), 2: VE(1), 3: V(nil), 4: V(nil), 9: VE(0xbeef), 10: VE(1), 11: V(nil), 12: V(nil)},
+		getFields{1: VE(0xbeef), 2: VE(1), 3: V(emptyL), 4: V(emptyM), 9: VE(0xbeef), 10: VE(1), 11: V(emptyM2), 12: V(emptyM3)},
 		listFields{5: {lenList(0)}, 6: {lenList(0)}},
 		mapFields{7: {lenMap(0)}, 8: {lenMap(0)}},
 	})
@@ -1238,89 +1168,141 @@
 		return protoV1.Equal(x, y)
 	}),
 	cmp.Transformer("UnwrapValue", func(pv pref.Value) interface{} {
-		return pv.Interface()
-	}),
-	cmp.Transformer("UnwrapGeneric", func(x pvalue.Unwrapper) interface{} {
-		return x.ProtoUnwrap()
+		switch v := pv.Interface().(type) {
+		case pref.Message:
+			out := make(map[pref.FieldNumber]pref.Value)
+			v.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
+				out[fd.Number()] = v
+				return true
+			})
+			return out
+		case pref.List:
+			var out []pref.Value
+			for i := 0; i < v.Len(); i++ {
+				out = append(out, v.Get(i))
+			}
+			return out
+		case pref.Map:
+			out := make(map[interface{}]pref.Value)
+			v.Range(func(k pref.MapKey, v pref.Value) bool {
+				out[k.Interface()] = v
+				return true
+			})
+			return out
+		default:
+			return v
+		}
 	}),
 	cmpopts.EquateNaNs(),
 	cmpopts.EquateEmpty(),
 }
 
 func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) {
-	fs := m.KnownFields()
+	fieldDescs := m.Descriptor().Fields()
+	oneofDescs := m.Descriptor().Oneofs()
 	for i, op := range tt {
 		p.Push(i)
 		switch op := op.(type) {
 		case equalMessage:
-			if diff := cmp.Diff(op.Message, m, cmpOpts); diff != "" {
+			if diff := cmp.Diff(V(op.Message), V(m), cmpOpts); diff != "" {
 				t.Errorf("operation %v, message mismatch (-want, +got):\n%s", p, diff)
 			}
 		case hasFields:
 			got := map[pref.FieldNumber]bool{}
 			want := map[pref.FieldNumber]bool(op)
 			for n := range want {
-				got[n] = fs.Has(n)
+				fd := fieldDescs.ByNumber(n)
+				got[n] = m.Has(fd)
 			}
 			if diff := cmp.Diff(want, got); diff != "" {
-				t.Errorf("operation %v, KnownFields.Has mismatch (-want, +got):\n%s", p, diff)
+				t.Errorf("operation %v, Message.Has mismatch (-want, +got):\n%s", p, diff)
 			}
 		case getFields:
 			got := map[pref.FieldNumber]pref.Value{}
 			want := map[pref.FieldNumber]pref.Value(op)
 			for n := range want {
-				got[n] = fs.Get(n)
+				fd := fieldDescs.ByNumber(n)
+				got[n] = m.Get(fd)
 			}
 			if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
-				t.Errorf("operation %v, KnownFields.Get mismatch (-want, +got):\n%s", p, diff)
+				t.Errorf("operation %v, Message.Get mismatch (-want, +got):\n%s", p, diff)
 			}
 		case setFields:
 			for n, v := range op {
-				fs.Set(n, v)
+				fd := fieldDescs.ByNumber(n)
+				m.Set(fd, v)
 			}
 		case clearFields:
 			for _, n := range op {
-				fs.Clear(n)
+				fd := fieldDescs.ByNumber(n)
+				m.Clear(fd)
 			}
 		case whichOneofs:
 			got := map[pref.Name]pref.FieldNumber{}
 			want := map[pref.Name]pref.FieldNumber(op)
 			for s := range want {
-				got[s] = fs.WhichOneof(s)
+				od := oneofDescs.ByName(s)
+				fd := m.WhichOneof(od)
+				if fd == nil {
+					got[s] = 0
+				} else {
+					got[s] = fd.Number()
+				}
 			}
 			if diff := cmp.Diff(want, got); diff != "" {
-				t.Errorf("operation %v, KnownFields.WhichOneof mismatch (-want, +got):\n%s", p, diff)
+				t.Errorf("operation %v, Message.WhichOneof mismatch (-want, +got):\n%s", p, diff)
 			}
 		case messageFields:
 			for n, tt := range op {
 				p.Push(int(n))
-				if !fs.Has(n) {
-					fs.Set(n, V(fs.NewMessage(n)))
-				}
-				testMessage(t, p, fs.Get(n).Message(), tt)
+				fd := fieldDescs.ByNumber(n)
+				testMessage(t, p, m.Get(fd).Message(), tt)
+				p.Pop()
+			}
+		case messageFieldsMutable:
+			for n, tt := range op {
+				p.Push(int(n))
+				fd := fieldDescs.ByNumber(n)
+				testMessage(t, p, m.Mutable(fd).Message(), tt)
 				p.Pop()
 			}
 		case listFields:
 			for n, tt := range op {
 				p.Push(int(n))
-				testLists(t, p, fs.Get(n).List(), tt)
+				fd := fieldDescs.ByNumber(n)
+				testLists(t, p, m.Get(fd).List(), tt)
+				p.Pop()
+			}
+		case listFieldsMutable:
+			for n, tt := range op {
+				p.Push(int(n))
+				fd := fieldDescs.ByNumber(n)
+				testLists(t, p, m.Mutable(fd).List(), tt)
 				p.Pop()
 			}
 		case mapFields:
 			for n, tt := range op {
 				p.Push(int(n))
-				testMaps(t, p, fs.Get(n).Map(), tt)
+				fd := fieldDescs.ByNumber(n)
+				testMaps(t, p, m.Get(fd).Map(), tt)
+				p.Pop()
+			}
+		case mapFieldsMutable:
+			for n, tt := range op {
+				p.Push(int(n))
+				fd := fieldDescs.ByNumber(n)
+				testMaps(t, p, m.Mutable(fd).Map(), tt)
 				p.Pop()
 			}
 		case rangeFields:
 			got := map[pref.FieldNumber]pref.Value{}
 			want := map[pref.FieldNumber]pref.Value(op)
-			fs.Range(func(n pref.FieldNumber, v pref.Value) bool {
-				got[n] = v
+			m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
+				got[fd.Number()] = v
 				return true
 			})
 			if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
-				t.Errorf("operation %v, KnownFields.Range mismatch (-want, +got):\n%s", p, diff)
+				t.Errorf("operation %v, Message.Range mismatch (-want, +got):\n%s", p, diff)
 			}
 		default:
 			t.Fatalf("operation %v, invalid operation: %T", p, op)
@@ -1334,7 +1316,7 @@
 		p.Push(i)
 		switch op := op.(type) {
 		case equalList:
-			if diff := cmp.Diff(op.List, v, cmpOpts); diff != "" {
+			if diff := cmp.Diff(V(op.List), V(v), cmpOpts); diff != "" {
 				t.Errorf("operation %v, list mismatch (-want, +got):\n%s", p, diff)
 			}
 		case lenList:
@@ -1376,7 +1358,7 @@
 		p.Push(i)
 		switch op := op.(type) {
 		case equalMap:
-			if diff := cmp.Diff(op.Map, m, cmpOpts); diff != "" {
+			if diff := cmp.Diff(V(op.Map), V(m), cmpOpts); diff != "" {
 				t.Errorf("operation %v, map mismatch (-want, +got):\n%s", p, diff)
 			}
 		case lenMap:
@@ -1434,6 +1416,11 @@
 	}
 }
 
+func getField(m pref.Message, n pref.FieldNumber) pref.Value {
+	fd := m.Descriptor().Fields().ByNumber(n)
+	return m.Get(fd)
+}
+
 type path []int
 
 func (p *path) Push(i int) { *p = append(*p, i) }