secure/bidirule: lazily precompute ASCII table

Precomputing the ASCII table in init makes the bidirule init path
reachable even when bidirule is not otherwise used. In a program that
blank-imports golang.org/x/net/idna, this keeps the unicode/bidi
lookup tables in the binary.

Initialize the table on first validation use instead. This cuts about
16 KiB from an unstripped darwin/arm64 binary for that program, with
no noticeable change in BenchmarkSpan.

Updates golang/go#38311

Change-Id: I46f347bdf9ba1bab16940a61e264c60bb5a0ab1a
Reviewed-on: https://go-review.googlesource.com/c/text/+/822824
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
diff --git a/secure/bidirule/bidirule.go b/secure/bidirule/bidirule.go
index 5386327..399cb89 100644
--- a/secure/bidirule/bidirule.go
+++ b/secure/bidirule/bidirule.go
@@ -10,6 +10,7 @@
 
 import (
 	"errors"
+	"sync"
 	"unicode/utf8"
 
 	"golang.org/x/text/transform"
@@ -246,8 +247,9 @@
 // Precomputing the ASCII values decreases running time for the ASCII fast path
 // by about 30%.
 var asciiTable [128]bidi.Properties
+var asciiTableOnce sync.Once
 
-func init() {
+func initASCIITable() {
 	for i := range asciiTable {
 		p, _ := bidi.LookupRune(rune(i))
 		asciiTable[i] = p
@@ -255,6 +257,8 @@
 }
 
 func (t *Transformer) advance(s []byte) (n int, ok bool) {
+	asciiTableOnce.Do(initASCIITable)
+
 	var e bidi.Properties
 	var sz int
 	for n < len(s) {
@@ -297,6 +301,8 @@
 }
 
 func (t *Transformer) advanceString(s string) (n int, ok bool) {
+	asciiTableOnce.Do(initASCIITable)
+
 	var e bidi.Properties
 	var sz int
 	for n < len(s) {