http2/hpack: reduce memory for huffman decoding table

Reduces process-wide heap (inuse_space) by 60kB by using a pointer to
a fixed-sized array instead of a slice of a fixed size.

Before:
119.44kB 23.43% 23.43%   147.88kB 29.01%  golang.org/x/net/http2/hpack.addDecoderNode

After:
 59.72kB 13.28% 39.85%    87.94kB 19.56%  golang.org/x/net/http2/hpack.addDecoderNode

(This is all work from an init func in http2/hpack)

Doesn't seem to affect runtime performance.

Measured with:

$ cat huffman_test.go
package main

import (
        "testing"

        _ "golang.org/x/net/http2"
        )

func TestMem(t *testing.T) {}

$ GODEBUG=memprofilerate=1 go test -memprofilerate=1 -memprofile=mem.prof -v .
=== RUN   TestMem
--- PASS: TestMem (0.00s)
PASS
ok      huffmem 0.052s

$ go tool pprof --inuse_space mem.prof

Change-Id: I5e56a5a2682f1063c955b342b37e97ca4c303dab
Reviewed-on: https://go-review.googlesource.com/127235
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/http2/hpack/hpack_test.go b/http2/hpack/hpack_test.go
index 974c35f..3f22274 100644
--- a/http2/hpack/hpack_test.go
+++ b/http2/hpack/hpack_test.go
@@ -462,6 +462,27 @@
 	}
 }
 
+func BenchmarkHuffmanDecode(b *testing.B) {
+	b.StopTimer()
+	enc, err := hex.DecodeString(strings.Replace("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
+		" ", "", -1))
+	if err != nil {
+		b.Fatal(err)
+	}
+	b.ReportAllocs()
+	b.StartTimer()
+	var buf bytes.Buffer
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		if _, err := HuffmanDecode(&buf, enc); err != nil {
+			b.Fatalf("decode error: %v", err)
+		}
+		if string(buf.Bytes()) != "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1" {
+			b.Fatalf("bogus output %q", buf.Bytes())
+		}
+	}
+}
+
 func TestAppendHuffmanString(t *testing.T) {
 	tests := []struct {
 		in, want string
diff --git a/http2/hpack/huffman.go b/http2/hpack/huffman.go
index 8850e39..87ec2aa 100644
--- a/http2/hpack/huffman.go
+++ b/http2/hpack/huffman.go
@@ -106,7 +106,7 @@
 
 type node struct {
 	// children is non-nil for internal nodes
-	children []*node
+	children *[256]*node
 
 	// The following are only valid if children is nil:
 	codeLen uint8 // number of bits that led to the output of sym
@@ -114,7 +114,7 @@
 }
 
 func newInternalNode() *node {
-	return &node{children: make([]*node, 256)}
+	return &node{children: new([256]*node)}
 }
 
 var rootHuffmanNode = newInternalNode()