x86/x86asm: make x86asm.Decode thread-safe

Moves initialization of the decoderCover variable from happening
unconditionally to only being initialized by the test code using it so
that it does not cause a data race when not being used and Decode is
called in parallel.

Fixes golang/go#33532

Change-Id: I64d748f94d135f0c1f55f1456ff770ac5205c85a
GitHub-Last-Rev: 679e78ed1daf3ddbd03792155e3be90b7b498fc4
GitHub-Pull-Request: golang/arch#4
Reviewed-on: https://go-review.googlesource.com/c/arch/+/189919
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/x86/x86asm/decode.go b/x86/x86asm/decode.go
index 250000e..8c98497 100644
--- a/x86/x86asm/decode.go
+++ b/x86/x86asm/decode.go
@@ -218,7 +218,6 @@
 
 // decoderCover records coverage information for which parts
 // of the byte code have been executed.
-// TODO(rsc): This is for testing. Only use this if a flag is given.
 var decoderCover []bool
 
 // Decode decodes the leading bytes in src as a single instruction.
@@ -462,9 +461,6 @@
 	// opshift gives the shift to use when saving the next
 	// opcode byte into inst.Opcode.
 	opshift = 24
-	if decoderCover == nil {
-		decoderCover = make([]bool, len(decoder))
-	}
 
 	// Decode loop, executing decoder program.
 	var oldPC, prevPC int
@@ -476,7 +472,9 @@
 			println("run", pc)
 		}
 		x := decoder[pc]
-		decoderCover[pc] = true
+		if decoderCover != nil {
+			decoderCover[pc] = true
+		}
 		pc++
 
 		// Read and decode ModR/M if needed by opcode.
diff --git a/x86/x86asm/ext_test.go b/x86/x86asm/ext_test.go
index 526ef5a..e63f113 100644
--- a/x86/x86asm/ext_test.go
+++ b/x86/x86asm/ext_test.go
@@ -100,6 +100,11 @@
 	generate func(f func([]byte)),
 	allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool,
 ) {
+	decoderCover = make([]bool, len(decoder))
+	defer func() {
+		decoderCover = nil
+	}()
+
 	start := time.Now()
 	ext := &ExtDis{
 		Dec:  make(chan ExtInst),