goprotobuf: remove unsafe buffer scratch allocator
This is part of the work towards making protobufs run on App Engine.
By the way, it's faster now.

Before:
proto_test.BenchmarkUnmarshal	   20000	     87053 ns/op
After:
proto_test.BenchmarkUnmarshal	   20000	     84825 ns/op

R=dsymonds, rsc, ken, r
CC=golang-dev
http://codereview.appspot.com/5310048
diff --git a/proto/decode.go b/proto/decode.go
index fe28821..fd3960d 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -333,7 +333,6 @@
 	st := t.Elem()
 	prop := GetProperties(st)
 	required, reqFields := prop.reqCount, uint64(0)
-	sbase := getsbase(prop) // scratch area for data items
 
 	var err os.Error
 	for err == nil && o.index < len(o.buf) {
@@ -354,7 +353,7 @@
 		fieldnum, ok := prop.tags[tag]
 		if !ok {
 			// Maybe it's an extension?
-			o.ptr = base
+			o.ptr = base // copy the address here to avoid a heap allocation.
 			iv := unsafe.Unreflect(t, unsafe.Pointer(&o.ptr))
 			if e, ok := iv.(extendableProto); ok && isExtensionField(e, int32(tag)) {
 				if err = o.skip(st, tag, wire); err == nil {
@@ -381,7 +380,7 @@
 				continue
 			}
 		}
-		err = dec(o, p, base, sbase)
+		err = dec(o, p, base)
 		if err == nil && p.Required {
 			// Successfully decoded a required field.
 			if tag <= 64 {
@@ -424,100 +423,102 @@
 // For each,
 //	u is the decoded value,
 //	v is a pointer to the field (pointer) in the struct
-//	x is a pointer to the preallocated scratch space to hold the decoded value.
+
+// Sizes of the pools to allocate inside the Buffer.
+// The goal is modest amortization and allocation on at lest 16-byte boundaries.
+const (
+	boolPoolSize = 16
+	int32PoolSize = 8
+	int64PoolSize = 4
+)
 
 // Decode a bool.
-func (o *Buffer) dec_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_bool(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
-	v := (**uint8)(unsafe.Pointer(base + p.offset))
-	x := (*uint8)(unsafe.Pointer(sbase + p.scratch))
-	*x = uint8(u)
-	*v = x
+	if len(o.bools) == 0 {
+		o.bools = make([]bool, boolPoolSize)
+	}
+	o.bools[0] = u != 0
+	v := (**bool)(unsafe.Pointer(base + p.offset))
+	*v = &o.bools[0]
+	o.bools = o.bools[1:]
 	return nil
 }
 
 // Decode an int32.
-func (o *Buffer) dec_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_int32(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
+	if len(o.int32s) == 0 {
+		o.int32s = make([]int32, int32PoolSize)
+	}
+	o.int32s[0] = int32(u)
 	v := (**int32)(unsafe.Pointer(base + p.offset))
-	x := (*int32)(unsafe.Pointer(sbase + p.scratch))
-	*x = int32(u)
-	*v = x
+	*v = &o.int32s[0]
+	o.int32s = o.int32s[1:]
 	return nil
 }
 
 // Decode an int64.
-func (o *Buffer) dec_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_int64(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
+	if len(o.int64s) == 0 {
+		o.int64s = make([]int64, int64PoolSize)
+	}
+	o.int64s[0] = int64(u)
 	v := (**int64)(unsafe.Pointer(base + p.offset))
-	x := (*int64)(unsafe.Pointer(sbase + p.scratch))
-	*x = int64(u)
-	*v = x
+	*v = &o.int64s[0]
+	o.int64s = o.int64s[1:]
 	return nil
 }
 
 // Decode a string.
-func (o *Buffer) dec_string(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_string(p *Properties, base uintptr) os.Error {
 	s, err := o.DecodeStringBytes()
 	if err != nil {
 		return err
 	}
+	sp := new(string)
+	*sp = s
 	v := (**string)(unsafe.Pointer(base + p.offset))
-	x := (*string)(unsafe.Pointer(sbase + p.scratch))
-	*x = s
-	*v = x
+	*v = sp
 	return nil
 }
 
 // Decode a slice of bytes ([]byte).
-func (o *Buffer) dec_slice_byte(p *Properties, base uintptr, sbase uintptr) os.Error {
-	b, err := o.DecodeRawBytes(false)
+func (o *Buffer) dec_slice_byte(p *Properties, base uintptr) os.Error {
+	b, err := o.DecodeRawBytes(true)
 	if err != nil {
 		return err
 	}
 
-	x := (*[]uint8)(unsafe.Pointer(base + p.offset))
-
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, b...)
+	v := (*[]byte)(unsafe.Pointer(base + p.offset))
+	*v = b
 	return nil
 }
 
 // Decode a slice of bools ([]bool).
-func (o *Buffer) dec_slice_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_bool(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
-	x := (*[]bool)(unsafe.Pointer(base + p.offset))
-
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, u != 0)
+	v := (*[]bool)(unsafe.Pointer(base + p.offset))
+	*v = append(*v, u != 0)
 	return nil
 }
 
 // Decode a slice of bools ([]bool) in packed format.
-func (o *Buffer) dec_slice_packed_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
-	x := (*[]bool)(unsafe.Pointer(base + p.offset))
+func (o *Buffer) dec_slice_packed_bool(p *Properties, base uintptr) os.Error {
+	v := (*[]bool)(unsafe.Pointer(base + p.offset))
 
 	nn, err := o.DecodeVarint()
 	if err != nil {
@@ -525,12 +526,7 @@
 	}
 	nb := int(nn) // number of bytes of encoded bools
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
+	y := *v
 	for i := 0; i < nb; i++ {
 		u, err := p.valDec(o)
 		if err != nil {
@@ -539,31 +535,24 @@
 		y = append(y, u != 0)
 	}
 
-	*x = y
+	*v = y
 	return nil
 }
 
 // Decode a slice of int32s ([]int32).
-func (o *Buffer) dec_slice_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_int32(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
-	x := (*[]int32)(unsafe.Pointer(base + p.offset))
-
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, int32(u))
+	v := (*[]int32)(unsafe.Pointer(base + p.offset))
+	*v = append(*v, int32(u))
 	return nil
 }
 
 // Decode a slice of int32s ([]int32) in packed format.
-func (o *Buffer) dec_slice_packed_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
-	x := (*[]int32)(unsafe.Pointer(base + p.offset))
+func (o *Buffer) dec_slice_packed_int32(p *Properties, base uintptr) os.Error {
+	v := (*[]int32)(unsafe.Pointer(base + p.offset))
 
 	nn, err := o.DecodeVarint()
 	if err != nil {
@@ -571,11 +560,7 @@
 	}
 	nb := int(nn) // number of bytes of encoded int32s
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
+	y := *v
 
 	fin := o.index + nb
 	for o.index < fin {
@@ -586,31 +571,26 @@
 		y = append(y, int32(u))
 	}
 
-	*x = y
+	*v = y
 	return nil
 }
 
 // Decode a slice of int64s ([]int64).
-func (o *Buffer) dec_slice_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_int64(p *Properties, base uintptr) os.Error {
 	u, err := p.valDec(o)
 	if err != nil {
 		return err
 	}
-	x := (*[]int64)(unsafe.Pointer(base + p.offset))
+	v := (*[]int64)(unsafe.Pointer(base + p.offset))
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, int64(u))
+	y := *v
+	*v = append(y, int64(u))
 	return nil
 }
 
 // Decode a slice of int64s ([]int64) in packed format.
-func (o *Buffer) dec_slice_packed_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
-	x := (*[]int64)(unsafe.Pointer(base + p.offset))
+func (o *Buffer) dec_slice_packed_int64(p *Properties, base uintptr) os.Error {
+	v := (*[]int64)(unsafe.Pointer(base + p.offset))
 
 	nn, err := o.DecodeVarint()
 	if err != nil {
@@ -618,12 +598,7 @@
 	}
 	nb := int(nn) // number of bytes of encoded int64s
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
+	y := *v
 	fin := o.index + nb
 	for o.index < fin {
 		u, err := p.valDec(o)
@@ -633,48 +608,38 @@
 		y = append(y, int64(u))
 	}
 
-	*x = y
+	*v = y
 	return nil
 }
 
 // Decode a slice of strings ([]string).
-func (o *Buffer) dec_slice_string(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_string(p *Properties, base uintptr) os.Error {
 	s, err := o.DecodeStringBytes()
 	if err != nil {
 		return err
 	}
-	x := (*[]string)(unsafe.Pointer(base + p.offset))
+	v := (*[]string)(unsafe.Pointer(base + p.offset))
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, s)
+	y := *v
+	*v = append(y, s)
 	return nil
 }
 
 // Decode a slice of slice of bytes ([][]byte).
-func (o *Buffer) dec_slice_slice_byte(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_slice_byte(p *Properties, base uintptr) os.Error {
 	b, err := o.DecodeRawBytes(true)
 	if err != nil {
 		return err
 	}
-	x := (*[][]byte)(unsafe.Pointer(base + p.offset))
+	v := (*[][]byte)(unsafe.Pointer(base + p.offset))
 
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
-
-	*x = append(y, b)
+	y := *v
+	*v = append(y, b)
 	return nil
 }
 
 // Decode a group.
-func (o *Buffer) dec_struct_group(p *Properties, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_struct_group(p *Properties, base uintptr) os.Error {
 	ptr := (**struct{})(unsafe.Pointer(base + p.offset))
 	typ := p.stype.Elem()
 	structv := unsafe.New(typ)
@@ -687,7 +652,7 @@
 }
 
 // Decode an embedded message.
-func (o *Buffer) dec_struct_message(p *Properties, base uintptr, sbase uintptr) (err os.Error) {
+func (o *Buffer) dec_struct_message(p *Properties, base uintptr) (err os.Error) {
 	raw, e := o.DecodeRawBytes(false)
 	if e != nil {
 		return e
@@ -718,30 +683,26 @@
 }
 
 // Decode a slice of embedded messages.
-func (o *Buffer) dec_slice_struct_message(p *Properties, base uintptr, sbase uintptr) os.Error {
-	return o.dec_slice_struct(p, false, base, sbase)
+func (o *Buffer) dec_slice_struct_message(p *Properties, base uintptr) os.Error {
+	return o.dec_slice_struct(p, false, base)
 }
 
 // Decode a slice of embedded groups.
-func (o *Buffer) dec_slice_struct_group(p *Properties, base uintptr, sbase uintptr) os.Error {
-	return o.dec_slice_struct(p, true, base, sbase)
+func (o *Buffer) dec_slice_struct_group(p *Properties, base uintptr) os.Error {
+	return o.dec_slice_struct(p, true, base)
 }
 
 // Decode a slice of structs ([]*struct).
-func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base uintptr, sbase uintptr) os.Error {
+func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base uintptr) os.Error {
 
-	x := (*[]*struct{})(unsafe.Pointer(base + p.offset))
-	y := *x
-	if cap(y) == 0 {
-		initSlice(unsafe.Pointer(x), sbase+p.scratch)
-		y = *x
-	}
+	v := (*[]*struct{})(unsafe.Pointer(base + p.offset))
+	y := *v
 
 	typ := p.stype.Elem()
 	structv := unsafe.New(typ)
 	bas := uintptr(structv)
 	y = append(y, (*struct{})(structv))
-	*x = y
+	*v = y
 
 	if is_group {
 		err := o.unmarshalType(p.stype, is_group, bas)
diff --git a/proto/encode.go b/proto/encode.go
index e2141c0..73f2eff 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -152,8 +152,7 @@
 // This is the format used for the bytes protocol buffer
 // type and for embedded messages.
 func (p *Buffer) EncodeRawBytes(b []byte) os.Error {
-	lb := len(b)
-	p.EncodeVarint(uint64(lb))
+	p.EncodeVarint(uint64(len(b)))
 	p.buf = append(p.buf, b...)
 	return nil
 }
@@ -161,10 +160,8 @@
 // EncodeStringBytes writes an encoded string to the Buffer.
 // This is the format used for the proto2 string type.
 func (p *Buffer) EncodeStringBytes(s string) os.Error {
-
-	// this works because strings and slices are the same.
-	y := *(*[]byte)(unsafe.Pointer(&s))
-	p.EncodeRawBytes(y)
+	p.EncodeVarint(uint64(len(s)))
+	p.buf = append(p.buf, s...)
 	return nil
 }
 
diff --git a/proto/extensions.go b/proto/extensions.go
index d329b90..f1c52cc 100644
--- a/proto/extensions.go
+++ b/proto/extensions.go
@@ -31,7 +31,6 @@
 
 package proto
 
-
 /*
  * Types and routines for supporting protocol buffer extensions.
  */
@@ -200,14 +199,11 @@
 	props.Init(t, "irrelevant_name", extension.Tag, 0)
 
 	base := unsafe.New(t)
-	var sbase uintptr
 	if t.Elem().Kind() == reflect.Struct {
-		// props.dec will be dec_struct_message, which does not refer to sbase.
+		// props.dec will be dec_struct_message.
 		*(*unsafe.Pointer)(base) = unsafe.New(t.Elem())
-	} else {
-		sbase = uintptr(unsafe.New(t.Elem()))
 	}
-	if err := props.dec(o, props, uintptr(base), sbase); err != nil {
+	if err := props.dec(o, props, uintptr(base)); err != nil {
 		return nil, err
 	}
 	return unsafe.Unreflect(t, base), nil
diff --git a/proto/lib.go b/proto/lib.go
index b816e91..a24c780 100644
--- a/proto/lib.go
+++ b/proto/lib.go
@@ -198,7 +198,11 @@
 	index     int        // write point
 	freelist  [10][]byte // list of available buffers
 	nfreelist int        // number of free buffers
-	ptr       uintptr    // scratch area for pointers
+	ptr uintptr // used to avoid a heap allocation.
+	// pools of basic types to amortize allocation.
+	bools []bool
+	int32s []int32
+	int64s []int64
 }
 
 // NewBuffer allocates a new Buffer and initializes its internal data to
diff --git a/proto/properties.go b/proto/properties.go
index b64481d..fc24517 100644
--- a/proto/properties.go
+++ b/proto/properties.go
@@ -71,7 +71,7 @@
 // Decoders are defined in decode.go
 // A decoder creates a value from its wire representation.
 // Unrecognized subelements are saved in unrec.
-type decoder func(p *Buffer, prop *Properties, base uintptr, sbase uintptr) os.Error
+type decoder func(p *Buffer, prop *Properties, base uintptr) os.Error
 
 // A valueDecoder decodes a single integer in a particular encoding.
 type valueDecoder func(o *Buffer) (x uint64, err os.Error)
@@ -83,7 +83,6 @@
 	tags      map[int]int    // map from proto tag to struct field number
 	origNames map[string]int // map from original name to struct field number
 	order     []int          // list of struct field numbers in tag order
-	nscratch  uintptr        // size of scratch space
 }
 
 // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
@@ -117,11 +116,8 @@
 	tagbuf  [8]byte
 	stype   reflect.Type
 
-	dec     decoder
-	valDec  valueDecoder // set for bool and numeric types only
-	scratch uintptr
-	sizeof  uintptr // calculations of scratch space
-	alignof uintptr
+	dec    decoder
+	valDec valueDecoder // set for bool and numeric types only
 
 	// If this is a packable field, this will be the decoder for the packed version of the field.
 	packedDec decoder
@@ -233,15 +229,6 @@
 
 // Initialize the fields for encoding and decoding.
 func (p *Properties) setEncAndDec(typ reflect.Type) {
-	var vbool bool
-	var vbyte byte
-	var vint32 int32
-	var vint64 int64
-	var vfloat32 float32
-	var vfloat64 float64
-	var vstring string
-	var vslice []byte
-
 	p.enc = nil
 	p.dec = nil
 
@@ -258,33 +245,21 @@
 		case reflect.Bool:
 			p.enc = (*Buffer).enc_bool
 			p.dec = (*Buffer).dec_bool
-			p.alignof = unsafe.Alignof(vbool)
-			p.sizeof = unsafe.Sizeof(vbool)
 		case reflect.Int32, reflect.Uint32:
 			p.enc = (*Buffer).enc_int32
 			p.dec = (*Buffer).dec_int32
-			p.alignof = unsafe.Alignof(vint32)
-			p.sizeof = unsafe.Sizeof(vint32)
 		case reflect.Int64, reflect.Uint64:
 			p.enc = (*Buffer).enc_int64
 			p.dec = (*Buffer).dec_int64
-			p.alignof = unsafe.Alignof(vint64)
-			p.sizeof = unsafe.Sizeof(vint64)
 		case reflect.Float32:
 			p.enc = (*Buffer).enc_int32 // can just treat them as bits
 			p.dec = (*Buffer).dec_int32
-			p.alignof = unsafe.Alignof(vfloat32)
-			p.sizeof = unsafe.Sizeof(vfloat32)
 		case reflect.Float64:
 			p.enc = (*Buffer).enc_int64 // can just treat them as bits
 			p.dec = (*Buffer).dec_int64
-			p.alignof = unsafe.Alignof(vfloat64)
-			p.sizeof = unsafe.Sizeof(vfloat64)
 		case reflect.String:
 			p.enc = (*Buffer).enc_string
 			p.dec = (*Buffer).dec_string
-			p.alignof = unsafe.Alignof(vstring)
-			p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
 		case reflect.Struct:
 			p.stype = t1
 			if p.Wire == "bytes" {
@@ -309,8 +284,6 @@
 			}
 			p.dec = (*Buffer).dec_slice_bool
 			p.packedDec = (*Buffer).dec_slice_packed_bool
-			p.alignof = unsafe.Alignof(vbool)
-			p.sizeof = startSize * unsafe.Sizeof(vbool)
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 			switch t2.Bits() {
 			case 32:
@@ -321,8 +294,6 @@
 				}
 				p.dec = (*Buffer).dec_slice_int32
 				p.packedDec = (*Buffer).dec_slice_packed_int32
-				p.alignof = unsafe.Alignof(vint32)
-				p.sizeof = startSize * unsafe.Sizeof(vint32)
 			case 64:
 				if p.Packed {
 					p.enc = (*Buffer).enc_slice_packed_int64
@@ -331,14 +302,10 @@
 				}
 				p.dec = (*Buffer).dec_slice_int64
 				p.packedDec = (*Buffer).dec_slice_packed_int64
-				p.alignof = unsafe.Alignof(vint64)
-				p.sizeof = startSize * unsafe.Sizeof(vint64)
 			case 8:
 				if t2.Kind() == reflect.Uint8 {
 					p.enc = (*Buffer).enc_slice_byte
 					p.dec = (*Buffer).dec_slice_byte
-					p.alignof = unsafe.Alignof(vbyte)
-					p.sizeof = startSize * unsafe.Sizeof(vbyte)
 				}
 			default:
 				logNoSliceEnc(t1, t2)
@@ -355,8 +322,6 @@
 				}
 				p.dec = (*Buffer).dec_slice_int32
 				p.packedDec = (*Buffer).dec_slice_packed_int32
-				p.alignof = unsafe.Alignof(vfloat32)
-				p.sizeof = startSize * unsafe.Sizeof(vfloat32)
 			case 64:
 				// can just treat them as bits
 				if p.Packed {
@@ -366,8 +331,6 @@
 				}
 				p.dec = (*Buffer).dec_slice_int64
 				p.packedDec = (*Buffer).dec_slice_packed_int64
-				p.alignof = unsafe.Alignof(vfloat64)
-				p.sizeof = startSize * unsafe.Sizeof(vfloat64)
 			default:
 				logNoSliceEnc(t1, t2)
 				break
@@ -375,8 +338,6 @@
 		case reflect.String:
 			p.enc = (*Buffer).enc_slice_string
 			p.dec = (*Buffer).dec_slice_string
-			p.alignof = unsafe.Alignof(vstring)
-			p.sizeof = startSize * unsafe.Sizeof(vstring)
 		case reflect.Ptr:
 			switch t3 := t2.Elem(); t3.Kind() {
 			default:
@@ -390,8 +351,6 @@
 					p.enc = (*Buffer).enc_slice_struct_message
 					p.dec = (*Buffer).dec_slice_struct_message
 				}
-				p.alignof = unsafe.Alignof(vslice)
-				p.sizeof = startSize * unsafe.Sizeof(vslice)
 			}
 		case reflect.Slice:
 			switch t2.Elem().Kind() {
@@ -401,8 +360,6 @@
 			case reflect.Uint8:
 				p.enc = (*Buffer).enc_slice_slice_byte
 				p.dec = (*Buffer).dec_slice_slice_byte
-				p.alignof = unsafe.Alignof(vslice)
-				p.sizeof = startSize * unsafe.Sizeof(vslice)
 			}
 		}
 	}
@@ -461,11 +418,8 @@
 		p := new(Properties)
 		p.Init(f.Type, f.Name, f.Tag.Get("protobuf"), f.Offset)
 		if f.Name == "XXX_extensions" { // special case
-			var vmap map[int32][]byte
 			p.enc = (*Buffer).enc_map
 			p.dec = nil // not needed
-			p.alignof = unsafe.Alignof(vmap)
-			p.sizeof = unsafe.Sizeof(vmap)
 		}
 		prop.Prop[i] = p
 		prop.order[i] = i
@@ -485,41 +439,24 @@
 	sort.Sort(prop)
 
 	// build required counts
-	// build scratch offsets
 	// build tags
 	reqCount := 0
-	scratch := uintptr(0)
 	prop.tags = make(map[int]int)
 	prop.origNames = make(map[string]int)
 	for i, p := range prop.Prop {
 		if p.Required {
 			reqCount++
 		}
-		scratch = align(scratch, p.alignof)
-		p.scratch = scratch
-		scratch += p.sizeof
 		prop.tags[p.Tag] = i
 		prop.origNames[p.OrigName] = i
 	}
 	prop.reqCount = reqCount
-	prop.nscratch = scratch
 
 	propertiesMap[t] = prop
 	mutex.Unlock()
 	return prop
 }
 
-// Alignment of the data in the scratch area.  It doesn't have to be
-// exact, just conservative.  Returns the first number >= o that divides s.
-func align(o uintptr, s uintptr) uintptr {
-	if s != 0 {
-		for o%uintptr(s) != 0 {
-			o++
-		}
-	}
-	return o
-}
-
 // Return the field index of the named field.
 // Returns nil if there is no such field.
 func fieldIndex(t reflect.Type, name string) []int {
@@ -555,23 +492,6 @@
 	return
 }
 
-// Allocate the aux space containing all the decoded data.  The structure
-// handed into Unmarshal is filled with pointers to this newly allocated
-// data.
-func getsbase(prop *StructProperties) uintptr {
-	var vbyteptr *byte
-	if prop.nscratch == 0 {
-		return 0
-	}
-
-	// allocate the decode space as pointers
-	// so that the GC will scan it for pointers
-	n := uintptr(unsafe.Sizeof(vbyteptr))
-	b := make([]*byte, (prop.nscratch+n-1)/n)
-	sbase := uintptr(unsafe.Pointer(&b[0]))
-	return sbase
-}
-
 // A global registry of enum types.
 // The generated code will register the generated maps by calling RegisterEnum.