]> Cypherpunks repositories - gostls13.git/commitdiff
go/internal/gcimporter: don't waste CPU copying bytes in `io.ReadAll`
authorSergey Zagursky <gvozdoder@gmail.com>
Fri, 4 Jun 2021 09:25:51 +0000 (12:25 +0300)
committerMatthew Dempsky <mdempsky@google.com>
Sat, 5 Jun 2021 09:28:43 +0000 (09:28 +0000)
`io.ReadAll` dynamically reallocates byte slice because it doesn't know
its size in advance. We don't need to read an entire file into memory
and therefore may use `bufio.Reader` to read its contents.

Fixes #46564

Change-Id: Id504b1512662b6dea4775d523455896fa4162ab3
Reviewed-on: https://go-review.googlesource.com/c/go/+/325429
Reviewed-by: Dominik Honnef <dominik@honnef.co>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Dominik Honnef <dominik@honnef.co>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/go/internal/gcimporter/gcimporter.go
src/go/internal/gcimporter/iimport.go

index b74daca246374542f6fa60362eb7f820930cedf9..73cf6334fd65e681aafe7d97b986de0b5dd8ed29 100644 (file)
@@ -145,17 +145,14 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi
                err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
 
        case "$$B\n":
-               var data []byte
-               data, err = io.ReadAll(buf)
-               if err != nil {
-                       break
-               }
+               var exportFormat byte
+               exportFormat, err = buf.ReadByte()
 
                // The indexed export format starts with an 'i'; the older
                // binary export format starts with a 'c', 'd', or 'v'
                // (from "version"). Select appropriate importer.
-               if len(data) > 0 && data[0] == 'i' {
-                       _, pkg, err = iImportData(fset, packages, data[1:], id)
+               if err == nil && exportFormat == 'i' {
+                       pkg, err = iImportData(fset, packages, buf, id)
                } else {
                        err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
                }
index a3184e7641aa01d793275a4daca78ae59f47eef1..76d47d08f1f88a9a11a4761604aba4d753d5fe5f 100644 (file)
@@ -8,6 +8,7 @@
 package gcimporter
 
 import (
+       "bufio"
        "bytes"
        "encoding/binary"
        "fmt"
@@ -20,7 +21,7 @@ import (
 )
 
 type intReader struct {
-       *bytes.Reader
+       *bufio.Reader
        path string
 }
 
@@ -61,7 +62,7 @@ const (
 // and returns the number of bytes consumed and a reference to the package.
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
-func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
+func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataReader *bufio.Reader, path string) (pkg *types.Package, err error) {
        const currentVersion = 1
        version := int64(-1)
        defer func() {
@@ -74,7 +75,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
                }
        }()
 
-       r := &intReader{bytes.NewReader(data), path}
+       r := &intReader{dataReader, path}
 
        version = int64(r.uint64())
        switch version {
@@ -86,10 +87,12 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
        sLen := int64(r.uint64())
        dLen := int64(r.uint64())
 
-       whence, _ := r.Seek(0, io.SeekCurrent)
-       stringData := data[whence : whence+sLen]
-       declData := data[whence+sLen : whence+sLen+dLen]
-       r.Seek(sLen+dLen, io.SeekCurrent)
+       data := make([]byte, sLen+dLen)
+       if _, err := io.ReadFull(r, data); err != nil {
+               errorf("cannot read %d bytes of stringData and declData: %s", len(data), err)
+       }
+       stringData := data[:sLen]
+       declData := data[sLen:]
 
        p := iimporter{
                ipath:   path,
@@ -165,9 +168,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
        // package was imported completely and without errors
        localpkg.MarkComplete()
-
-       consumed, _ := r.Seek(0, io.SeekCurrent)
-       return int(consumed), localpkg, nil
+       return localpkg, nil
 }
 
 type iimporter struct {