Skip to content

Commit 83cac16

Browse files
committed
internal/go/gcexportdata: read file directly when possible
1 parent 0295cbe commit 83cac16

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

internal/go/gcexportdata/gcexportdata.go

+41-4
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,32 @@ import (
2828
"go/types"
2929
"io"
3030
"io/ioutil"
31+
"os"
3132

3233
"honnef.co/go/tools/internal/go/gcimporter"
3334
)
3435

36+
type bufferedReader struct {
37+
r io.Reader
38+
buf *bufio.Reader
39+
}
40+
41+
func (r *bufferedReader) Read(b []byte) (int, error) {
42+
return r.buf.Read(b)
43+
}
44+
45+
func (r *bufferedReader) ReadSlice(delim byte) (line []byte, err error) {
46+
return r.buf.ReadSlice(delim)
47+
}
48+
3549
// NewReader returns a reader for the export data section of an object
3650
// (.o) or archive (.a) file read from r. The new reader may provide
3751
// additional trailing data beyond the end of the export data.
3852
func NewReader(r io.Reader) (io.Reader, error) {
39-
buf := bufio.NewReader(r)
53+
buf := &bufferedReader{
54+
r: r,
55+
buf: bufio.NewReader(r),
56+
}
4057
_, err := gcimporter.FindExportData(buf)
4158
// If we ever switch to a zip-like archive format with the ToC
4259
// at the end, we can return the correct portion of export data,
@@ -57,9 +74,29 @@ func NewReader(r io.Reader) (io.Reader, error) {
5774
//
5875
// On return, the state of the reader is undefined.
5976
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
60-
data, err := ioutil.ReadAll(in)
61-
if err != nil {
62-
return nil, fmt.Errorf("reading export data for %q: %v", path, err)
77+
var data []byte
78+
if br, ok := in.(*bufferedReader); ok {
79+
if f, ok := br.r.(*os.File); ok {
80+
fi, err := f.Stat()
81+
if err == nil {
82+
// we expect to be close to the start of the file,
83+
// which is why we don't bother checking with
84+
// SEEK_CUR.
85+
data = make([]byte, fi.Size())
86+
n, err := io.ReadFull(in, data)
87+
data = data[:n]
88+
if err != nil && err != io.ErrUnexpectedEOF {
89+
data = nil
90+
}
91+
}
92+
}
93+
}
94+
if data == nil {
95+
var err error
96+
data, err = ioutil.ReadAll(in)
97+
if err != nil {
98+
return nil, fmt.Errorf("reading export data for %q: %v", path, err)
99+
}
63100
}
64101

65102
if bytes.HasPrefix(data, []byte("!<arch>")) {

internal/go/gcimporter/exportdata.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
package gcimporter
1010

1111
import (
12-
"bufio"
1312
"fmt"
1413
"io"
1514
"strconv"
1615
"strings"
1716
)
1817

19-
func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
18+
func readGopackHeader(r io.Reader) (name string, size int, err error) {
2019
// See $GOROOT/include/ar.h.
2120
hdr := make([]byte, 16+12+6+6+8+10+2)
2221
_, err = io.ReadFull(r, hdr)
@@ -37,13 +36,18 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
3736
return
3837
}
3938

39+
type BufferedReader interface {
40+
Read(b []byte) (int, error)
41+
ReadSlice(delim byte) (line []byte, err error)
42+
}
43+
4044
// FindExportData positions the reader r at the beginning of the
4145
// export data section of an underlying GC-created object/archive
4246
// file by reading from it. The reader must be positioned at the
4347
// start of the file before calling this function. The hdr result
4448
// is the string before the export data, either "$$" or "$$B".
4549
//
46-
func FindExportData(r *bufio.Reader) (hdr string, err error) {
50+
func FindExportData(r BufferedReader) (hdr string, err error) {
4751
// Read first line to make sure this is an object file.
4852
line, err := r.ReadSlice('\n')
4953
if err != nil {

0 commit comments

Comments
 (0)