goprotobuf: Several optimisations:
  - avoid allocation in dec_slice_struct.
  - store backpointer to StructProperties in Properties to avoid calls to GetProperties.
  - speed up XXX_unrecognized operations.

R=adg
CC=golang-dev
http://codereview.appspot.com/6450135
diff --git a/proto/decode.go b/proto/decode.go
index c5b1ad7..1929747 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -213,7 +213,7 @@
 // Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
 // If the protocol buffer has extensions, and the field matches, add it as an extension.
 // Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
-func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base uintptr) error {
+func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base, unrecOffset uintptr) error {
 
 	oi := o.index
 
@@ -222,13 +222,11 @@
 		return err
 	}
 
-	x := fieldIndex(t, "XXX_unrecognized")
-	if x == nil {
+	if unrecOffset == 0 {
 		return nil
 	}
 
-	p := propByIndex(t, x)
-	ptr := (*[]byte)(unsafe.Pointer(base + p.offset))
+	ptr := (*[]byte)(unsafe.Pointer(base + unrecOffset))
 
 	if *ptr == nil {
 		// This is the first skipped element,
@@ -286,6 +284,8 @@
 }
 
 // Unmarshaler is the interface representing objects that can unmarshal themselves.
+// The argument points to data that may be overwritten, so implementations should
+// not keep references to the buffer.
 type Unmarshaler interface {
 	Unmarshal([]byte) error
 }
@@ -333,7 +333,7 @@
 		return err
 	}
 
-	err = p.unmarshalType(typ, false, base)
+	err = p.unmarshalType(typ, GetProperties(typ.Elem()), false, base)
 
 	if collectStats {
 		stats.Decode++
@@ -343,9 +343,8 @@
 }
 
 // unmarshalType does the work of unmarshaling a structure.
-func (o *Buffer) unmarshalType(t reflect.Type, is_group bool, base uintptr) error {
+func (o *Buffer) unmarshalType(t reflect.Type, prop *StructProperties, is_group bool, base uintptr) error {
 	st := t.Elem()
-	prop := GetProperties(st)
 	required, reqFields := prop.reqCount, uint64(0)
 
 	var err error
@@ -379,7 +378,7 @@
 				}
 				continue
 			}
-			err = o.skipAndSave(st, tag, wire, base)
+			err = o.skipAndSave(st, tag, wire, base, prop.unrecOffset)
 			continue
 		}
 		p := prop.Prop[fieldnum]
@@ -656,7 +655,7 @@
 	structv := unsafe.Pointer(bas)
 	*ptr = (*struct{})(structv)
 
-	err := o.unmarshalType(p.stype, true, bas)
+	err := o.unmarshalType(p.stype, p.sprop, true, bas)
 
 	return err
 }
@@ -685,7 +684,7 @@
 	o.buf = raw
 	o.index = 0
 
-	err = o.unmarshalType(p.stype, false, bas)
+	err = o.unmarshalType(p.stype, p.sprop, false, bas)
 	o.buf = obuf
 	o.index = oi
 
@@ -715,11 +714,11 @@
 	*v = y
 
 	if is_group {
-		err := o.unmarshalType(p.stype, is_group, bas)
+		err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
 		return err
 	}
 
-	raw, err := o.DecodeRawBytes(true)
+	raw, err := o.DecodeRawBytes(false)
 	if err != nil {
 		return err
 	}
@@ -735,7 +734,7 @@
 	o.buf = raw
 	o.index = 0
 
-	err = o.unmarshalType(p.stype, is_group, bas)
+	err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
 
 	o.buf = obuf
 	o.index = oi