runtime: use typed memmove (write barriers) for chan, map, interface content

Found with GODEBUG=wbshadow=2 mode.
Eventually that will run automatically, but right now
it still detects other missing write barriers.

Change-Id: Iea83d693480c2f3008b4e80d55821acff65970a6
Reviewed-on: https://go-review.googlesource.com/2277
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index f62e51a..db3dbdb 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -132,16 +132,15 @@
 }
 
 func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
-	size := uintptr(t.size)
 	ep := (*eface)(unsafe.Pointer(&e))
 	if isDirectIface(t) {
 		ep._type = t
-		memmove(unsafe.Pointer(&ep.data), elem, size)
+		typedmemmove(t, unsafe.Pointer(&ep.data), elem)
 	} else {
 		x := newobject(t)
 		// TODO: We allocate a zeroed object only to overwrite it with
 		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
-		memmove(x, elem, size)
+		typedmemmove(t, x, elem)
 		ep._type = t
 		ep.data = x
 	}
@@ -154,14 +153,13 @@
 		tab = getitab(inter, t, false)
 		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
 	}
-	size := uintptr(t.size)
 	pi := (*iface)(unsafe.Pointer(&i))
 	if isDirectIface(t) {
 		pi.tab = tab
-		memmove(unsafe.Pointer(&pi.data), elem, size)
+		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
 	} else {
 		x := newobject(t)
-		memmove(x, elem, size)
+		typedmemmove(t, x, elem)
 		pi.tab = tab
 		pi.data = x
 	}
@@ -180,11 +178,15 @@
 	if tab._type != t {
 		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
 	}
-	size := uintptr(t.size)
+	// NOTE(rsc): If this changes to take a pointer argument
+	// instead of using &r, these calls need to change to be
+	// typedmemmove (the first can be just writebarrierptr).
+	// Until then, it is very important that no blocking operation
+	// happens between the memmove and the return.
 	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size))
 	} else {
-		memmove(unsafe.Pointer(&r), ip.data, size)
+		memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size))
 	}
 	return
 }
@@ -192,19 +194,23 @@
 //go:nosplit
 func assertI2T2(t *_type, i fInterface) (r byte) {
 	ip := (*iface)(unsafe.Pointer(&i))
-	size := uintptr(t.size)
-	ok := (*bool)(add(unsafe.Pointer(&r), size))
+	ok := (*bool)(add(unsafe.Pointer(&r), uintptr(t.size)))
 	tab := ip.tab
 	if tab == nil || tab._type != t {
 		*ok = false
-		memclr(unsafe.Pointer(&r), size)
+		memclr(unsafe.Pointer(&r), uintptr(t.size))
 		return
 	}
 	*ok = true
+	// NOTE(rsc): If this changes to take a pointer argument
+	// instead of using &r, these calls need to change to be
+	// typedmemmove (the first can be just writebarrierptr).
+	// Until then, it is very important that no blocking operation
+	// happens between the memmove and the return.
 	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size))
 	} else {
-		memmove(unsafe.Pointer(&r), ip.data, size)
+		memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size))
 	}
 	return
 }
@@ -224,11 +230,15 @@
 	if ep._type != t {
 		panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
 	}
-	size := uintptr(t.size)
+	// NOTE(rsc): If this changes to take a pointer argument
+	// instead of using &r, these calls need to change to be
+	// typedmemmove (the first can be just writebarrierptr).
+	// Until then, it is very important that no blocking operation
+	// happens between the memmove and the return.
 	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), uintptr(t.size))
 	} else {
-		memmove(unsafe.Pointer(&r), ep.data, size)
+		memmove(unsafe.Pointer(&r), ep.data, uintptr(t.size))
 	}
 	return
 }
@@ -244,6 +254,11 @@
 		return
 	}
 	*ok = true
+	// NOTE(rsc): If this changes to take a pointer argument
+	// instead of using &r, these calls need to change to be
+	// typedmemmove (the first can be just writebarrierptr).
+	// Until then, it is very important that no blocking operation
+	// happens between the memmove and the return.
 	if isDirectIface(t) {
 		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
 	} else {