2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2015-12-01 11:52:32 -08:00
|
|
|
//go:generate go run mkbuiltin.go
|
2015-02-24 12:19:01 -05:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
2016-02-08 12:07:39 -05:00
|
|
|
"cmd/compile/internal/ssa"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"path"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"unicode"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
2015-09-11 00:03:19 +02:00
|
|
|
var imported_unsafe bool
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-19 23:56:30 -04:00
|
|
|
var (
|
|
|
|
|
goos string
|
|
|
|
|
goarch string
|
|
|
|
|
goroot string
|
|
|
|
|
buildid string
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
cmd/internal/gc: optimize append + write barrier
The code generated for x = append(x, v) is roughly:
t := x
if len(t)+1 > cap(t) {
t = grow(t)
}
t[len(t)] = v
len(t)++
x = t
We used to generate this code as Go pseudocode during walk.
Generate it instead as actual instructions during gen.
Doing so lets us apply a few optimizations. The most important
is that when, as in the above example, the source slice and the
destination slice are the same, the code can instead do:
t := x
if len(t)+1 > cap(t) {
t = grow(t)
x = {base(t), len(t)+1, cap(t)}
} else {
len(x)++
}
t[len(t)] = v
That is, in the fast path that does not reallocate the array,
only the updated length needs to be written back to x,
not the array pointer and not the capacity. This is more like
what you'd write by hand in C. It's faster in general, since
the fast path elides two of the three stores, but it's especially
faster when the form of x is such that the base pointer write
would turn into a write barrier. No write, no barrier.
name old mean new mean delta
BinaryTree17 5.68s × (0.97,1.04) 5.81s × (0.98,1.03) +2.35% (p=0.023)
Fannkuch11 4.41s × (0.98,1.03) 4.35s × (1.00,1.00) ~ (p=0.090)
FmtFprintfEmpty 92.7ns × (0.91,1.16) 86.0ns × (0.94,1.11) -7.31% (p=0.038)
FmtFprintfString 281ns × (0.96,1.08) 276ns × (0.98,1.04) ~ (p=0.219)
FmtFprintfInt 288ns × (0.97,1.06) 274ns × (0.98,1.06) -4.94% (p=0.002)
FmtFprintfIntInt 493ns × (0.97,1.04) 506ns × (0.99,1.01) +2.65% (p=0.009)
FmtFprintfPrefixedInt 423ns × (0.97,1.04) 391ns × (0.99,1.01) -7.52% (p=0.000)
FmtFprintfFloat 598ns × (0.99,1.01) 566ns × (0.99,1.01) -5.27% (p=0.000)
FmtManyArgs 1.89µs × (0.98,1.05) 1.91µs × (0.99,1.01) ~ (p=0.231)
GobDecode 14.8ms × (0.98,1.03) 15.3ms × (0.99,1.02) +3.01% (p=0.000)
GobEncode 12.3ms × (0.98,1.01) 11.5ms × (0.97,1.03) -5.93% (p=0.000)
Gzip 656ms × (0.99,1.05) 645ms × (0.99,1.01) ~ (p=0.055)
Gunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) -0.32% (p=0.034)
HTTPClientServer 91.2µs × (0.97,1.04) 90.5µs × (0.97,1.04) ~ (p=0.468)
JSONEncode 32.6ms × (0.97,1.08) 32.0ms × (0.98,1.03) ~ (p=0.190)
JSONDecode 114ms × (0.97,1.05) 114ms × (0.99,1.01) ~ (p=0.887)
Mandelbrot200 6.11ms × (0.98,1.04) 6.04ms × (1.00,1.01) ~ (p=0.167)
GoParse 6.66ms × (0.97,1.04) 6.47ms × (0.97,1.05) -2.81% (p=0.014)
RegexpMatchEasy0_32 159ns × (0.99,1.00) 171ns × (0.93,1.07) +7.19% (p=0.002)
RegexpMatchEasy0_1K 538ns × (1.00,1.01) 550ns × (0.98,1.01) +2.30% (p=0.000)
RegexpMatchEasy1_32 138ns × (1.00,1.00) 135ns × (0.99,1.02) -1.60% (p=0.000)
RegexpMatchEasy1_1K 869ns × (0.99,1.01) 879ns × (1.00,1.01) +1.08% (p=0.000)
RegexpMatchMedium_32 252ns × (0.99,1.01) 243ns × (1.00,1.00) -3.71% (p=0.000)
RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 70.3µs × (1.00,1.00) -3.34% (p=0.000)
RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.82µs × (1.00,1.01) -0.81% (p=0.000)
RegexpMatchHard_1K 118µs × (1.00,1.00) 117µs × (1.00,1.00) -0.56% (p=0.000)
Revcomp 920ms × (0.97,1.07) 917ms × (0.97,1.04) ~ (p=0.808)
Template 129ms × (0.98,1.03) 114ms × (0.99,1.01) -12.06% (p=0.000)
TimeParse 619ns × (0.99,1.01) 622ns × (0.99,1.01) ~ (p=0.062)
TimeFormat 661ns × (0.98,1.04) 665ns × (0.99,1.01) ~ (p=0.524)
See next CL for combination with a similar optimization for slice.
The benchmarks that are slower in this CL are still faster overall
with the combination of the two.
Change-Id: I2a7421658091b2488c64741b4db15ab6c3b4cb7e
Reviewed-on: https://go-review.googlesource.com/9812
Reviewed-by: David Chase <drchase@google.com>
2015-05-06 12:34:30 -04:00
|
|
|
var (
|
|
|
|
|
Debug_append int
|
2015-05-24 03:58:03 -04:00
|
|
|
Debug_panic int
|
cmd/internal/gc: optimize slice + write barrier
The code generated for a slice x[i:j] or x[i:j:k] computes the entire
new slice (base, len, cap) and then uses it as the evaluation of the
slice expression.
If the slice is part of an update x = x[i:j] or x = x[i:j:k], there are
opportunities to avoid computing some of these fields.
For x = x[0:i], we know that only the len is changing;
base can be ignored completely, and cap can be left unmodified.
For x = x[0:i:j], we know that only len and cap are changing;
base can be ignored completely.
For x = x[i:i], we know that the resulting cap is zero, and we don't
adjust the base during a slice producing a zero-cap result,
so again base can be ignored completely.
No write to base, no write barrier.
The old slice code was trying to work at a Go syntax level, mainly
because that was how you wrote code just once instead of once
per architecture. Now the compiler is factored a bit better and we
can implement slice during code generation but still have one copy
of the code. So the new code is working at that lower level.
(It must, to update only parts of the result.)
This CL by itself:
name old mean new mean delta
BinaryTree17 5.81s × (0.98,1.03) 5.71s × (0.96,1.05) ~ (p=0.101)
Fannkuch11 4.35s × (1.00,1.00) 4.39s × (1.00,1.00) +0.79% (p=0.000)
FmtFprintfEmpty 86.0ns × (0.94,1.11) 82.6ns × (0.98,1.04) -3.86% (p=0.048)
FmtFprintfString 276ns × (0.98,1.04) 273ns × (0.98,1.02) ~ (p=0.235)
FmtFprintfInt 274ns × (0.98,1.06) 270ns × (0.99,1.01) ~ (p=0.119)
FmtFprintfIntInt 506ns × (0.99,1.01) 475ns × (0.99,1.01) -6.02% (p=0.000)
FmtFprintfPrefixedInt 391ns × (0.99,1.01) 393ns × (1.00,1.01) ~ (p=0.139)
FmtFprintfFloat 566ns × (0.99,1.01) 574ns × (1.00,1.01) +1.33% (p=0.001)
FmtManyArgs 1.91µs × (0.99,1.01) 1.87µs × (0.99,1.02) -1.83% (p=0.000)
GobDecode 15.3ms × (0.99,1.02) 15.0ms × (0.98,1.05) -1.84% (p=0.042)
GobEncode 11.5ms × (0.97,1.03) 11.4ms × (0.99,1.03) ~ (p=0.152)
Gzip 645ms × (0.99,1.01) 647ms × (0.99,1.01) ~ (p=0.265)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.90% (p=0.000)
HTTPClientServer 90.5µs × (0.97,1.04) 88.5µs × (0.99,1.03) -2.27% (p=0.014)
JSONEncode 32.0ms × (0.98,1.03) 29.6ms × (0.98,1.01) -7.51% (p=0.000)
JSONDecode 114ms × (0.99,1.01) 104ms × (1.00,1.01) -8.60% (p=0.000)
Mandelbrot200 6.04ms × (1.00,1.01) 6.02ms × (1.00,1.00) ~ (p=0.057)
GoParse 6.47ms × (0.97,1.05) 6.37ms × (0.97,1.04) ~ (p=0.105)
RegexpMatchEasy0_32 171ns × (0.93,1.07) 152ns × (0.99,1.01) -11.09% (p=0.000)
RegexpMatchEasy0_1K 550ns × (0.98,1.01) 530ns × (1.00,1.00) -3.78% (p=0.000)
RegexpMatchEasy1_32 135ns × (0.99,1.02) 134ns × (0.99,1.01) -1.33% (p=0.002)
RegexpMatchEasy1_1K 879ns × (1.00,1.01) 865ns × (1.00,1.00) -1.58% (p=0.000)
RegexpMatchMedium_32 243ns × (1.00,1.00) 233ns × (1.00,1.00) -4.30% (p=0.000)
RegexpMatchMedium_1K 70.3µs × (1.00,1.00) 69.5µs × (1.00,1.00) -1.13% (p=0.000)
RegexpMatchHard_32 3.82µs × (1.00,1.01) 3.74µs × (1.00,1.00) -1.95% (p=0.000)
RegexpMatchHard_1K 117µs × (1.00,1.00) 115µs × (1.00,1.00) -1.69% (p=0.000)
Revcomp 917ms × (0.97,1.04) 920ms × (0.97,1.04) ~ (p=0.786)
Template 114ms × (0.99,1.01) 117ms × (0.99,1.01) +2.58% (p=0.000)
TimeParse 622ns × (0.99,1.01) 615ns × (0.99,1.00) -1.06% (p=0.000)
TimeFormat 665ns × (0.99,1.01) 654ns × (0.99,1.00) -1.70% (p=0.000)
This CL and previous CL (append) combined:
name old mean new mean delta
BinaryTree17 5.68s × (0.97,1.04) 5.71s × (0.96,1.05) ~ (p=0.638)
Fannkuch11 4.41s × (0.98,1.03) 4.39s × (1.00,1.00) ~ (p=0.474)
FmtFprintfEmpty 92.7ns × (0.91,1.16) 82.6ns × (0.98,1.04) -10.89% (p=0.004)
FmtFprintfString 281ns × (0.96,1.08) 273ns × (0.98,1.02) ~ (p=0.078)
FmtFprintfInt 288ns × (0.97,1.06) 270ns × (0.99,1.01) -6.37% (p=0.000)
FmtFprintfIntInt 493ns × (0.97,1.04) 475ns × (0.99,1.01) -3.53% (p=0.002)
FmtFprintfPrefixedInt 423ns × (0.97,1.04) 393ns × (1.00,1.01) -7.07% (p=0.000)
FmtFprintfFloat 598ns × (0.99,1.01) 574ns × (1.00,1.01) -4.02% (p=0.000)
FmtManyArgs 1.89µs × (0.98,1.05) 1.87µs × (0.99,1.02) ~ (p=0.305)
GobDecode 14.8ms × (0.98,1.03) 15.0ms × (0.98,1.05) ~ (p=0.237)
GobEncode 12.3ms × (0.98,1.01) 11.4ms × (0.99,1.03) -6.95% (p=0.000)
Gzip 656ms × (0.99,1.05) 647ms × (0.99,1.01) ~ (p=0.101)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.58% (p=0.001)
HTTPClientServer 91.2µs × (0.97,1.04) 88.5µs × (0.99,1.03) -3.02% (p=0.003)
JSONEncode 32.6ms × (0.97,1.08) 29.6ms × (0.98,1.01) -9.10% (p=0.000)
JSONDecode 114ms × (0.97,1.05) 104ms × (1.00,1.01) -8.74% (p=0.000)
Mandelbrot200 6.11ms × (0.98,1.04) 6.02ms × (1.00,1.00) ~ (p=0.090)
GoParse 6.66ms × (0.97,1.04) 6.37ms × (0.97,1.04) -4.41% (p=0.000)
RegexpMatchEasy0_32 159ns × (0.99,1.00) 152ns × (0.99,1.01) -4.69% (p=0.000)
RegexpMatchEasy0_1K 538ns × (1.00,1.01) 530ns × (1.00,1.00) -1.57% (p=0.000)
RegexpMatchEasy1_32 138ns × (1.00,1.00) 134ns × (0.99,1.01) -2.91% (p=0.000)
RegexpMatchEasy1_1K 869ns × (0.99,1.01) 865ns × (1.00,1.00) -0.51% (p=0.012)
RegexpMatchMedium_32 252ns × (0.99,1.01) 233ns × (1.00,1.00) -7.85% (p=0.000)
RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 69.5µs × (1.00,1.00) -4.43% (p=0.000)
RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.74µs × (1.00,1.00) -2.74% (p=0.000)
RegexpMatchHard_1K 118µs × (1.00,1.00) 115µs × (1.00,1.00) -2.24% (p=0.000)
Revcomp 920ms × (0.97,1.07) 920ms × (0.97,1.04) ~ (p=0.998)
Template 129ms × (0.98,1.03) 117ms × (0.99,1.01) -9.79% (p=0.000)
TimeParse 619ns × (0.99,1.01) 615ns × (0.99,1.00) -0.57% (p=0.011)
TimeFormat 661ns × (0.98,1.04) 654ns × (0.99,1.00) ~ (p=0.223)
Change-Id: If054d81ab2c71d8d62cf54b5b1fac2af66b387fc
Reviewed-on: https://go-review.googlesource.com/9813
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-05-06 12:35:53 -04:00
|
|
|
Debug_slice int
|
2015-05-24 03:58:03 -04:00
|
|
|
Debug_wb int
|
cmd/internal/gc: optimize append + write barrier
The code generated for x = append(x, v) is roughly:
t := x
if len(t)+1 > cap(t) {
t = grow(t)
}
t[len(t)] = v
len(t)++
x = t
We used to generate this code as Go pseudocode during walk.
Generate it instead as actual instructions during gen.
Doing so lets us apply a few optimizations. The most important
is that when, as in the above example, the source slice and the
destination slice are the same, the code can instead do:
t := x
if len(t)+1 > cap(t) {
t = grow(t)
x = {base(t), len(t)+1, cap(t)}
} else {
len(x)++
}
t[len(t)] = v
That is, in the fast path that does not reallocate the array,
only the updated length needs to be written back to x,
not the array pointer and not the capacity. This is more like
what you'd write by hand in C. It's faster in general, since
the fast path elides two of the three stores, but it's especially
faster when the form of x is such that the base pointer write
would turn into a write barrier. No write, no barrier.
name old mean new mean delta
BinaryTree17 5.68s × (0.97,1.04) 5.81s × (0.98,1.03) +2.35% (p=0.023)
Fannkuch11 4.41s × (0.98,1.03) 4.35s × (1.00,1.00) ~ (p=0.090)
FmtFprintfEmpty 92.7ns × (0.91,1.16) 86.0ns × (0.94,1.11) -7.31% (p=0.038)
FmtFprintfString 281ns × (0.96,1.08) 276ns × (0.98,1.04) ~ (p=0.219)
FmtFprintfInt 288ns × (0.97,1.06) 274ns × (0.98,1.06) -4.94% (p=0.002)
FmtFprintfIntInt 493ns × (0.97,1.04) 506ns × (0.99,1.01) +2.65% (p=0.009)
FmtFprintfPrefixedInt 423ns × (0.97,1.04) 391ns × (0.99,1.01) -7.52% (p=0.000)
FmtFprintfFloat 598ns × (0.99,1.01) 566ns × (0.99,1.01) -5.27% (p=0.000)
FmtManyArgs 1.89µs × (0.98,1.05) 1.91µs × (0.99,1.01) ~ (p=0.231)
GobDecode 14.8ms × (0.98,1.03) 15.3ms × (0.99,1.02) +3.01% (p=0.000)
GobEncode 12.3ms × (0.98,1.01) 11.5ms × (0.97,1.03) -5.93% (p=0.000)
Gzip 656ms × (0.99,1.05) 645ms × (0.99,1.01) ~ (p=0.055)
Gunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) -0.32% (p=0.034)
HTTPClientServer 91.2µs × (0.97,1.04) 90.5µs × (0.97,1.04) ~ (p=0.468)
JSONEncode 32.6ms × (0.97,1.08) 32.0ms × (0.98,1.03) ~ (p=0.190)
JSONDecode 114ms × (0.97,1.05) 114ms × (0.99,1.01) ~ (p=0.887)
Mandelbrot200 6.11ms × (0.98,1.04) 6.04ms × (1.00,1.01) ~ (p=0.167)
GoParse 6.66ms × (0.97,1.04) 6.47ms × (0.97,1.05) -2.81% (p=0.014)
RegexpMatchEasy0_32 159ns × (0.99,1.00) 171ns × (0.93,1.07) +7.19% (p=0.002)
RegexpMatchEasy0_1K 538ns × (1.00,1.01) 550ns × (0.98,1.01) +2.30% (p=0.000)
RegexpMatchEasy1_32 138ns × (1.00,1.00) 135ns × (0.99,1.02) -1.60% (p=0.000)
RegexpMatchEasy1_1K 869ns × (0.99,1.01) 879ns × (1.00,1.01) +1.08% (p=0.000)
RegexpMatchMedium_32 252ns × (0.99,1.01) 243ns × (1.00,1.00) -3.71% (p=0.000)
RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 70.3µs × (1.00,1.00) -3.34% (p=0.000)
RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.82µs × (1.00,1.01) -0.81% (p=0.000)
RegexpMatchHard_1K 118µs × (1.00,1.00) 117µs × (1.00,1.00) -0.56% (p=0.000)
Revcomp 920ms × (0.97,1.07) 917ms × (0.97,1.04) ~ (p=0.808)
Template 129ms × (0.98,1.03) 114ms × (0.99,1.01) -12.06% (p=0.000)
TimeParse 619ns × (0.99,1.01) 622ns × (0.99,1.01) ~ (p=0.062)
TimeFormat 661ns × (0.98,1.04) 665ns × (0.99,1.01) ~ (p=0.524)
See next CL for combination with a similar optimization for slice.
The benchmarks that are slower in this CL are still faster overall
with the combination of the two.
Change-Id: I2a7421658091b2488c64741b4db15ab6c3b4cb7e
Reviewed-on: https://go-review.googlesource.com/9812
Reviewed-by: David Chase <drchase@google.com>
2015-05-06 12:34:30 -04:00
|
|
|
)
|
2015-04-17 00:34:18 -04:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
const BOM = 0xFEFF
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Debug arguments.
|
|
|
|
|
// These can be specified with the -d flag, as in "-d nil"
|
|
|
|
|
// to set the debug_checknil variable. In general the list passed
|
|
|
|
|
// to -d can be comma-separated.
|
|
|
|
|
var debugtab = []struct {
|
|
|
|
|
name string
|
|
|
|
|
val *int
|
2015-03-08 18:46:28 -04:00
|
|
|
}{
|
runtime: replace GC programs with simpler encoding, faster decoder
Small types record the location of pointers in their memory layout
by using a simple bitmap. In Go 1.4 the bitmap held 4-bit entries,
and in Go 1.5 the bitmap holds 1-bit entries, but in both cases using
a bitmap for a large type containing arrays does not make sense:
if someone refers to the type [1<<28]*byte in a program in such
a way that the type information makes it into the binary, it would be
a waste of space to write a 128 MB (for 4-bit entries) or even 32 MB
(for 1-bit entries) bitmap full of 1s into the binary or even to keep
one in memory during the execution of the program.
For large types containing arrays, it is much more compact to describe
the locations of pointers using a notation that can express repetition
than to lay out a bitmap of pointers. Go 1.4 included such a notation,
called ``GC programs'' but it was complex, required recursion during
decoding, and was generally slow. Dmitriy measured the execution of
these programs writing directly to the heap bitmap as being 7x slower
than copying from a preunrolled 4-bit mask (and frankly that code was
not terribly fast either). For some tests, unrollgcprog1 was seen costing
as much as 3x more than the rest of malloc combined.
This CL introduces a different form for the GC programs. They use a
simple Lempel-Ziv-style encoding of the 1-bit pointer information,
in which the only operations are (1) emit the following n bits
and (2) repeat the last n bits c more times. This encoding can be
generated directly from the Go type information (using repetition
only for arrays or large runs of non-pointer data) and it can be decoded
very efficiently. In particular the decoding requires little state and
no recursion, so that the entire decoding can run without any memory
accesses other than the reads of the encoding and the writes of the
decoded form to the heap bitmap. For recursive types like arrays of
arrays of arrays, the inner instructions are only executed once, not
n times, so that large repetitions run at full speed. (In contrast, large
repetitions in the old programs repeated the individual bit-level layout
of the inner data over and over.) The result is as much as 25x faster
decoding compared to the old form.
Because the old decoder was so slow, Go 1.4 had three (or so) cases
for how to set the heap bitmap bits for an allocation of a given type:
(1) If the type had an even number of words up to 32 words, then
the 4-bit pointer mask for the type fit in no more than 16 bytes;
store the 4-bit pointer mask directly in the binary and copy from it.
(1b) If the type had an odd number of words up to 15 words, then
the 4-bit pointer mask for the type, doubled to end on a byte boundary,
fit in no more than 16 bytes; store that doubled mask directly in the
binary and copy from it.
(2) If the type had an even number of words up to 128 words,
or an odd number of words up to 63 words (again due to doubling),
then the 4-bit pointer mask would fit in a 64-byte unrolled mask.
Store a GC program in the binary, but leave space in the BSS for
the unrolled mask. Execute the GC program to construct the mask the
first time it is needed, and thereafter copy from the mask.
(3) Otherwise, store a GC program and execute it to write directly to
the heap bitmap each time an object of that type is allocated.
(This is the case that was 7x slower than the other two.)
Because the new pointer masks store 1-bit entries instead of 4-bit
entries and because using the decoder no longer carries a significant
overhead, after this CL (that is, for Go 1.5) there are only two cases:
(1) If the type is 128 words or less (no condition about odd or even),
store the 1-bit pointer mask directly in the binary and use it to
initialize the heap bitmap during malloc. (Implemented in CL 9702.)
(2) There is no case 2 anymore.
(3) Otherwise, store a GC program and execute it to write directly to
the heap bitmap each time an object of that type is allocated.
Executing the GC program directly into the heap bitmap (case (3) above)
was disabled for the Go 1.5 dev cycle, both to avoid needing to use
GC programs for typedmemmove and to avoid updating that code as
the heap bitmap format changed. Typedmemmove no longer uses this
type information; as of CL 9886 it uses the heap bitmap directly.
Now that the heap bitmap format is stable, we reintroduce GC programs
and their space savings.
Benchmarks for heapBitsSetType, before this CL vs this CL:
name old mean new mean delta
SetTypePtr 7.59ns × (0.99,1.02) 5.16ns × (1.00,1.00) -32.05% (p=0.000)
SetTypePtr8 21.0ns × (0.98,1.05) 21.4ns × (1.00,1.00) ~ (p=0.179)
SetTypePtr16 24.1ns × (0.99,1.01) 24.6ns × (1.00,1.00) +2.41% (p=0.001)
SetTypePtr32 31.2ns × (0.99,1.01) 32.4ns × (0.99,1.02) +3.72% (p=0.001)
SetTypePtr64 45.2ns × (1.00,1.00) 47.2ns × (1.00,1.00) +4.42% (p=0.000)
SetTypePtr126 75.8ns × (0.99,1.01) 79.1ns × (1.00,1.00) +4.25% (p=0.000)
SetTypePtr128 74.3ns × (0.99,1.01) 77.6ns × (1.00,1.01) +4.55% (p=0.000)
SetTypePtrSlice 726ns × (1.00,1.01) 712ns × (1.00,1.00) -1.95% (p=0.001)
SetTypeNode1 20.0ns × (0.99,1.01) 20.7ns × (1.00,1.00) +3.71% (p=0.000)
SetTypeNode1Slice 112ns × (1.00,1.00) 113ns × (0.99,1.00) ~ (p=0.070)
SetTypeNode8 23.9ns × (1.00,1.00) 24.7ns × (1.00,1.01) +3.18% (p=0.000)
SetTypeNode8Slice 294ns × (0.99,1.02) 287ns × (0.99,1.01) -2.38% (p=0.015)
SetTypeNode64 52.8ns × (0.99,1.03) 51.8ns × (0.99,1.01) ~ (p=0.069)
SetTypeNode64Slice 1.13µs × (0.99,1.05) 1.14µs × (0.99,1.00) ~ (p=0.767)
SetTypeNode64Dead 36.0ns × (1.00,1.01) 32.5ns × (0.99,1.00) -9.67% (p=0.000)
SetTypeNode64DeadSlice 1.43µs × (0.99,1.01) 1.40µs × (1.00,1.00) -2.39% (p=0.001)
SetTypeNode124 75.7ns × (1.00,1.01) 79.0ns × (1.00,1.00) +4.44% (p=0.000)
SetTypeNode124Slice 1.94µs × (1.00,1.01) 2.04µs × (0.99,1.01) +4.98% (p=0.000)
SetTypeNode126 75.4ns × (1.00,1.01) 77.7ns × (0.99,1.01) +3.11% (p=0.000)
SetTypeNode126Slice 1.95µs × (0.99,1.01) 2.03µs × (1.00,1.00) +3.74% (p=0.000)
SetTypeNode128 85.4ns × (0.99,1.01) 122.0ns × (1.00,1.00) +42.89% (p=0.000)
SetTypeNode128Slice 2.20µs × (1.00,1.01) 2.36µs × (0.98,1.02) +7.48% (p=0.001)
SetTypeNode130 83.3ns × (1.00,1.00) 123.0ns × (1.00,1.00) +47.61% (p=0.000)
SetTypeNode130Slice 2.30µs × (0.99,1.01) 2.40µs × (0.98,1.01) +4.37% (p=0.000)
SetTypeNode1024 498ns × (1.00,1.00) 537ns × (1.00,1.00) +7.96% (p=0.000)
SetTypeNode1024Slice 15.5µs × (0.99,1.01) 17.8µs × (1.00,1.00) +15.27% (p=0.000)
The above compares always using a cached pointer mask (and the
corresponding waste of memory) against using the programs directly.
Some slowdown is expected, in exchange for having a better general algorithm.
The GC programs kick in for SetTypeNode128, SetTypeNode130, SetTypeNode1024,
along with the slice variants of those.
It is possible that the cutoff of 128 words (bits) should be raised
in a followup CL, but even with this low cutoff the GC programs are
faster than Go 1.4's "fast path" non-GC program case.
Benchmarks for heapBitsSetType, Go 1.4 vs this CL:
name old mean new mean delta
SetTypePtr 6.89ns × (1.00,1.00) 5.17ns × (1.00,1.00) -25.02% (p=0.000)
SetTypePtr8 25.8ns × (0.97,1.05) 21.5ns × (1.00,1.00) -16.70% (p=0.000)
SetTypePtr16 39.8ns × (0.97,1.02) 24.7ns × (0.99,1.01) -37.81% (p=0.000)
SetTypePtr32 68.8ns × (0.98,1.01) 32.2ns × (1.00,1.01) -53.18% (p=0.000)
SetTypePtr64 130ns × (1.00,1.00) 47ns × (1.00,1.00) -63.67% (p=0.000)
SetTypePtr126 241ns × (0.99,1.01) 79ns × (1.00,1.01) -67.25% (p=0.000)
SetTypePtr128 2.07µs × (1.00,1.00) 0.08µs × (1.00,1.00) -96.27% (p=0.000)
SetTypePtrSlice 1.05µs × (0.99,1.01) 0.72µs × (0.99,1.02) -31.70% (p=0.000)
SetTypeNode1 16.0ns × (0.99,1.01) 20.8ns × (0.99,1.03) +29.91% (p=0.000)
SetTypeNode1Slice 184ns × (0.99,1.01) 112ns × (0.99,1.01) -39.26% (p=0.000)
SetTypeNode8 29.5ns × (0.97,1.02) 24.6ns × (1.00,1.00) -16.50% (p=0.000)
SetTypeNode8Slice 624ns × (0.98,1.02) 285ns × (1.00,1.00) -54.31% (p=0.000)
SetTypeNode64 135ns × (0.96,1.08) 52ns × (0.99,1.02) -61.32% (p=0.000)
SetTypeNode64Slice 3.83µs × (1.00,1.00) 1.14µs × (0.99,1.01) -70.16% (p=0.000)
SetTypeNode64Dead 134ns × (0.99,1.01) 32ns × (1.00,1.01) -75.74% (p=0.000)
SetTypeNode64DeadSlice 3.83µs × (0.99,1.00) 1.40µs × (1.00,1.01) -63.42% (p=0.000)
SetTypeNode124 240ns × (0.99,1.01) 79ns × (1.00,1.01) -67.05% (p=0.000)
SetTypeNode124Slice 7.27µs × (1.00,1.00) 2.04µs × (1.00,1.00) -71.95% (p=0.000)
SetTypeNode126 2.06µs × (0.99,1.01) 0.08µs × (0.99,1.01) -96.23% (p=0.000)
SetTypeNode126Slice 64.4µs × (1.00,1.00) 2.0µs × (1.00,1.00) -96.85% (p=0.000)
SetTypeNode128 2.09µs × (1.00,1.01) 0.12µs × (1.00,1.00) -94.15% (p=0.000)
SetTypeNode128Slice 65.4µs × (1.00,1.00) 2.4µs × (0.99,1.03) -96.39% (p=0.000)
SetTypeNode130 2.11µs × (1.00,1.00) 0.12µs × (1.00,1.00) -94.18% (p=0.000)
SetTypeNode130Slice 66.3µs × (1.00,1.00) 2.4µs × (0.97,1.08) -96.34% (p=0.000)
SetTypeNode1024 16.0µs × (1.00,1.01) 0.5µs × (1.00,1.00) -96.65% (p=0.000)
SetTypeNode1024Slice 512µs × (1.00,1.00) 18µs × (0.98,1.04) -96.45% (p=0.000)
SetTypeNode124 uses a 124 data + 2 ptr = 126-word allocation.
Both Go 1.4 and this CL are using pointer bitmaps for this case,
so that's an overall 3x speedup for using pointer bitmaps.
SetTypeNode128 uses a 128 data + 2 ptr = 130-word allocation.
Both Go 1.4 and this CL are running the GC program for this case,
so that's an overall 17x speedup when using GC programs (and
I've seen >20x on other systems).
Comparing Go 1.4's SetTypeNode124 (pointer bitmap) against
this CL's SetTypeNode128 (GC program), the slow path in the
code in this CL is 2x faster than the fast path in Go 1.4.
The Go 1 benchmarks are basically unaffected compared to just before this CL.
Go 1 benchmarks, before this CL vs this CL:
name old mean new mean delta
BinaryTree17 5.87s × (0.97,1.04) 5.91s × (0.96,1.04) ~ (p=0.306)
Fannkuch11 4.38s × (1.00,1.00) 4.37s × (1.00,1.01) -0.22% (p=0.006)
FmtFprintfEmpty 90.7ns × (0.97,1.10) 89.3ns × (0.96,1.09) ~ (p=0.280)
FmtFprintfString 282ns × (0.98,1.04) 287ns × (0.98,1.07) +1.72% (p=0.039)
FmtFprintfInt 269ns × (0.99,1.03) 282ns × (0.97,1.04) +4.87% (p=0.000)
FmtFprintfIntInt 478ns × (0.99,1.02) 481ns × (0.99,1.02) +0.61% (p=0.048)
FmtFprintfPrefixedInt 399ns × (0.98,1.03) 400ns × (0.98,1.05) ~ (p=0.533)
FmtFprintfFloat 563ns × (0.99,1.01) 570ns × (1.00,1.01) +1.37% (p=0.000)
FmtManyArgs 1.89µs × (0.99,1.01) 1.92µs × (0.99,1.02) +1.88% (p=0.000)
GobDecode 15.2ms × (0.99,1.01) 15.2ms × (0.98,1.05) ~ (p=0.609)
GobEncode 11.6ms × (0.98,1.03) 11.9ms × (0.98,1.04) +2.17% (p=0.000)
Gzip 648ms × (0.99,1.01) 648ms × (1.00,1.01) ~ (p=0.835)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) ~ (p=0.169)
HTTPClientServer 90.5µs × (0.98,1.03) 91.5µs × (0.98,1.04) +1.04% (p=0.045)
JSONEncode 31.5ms × (0.98,1.03) 31.4ms × (0.98,1.03) ~ (p=0.549)
JSONDecode 111ms × (0.99,1.01) 107ms × (0.99,1.01) -3.21% (p=0.000)
Mandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~ (p=0.878)
GoParse 6.54ms × (0.99,1.02) 6.61ms × (0.99,1.03) +1.08% (p=0.004)
RegexpMatchEasy0_32 160ns × (1.00,1.01) 161ns × (1.00,1.00) +0.40% (p=0.000)
RegexpMatchEasy0_1K 560ns × (0.99,1.01) 559ns × (0.99,1.01) ~ (p=0.088)
RegexpMatchEasy1_32 138ns × (0.99,1.01) 138ns × (1.00,1.00) ~ (p=0.380)
RegexpMatchEasy1_1K 877ns × (1.00,1.00) 878ns × (1.00,1.00) ~ (p=0.157)
RegexpMatchMedium_32 251ns × (0.99,1.00) 251ns × (1.00,1.01) +0.28% (p=0.021)
RegexpMatchMedium_1K 72.6µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.539)
RegexpMatchHard_32 3.84µs × (1.00,1.00) 3.84µs × (1.00,1.00) ~ (p=0.378)
RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) ~ (p=0.067)
Revcomp 904ms × (0.99,1.02) 904ms × (0.99,1.01) ~ (p=0.943)
Template 125ms × (0.99,1.02) 127ms × (0.99,1.01) +1.79% (p=0.000)
TimeParse 627ns × (0.99,1.01) 622ns × (0.99,1.01) -0.88% (p=0.000)
TimeFormat 655ns × (0.99,1.02) 655ns × (0.99,1.02) ~ (p=0.976)
For the record, Go 1 benchmarks, Go 1.4 vs this CL:
name old mean new mean delta
BinaryTree17 4.61s × (0.97,1.05) 5.91s × (0.98,1.03) +28.35% (p=0.000)
Fannkuch11 4.40s × (0.99,1.03) 4.41s × (0.99,1.01) ~ (p=0.212)
FmtFprintfEmpty 102ns × (0.99,1.01) 84ns × (0.99,1.02) -18.38% (p=0.000)
FmtFprintfString 302ns × (0.98,1.01) 303ns × (0.99,1.02) ~ (p=0.203)
FmtFprintfInt 313ns × (0.97,1.05) 270ns × (0.99,1.01) -13.69% (p=0.000)
FmtFprintfIntInt 524ns × (0.98,1.02) 477ns × (0.99,1.00) -8.87% (p=0.000)
FmtFprintfPrefixedInt 424ns × (0.98,1.02) 386ns × (0.99,1.01) -8.96% (p=0.000)
FmtFprintfFloat 652ns × (0.98,1.02) 594ns × (0.97,1.05) -8.97% (p=0.000)
FmtManyArgs 2.13µs × (0.99,1.02) 1.94µs × (0.99,1.01) -8.92% (p=0.000)
GobDecode 17.1ms × (0.99,1.02) 14.9ms × (0.98,1.03) -13.07% (p=0.000)
GobEncode 13.5ms × (0.98,1.03) 11.5ms × (0.98,1.03) -15.25% (p=0.000)
Gzip 656ms × (0.99,1.02) 647ms × (0.99,1.01) -1.29% (p=0.000)
Gunzip 143ms × (0.99,1.02) 144ms × (0.99,1.01) ~ (p=0.204)
HTTPClientServer 88.2µs × (0.98,1.02) 90.8µs × (0.98,1.01) +2.93% (p=0.000)
JSONEncode 32.2ms × (0.98,1.02) 30.9ms × (0.97,1.04) -4.06% (p=0.001)
JSONDecode 121ms × (0.98,1.02) 110ms × (0.98,1.05) -8.95% (p=0.000)
Mandelbrot200 6.06ms × (0.99,1.01) 6.11ms × (0.98,1.04) ~ (p=0.184)
GoParse 6.76ms × (0.97,1.04) 6.58ms × (0.98,1.05) -2.63% (p=0.003)
RegexpMatchEasy0_32 195ns × (1.00,1.01) 155ns × (0.99,1.01) -20.43% (p=0.000)
RegexpMatchEasy0_1K 479ns × (0.98,1.03) 535ns × (0.99,1.02) +11.59% (p=0.000)
RegexpMatchEasy1_32 169ns × (0.99,1.02) 131ns × (0.99,1.03) -22.44% (p=0.000)
RegexpMatchEasy1_1K 1.53µs × (0.99,1.01) 0.87µs × (0.99,1.02) -43.07% (p=0.000)
RegexpMatchMedium_32 334ns × (0.99,1.01) 242ns × (0.99,1.01) -27.53% (p=0.000)
RegexpMatchMedium_1K 125µs × (1.00,1.01) 72µs × (0.99,1.03) -42.53% (p=0.000)
RegexpMatchHard_32 6.03µs × (0.99,1.01) 3.79µs × (0.99,1.01) -37.12% (p=0.000)
RegexpMatchHard_1K 189µs × (0.99,1.02) 115µs × (0.99,1.01) -39.20% (p=0.000)
Revcomp 935ms × (0.96,1.03) 926ms × (0.98,1.02) ~ (p=0.083)
Template 146ms × (0.97,1.05) 119ms × (0.99,1.01) -18.37% (p=0.000)
TimeParse 660ns × (0.99,1.01) 624ns × (0.99,1.02) -5.43% (p=0.000)
TimeFormat 670ns × (0.98,1.02) 710ns × (1.00,1.01) +5.97% (p=0.000)
This CL is a bit larger than I would like, but the compiler, linker, runtime,
and package reflect all need to be in sync about the format of these programs,
so there is no easy way to split this into independent changes (at least
while keeping the build working at each change).
Fixes #9625.
Fixes #10524.
Change-Id: I9e3e20d6097099d0f8532d1cb5b1af528804989a
Reviewed-on: https://go-review.googlesource.com/9888
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
2015-05-08 01:43:18 -04:00
|
|
|
{"append", &Debug_append}, // print information about append compilation
|
|
|
|
|
{"disablenil", &Disable_checknil}, // disable nil checks
|
|
|
|
|
{"gcprog", &Debug_gcprog}, // print dump of GC programs
|
2015-03-20 00:06:10 -04:00
|
|
|
{"nil", &Debug_checknil}, // print information about nil checks
|
2015-05-24 03:58:03 -04:00
|
|
|
{"panic", &Debug_panic}, // do not hide any compiler panic
|
runtime: replace GC programs with simpler encoding, faster decoder
Small types record the location of pointers in their memory layout
by using a simple bitmap. In Go 1.4 the bitmap held 4-bit entries,
and in Go 1.5 the bitmap holds 1-bit entries, but in both cases using
a bitmap for a large type containing arrays does not make sense:
if someone refers to the type [1<<28]*byte in a program in such
a way that the type information makes it into the binary, it would be
a waste of space to write a 128 MB (for 4-bit entries) or even 32 MB
(for 1-bit entries) bitmap full of 1s into the binary or even to keep
one in memory during the execution of the program.
For large types containing arrays, it is much more compact to describe
the locations of pointers using a notation that can express repetition
than to lay out a bitmap of pointers. Go 1.4 included such a notation,
called ``GC programs'' but it was complex, required recursion during
decoding, and was generally slow. Dmitriy measured the execution of
these programs writing directly to the heap bitmap as being 7x slower
than copying from a preunrolled 4-bit mask (and frankly that code was
not terribly fast either). For some tests, unrollgcprog1 was seen costing
as much as 3x more than the rest of malloc combined.
This CL introduces a different form for the GC programs. They use a
simple Lempel-Ziv-style encoding of the 1-bit pointer information,
in which the only operations are (1) emit the following n bits
and (2) repeat the last n bits c more times. This encoding can be
generated directly from the Go type information (using repetition
only for arrays or large runs of non-pointer data) and it can be decoded
very efficiently. In particular the decoding requires little state and
no recursion, so that the entire decoding can run without any memory
accesses other than the reads of the encoding and the writes of the
decoded form to the heap bitmap. For recursive types like arrays of
arrays of arrays, the inner instructions are only executed once, not
n times, so that large repetitions run at full speed. (In contrast, large
repetitions in the old programs repeated the individual bit-level layout
of the inner data over and over.) The result is as much as 25x faster
decoding compared to the old form.
Because the old decoder was so slow, Go 1.4 had three (or so) cases
for how to set the heap bitmap bits for an allocation of a given type:
(1) If the type had an even number of words up to 32 words, then
the 4-bit pointer mask for the type fit in no more than 16 bytes;
store the 4-bit pointer mask directly in the binary and copy from it.
(1b) If the type had an odd number of words up to 15 words, then
the 4-bit pointer mask for the type, doubled to end on a byte boundary,
fit in no more than 16 bytes; store that doubled mask directly in the
binary and copy from it.
(2) If the type had an even number of words up to 128 words,
or an odd number of words up to 63 words (again due to doubling),
then the 4-bit pointer mask would fit in a 64-byte unrolled mask.
Store a GC program in the binary, but leave space in the BSS for
the unrolled mask. Execute the GC program to construct the mask the
first time it is needed, and thereafter copy from the mask.
(3) Otherwise, store a GC program and execute it to write directly to
the heap bitmap each time an object of that type is allocated.
(This is the case that was 7x slower than the other two.)
Because the new pointer masks store 1-bit entries instead of 4-bit
entries and because using the decoder no longer carries a significant
overhead, after this CL (that is, for Go 1.5) there are only two cases:
(1) If the type is 128 words or less (no condition about odd or even),
store the 1-bit pointer mask directly in the binary and use it to
initialize the heap bitmap during malloc. (Implemented in CL 9702.)
(2) There is no case 2 anymore.
(3) Otherwise, store a GC program and execute it to write directly to
the heap bitmap each time an object of that type is allocated.
Executing the GC program directly into the heap bitmap (case (3) above)
was disabled for the Go 1.5 dev cycle, both to avoid needing to use
GC programs for typedmemmove and to avoid updating that code as
the heap bitmap format changed. Typedmemmove no longer uses this
type information; as of CL 9886 it uses the heap bitmap directly.
Now that the heap bitmap format is stable, we reintroduce GC programs
and their space savings.
Benchmarks for heapBitsSetType, before this CL vs this CL:
name old mean new mean delta
SetTypePtr 7.59ns × (0.99,1.02) 5.16ns × (1.00,1.00) -32.05% (p=0.000)
SetTypePtr8 21.0ns × (0.98,1.05) 21.4ns × (1.00,1.00) ~ (p=0.179)
SetTypePtr16 24.1ns × (0.99,1.01) 24.6ns × (1.00,1.00) +2.41% (p=0.001)
SetTypePtr32 31.2ns × (0.99,1.01) 32.4ns × (0.99,1.02) +3.72% (p=0.001)
SetTypePtr64 45.2ns × (1.00,1.00) 47.2ns × (1.00,1.00) +4.42% (p=0.000)
SetTypePtr126 75.8ns × (0.99,1.01) 79.1ns × (1.00,1.00) +4.25% (p=0.000)
SetTypePtr128 74.3ns × (0.99,1.01) 77.6ns × (1.00,1.01) +4.55% (p=0.000)
SetTypePtrSlice 726ns × (1.00,1.01) 712ns × (1.00,1.00) -1.95% (p=0.001)
SetTypeNode1 20.0ns × (0.99,1.01) 20.7ns × (1.00,1.00) +3.71% (p=0.000)
SetTypeNode1Slice 112ns × (1.00,1.00) 113ns × (0.99,1.00) ~ (p=0.070)
SetTypeNode8 23.9ns × (1.00,1.00) 24.7ns × (1.00,1.01) +3.18% (p=0.000)
SetTypeNode8Slice 294ns × (0.99,1.02) 287ns × (0.99,1.01) -2.38% (p=0.015)
SetTypeNode64 52.8ns × (0.99,1.03) 51.8ns × (0.99,1.01) ~ (p=0.069)
SetTypeNode64Slice 1.13µs × (0.99,1.05) 1.14µs × (0.99,1.00) ~ (p=0.767)
SetTypeNode64Dead 36.0ns × (1.00,1.01) 32.5ns × (0.99,1.00) -9.67% (p=0.000)
SetTypeNode64DeadSlice 1.43µs × (0.99,1.01) 1.40µs × (1.00,1.00) -2.39% (p=0.001)
SetTypeNode124 75.7ns × (1.00,1.01) 79.0ns × (1.00,1.00) +4.44% (p=0.000)
SetTypeNode124Slice 1.94µs × (1.00,1.01) 2.04µs × (0.99,1.01) +4.98% (p=0.000)
SetTypeNode126 75.4ns × (1.00,1.01) 77.7ns × (0.99,1.01) +3.11% (p=0.000)
SetTypeNode126Slice 1.95µs × (0.99,1.01) 2.03µs × (1.00,1.00) +3.74% (p=0.000)
SetTypeNode128 85.4ns × (0.99,1.01) 122.0ns × (1.00,1.00) +42.89% (p=0.000)
SetTypeNode128Slice 2.20µs × (1.00,1.01) 2.36µs × (0.98,1.02) +7.48% (p=0.001)
SetTypeNode130 83.3ns × (1.00,1.00) 123.0ns × (1.00,1.00) +47.61% (p=0.000)
SetTypeNode130Slice 2.30µs × (0.99,1.01) 2.40µs × (0.98,1.01) +4.37% (p=0.000)
SetTypeNode1024 498ns × (1.00,1.00) 537ns × (1.00,1.00) +7.96% (p=0.000)
SetTypeNode1024Slice 15.5µs × (0.99,1.01) 17.8µs × (1.00,1.00) +15.27% (p=0.000)
The above compares always using a cached pointer mask (and the
corresponding waste of memory) against using the programs directly.
Some slowdown is expected, in exchange for having a better general algorithm.
The GC programs kick in for SetTypeNode128, SetTypeNode130, SetTypeNode1024,
along with the slice variants of those.
It is possible that the cutoff of 128 words (bits) should be raised
in a followup CL, but even with this low cutoff the GC programs are
faster than Go 1.4's "fast path" non-GC program case.
Benchmarks for heapBitsSetType, Go 1.4 vs this CL:
name old mean new mean delta
SetTypePtr 6.89ns × (1.00,1.00) 5.17ns × (1.00,1.00) -25.02% (p=0.000)
SetTypePtr8 25.8ns × (0.97,1.05) 21.5ns × (1.00,1.00) -16.70% (p=0.000)
SetTypePtr16 39.8ns × (0.97,1.02) 24.7ns × (0.99,1.01) -37.81% (p=0.000)
SetTypePtr32 68.8ns × (0.98,1.01) 32.2ns × (1.00,1.01) -53.18% (p=0.000)
SetTypePtr64 130ns × (1.00,1.00) 47ns × (1.00,1.00) -63.67% (p=0.000)
SetTypePtr126 241ns × (0.99,1.01) 79ns × (1.00,1.01) -67.25% (p=0.000)
SetTypePtr128 2.07µs × (1.00,1.00) 0.08µs × (1.00,1.00) -96.27% (p=0.000)
SetTypePtrSlice 1.05µs × (0.99,1.01) 0.72µs × (0.99,1.02) -31.70% (p=0.000)
SetTypeNode1 16.0ns × (0.99,1.01) 20.8ns × (0.99,1.03) +29.91% (p=0.000)
SetTypeNode1Slice 184ns × (0.99,1.01) 112ns × (0.99,1.01) -39.26% (p=0.000)
SetTypeNode8 29.5ns × (0.97,1.02) 24.6ns × (1.00,1.00) -16.50% (p=0.000)
SetTypeNode8Slice 624ns × (0.98,1.02) 285ns × (1.00,1.00) -54.31% (p=0.000)
SetTypeNode64 135ns × (0.96,1.08) 52ns × (0.99,1.02) -61.32% (p=0.000)
SetTypeNode64Slice 3.83µs × (1.00,1.00) 1.14µs × (0.99,1.01) -70.16% (p=0.000)
SetTypeNode64Dead 134ns × (0.99,1.01) 32ns × (1.00,1.01) -75.74% (p=0.000)
SetTypeNode64DeadSlice 3.83µs × (0.99,1.00) 1.40µs × (1.00,1.01) -63.42% (p=0.000)
SetTypeNode124 240ns × (0.99,1.01) 79ns × (1.00,1.01) -67.05% (p=0.000)
SetTypeNode124Slice 7.27µs × (1.00,1.00) 2.04µs × (1.00,1.00) -71.95% (p=0.000)
SetTypeNode126 2.06µs × (0.99,1.01) 0.08µs × (0.99,1.01) -96.23% (p=0.000)
SetTypeNode126Slice 64.4µs × (1.00,1.00) 2.0µs × (1.00,1.00) -96.85% (p=0.000)
SetTypeNode128 2.09µs × (1.00,1.01) 0.12µs × (1.00,1.00) -94.15% (p=0.000)
SetTypeNode128Slice 65.4µs × (1.00,1.00) 2.4µs × (0.99,1.03) -96.39% (p=0.000)
SetTypeNode130 2.11µs × (1.00,1.00) 0.12µs × (1.00,1.00) -94.18% (p=0.000)
SetTypeNode130Slice 66.3µs × (1.00,1.00) 2.4µs × (0.97,1.08) -96.34% (p=0.000)
SetTypeNode1024 16.0µs × (1.00,1.01) 0.5µs × (1.00,1.00) -96.65% (p=0.000)
SetTypeNode1024Slice 512µs × (1.00,1.00) 18µs × (0.98,1.04) -96.45% (p=0.000)
SetTypeNode124 uses a 124 data + 2 ptr = 126-word allocation.
Both Go 1.4 and this CL are using pointer bitmaps for this case,
so that's an overall 3x speedup for using pointer bitmaps.
SetTypeNode128 uses a 128 data + 2 ptr = 130-word allocation.
Both Go 1.4 and this CL are running the GC program for this case,
so that's an overall 17x speedup when using GC programs (and
I've seen >20x on other systems).
Comparing Go 1.4's SetTypeNode124 (pointer bitmap) against
this CL's SetTypeNode128 (GC program), the slow path in the
code in this CL is 2x faster than the fast path in Go 1.4.
The Go 1 benchmarks are basically unaffected compared to just before this CL.
Go 1 benchmarks, before this CL vs this CL:
name old mean new mean delta
BinaryTree17 5.87s × (0.97,1.04) 5.91s × (0.96,1.04) ~ (p=0.306)
Fannkuch11 4.38s × (1.00,1.00) 4.37s × (1.00,1.01) -0.22% (p=0.006)
FmtFprintfEmpty 90.7ns × (0.97,1.10) 89.3ns × (0.96,1.09) ~ (p=0.280)
FmtFprintfString 282ns × (0.98,1.04) 287ns × (0.98,1.07) +1.72% (p=0.039)
FmtFprintfInt 269ns × (0.99,1.03) 282ns × (0.97,1.04) +4.87% (p=0.000)
FmtFprintfIntInt 478ns × (0.99,1.02) 481ns × (0.99,1.02) +0.61% (p=0.048)
FmtFprintfPrefixedInt 399ns × (0.98,1.03) 400ns × (0.98,1.05) ~ (p=0.533)
FmtFprintfFloat 563ns × (0.99,1.01) 570ns × (1.00,1.01) +1.37% (p=0.000)
FmtManyArgs 1.89µs × (0.99,1.01) 1.92µs × (0.99,1.02) +1.88% (p=0.000)
GobDecode 15.2ms × (0.99,1.01) 15.2ms × (0.98,1.05) ~ (p=0.609)
GobEncode 11.6ms × (0.98,1.03) 11.9ms × (0.98,1.04) +2.17% (p=0.000)
Gzip 648ms × (0.99,1.01) 648ms × (1.00,1.01) ~ (p=0.835)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) ~ (p=0.169)
HTTPClientServer 90.5µs × (0.98,1.03) 91.5µs × (0.98,1.04) +1.04% (p=0.045)
JSONEncode 31.5ms × (0.98,1.03) 31.4ms × (0.98,1.03) ~ (p=0.549)
JSONDecode 111ms × (0.99,1.01) 107ms × (0.99,1.01) -3.21% (p=0.000)
Mandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~ (p=0.878)
GoParse 6.54ms × (0.99,1.02) 6.61ms × (0.99,1.03) +1.08% (p=0.004)
RegexpMatchEasy0_32 160ns × (1.00,1.01) 161ns × (1.00,1.00) +0.40% (p=0.000)
RegexpMatchEasy0_1K 560ns × (0.99,1.01) 559ns × (0.99,1.01) ~ (p=0.088)
RegexpMatchEasy1_32 138ns × (0.99,1.01) 138ns × (1.00,1.00) ~ (p=0.380)
RegexpMatchEasy1_1K 877ns × (1.00,1.00) 878ns × (1.00,1.00) ~ (p=0.157)
RegexpMatchMedium_32 251ns × (0.99,1.00) 251ns × (1.00,1.01) +0.28% (p=0.021)
RegexpMatchMedium_1K 72.6µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.539)
RegexpMatchHard_32 3.84µs × (1.00,1.00) 3.84µs × (1.00,1.00) ~ (p=0.378)
RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) ~ (p=0.067)
Revcomp 904ms × (0.99,1.02) 904ms × (0.99,1.01) ~ (p=0.943)
Template 125ms × (0.99,1.02) 127ms × (0.99,1.01) +1.79% (p=0.000)
TimeParse 627ns × (0.99,1.01) 622ns × (0.99,1.01) -0.88% (p=0.000)
TimeFormat 655ns × (0.99,1.02) 655ns × (0.99,1.02) ~ (p=0.976)
For the record, Go 1 benchmarks, Go 1.4 vs this CL:
name old mean new mean delta
BinaryTree17 4.61s × (0.97,1.05) 5.91s × (0.98,1.03) +28.35% (p=0.000)
Fannkuch11 4.40s × (0.99,1.03) 4.41s × (0.99,1.01) ~ (p=0.212)
FmtFprintfEmpty 102ns × (0.99,1.01) 84ns × (0.99,1.02) -18.38% (p=0.000)
FmtFprintfString 302ns × (0.98,1.01) 303ns × (0.99,1.02) ~ (p=0.203)
FmtFprintfInt 313ns × (0.97,1.05) 270ns × (0.99,1.01) -13.69% (p=0.000)
FmtFprintfIntInt 524ns × (0.98,1.02) 477ns × (0.99,1.00) -8.87% (p=0.000)
FmtFprintfPrefixedInt 424ns × (0.98,1.02) 386ns × (0.99,1.01) -8.96% (p=0.000)
FmtFprintfFloat 652ns × (0.98,1.02) 594ns × (0.97,1.05) -8.97% (p=0.000)
FmtManyArgs 2.13µs × (0.99,1.02) 1.94µs × (0.99,1.01) -8.92% (p=0.000)
GobDecode 17.1ms × (0.99,1.02) 14.9ms × (0.98,1.03) -13.07% (p=0.000)
GobEncode 13.5ms × (0.98,1.03) 11.5ms × (0.98,1.03) -15.25% (p=0.000)
Gzip 656ms × (0.99,1.02) 647ms × (0.99,1.01) -1.29% (p=0.000)
Gunzip 143ms × (0.99,1.02) 144ms × (0.99,1.01) ~ (p=0.204)
HTTPClientServer 88.2µs × (0.98,1.02) 90.8µs × (0.98,1.01) +2.93% (p=0.000)
JSONEncode 32.2ms × (0.98,1.02) 30.9ms × (0.97,1.04) -4.06% (p=0.001)
JSONDecode 121ms × (0.98,1.02) 110ms × (0.98,1.05) -8.95% (p=0.000)
Mandelbrot200 6.06ms × (0.99,1.01) 6.11ms × (0.98,1.04) ~ (p=0.184)
GoParse 6.76ms × (0.97,1.04) 6.58ms × (0.98,1.05) -2.63% (p=0.003)
RegexpMatchEasy0_32 195ns × (1.00,1.01) 155ns × (0.99,1.01) -20.43% (p=0.000)
RegexpMatchEasy0_1K 479ns × (0.98,1.03) 535ns × (0.99,1.02) +11.59% (p=0.000)
RegexpMatchEasy1_32 169ns × (0.99,1.02) 131ns × (0.99,1.03) -22.44% (p=0.000)
RegexpMatchEasy1_1K 1.53µs × (0.99,1.01) 0.87µs × (0.99,1.02) -43.07% (p=0.000)
RegexpMatchMedium_32 334ns × (0.99,1.01) 242ns × (0.99,1.01) -27.53% (p=0.000)
RegexpMatchMedium_1K 125µs × (1.00,1.01) 72µs × (0.99,1.03) -42.53% (p=0.000)
RegexpMatchHard_32 6.03µs × (0.99,1.01) 3.79µs × (0.99,1.01) -37.12% (p=0.000)
RegexpMatchHard_1K 189µs × (0.99,1.02) 115µs × (0.99,1.01) -39.20% (p=0.000)
Revcomp 935ms × (0.96,1.03) 926ms × (0.98,1.02) ~ (p=0.083)
Template 146ms × (0.97,1.05) 119ms × (0.99,1.01) -18.37% (p=0.000)
TimeParse 660ns × (0.99,1.01) 624ns × (0.99,1.02) -5.43% (p=0.000)
TimeFormat 670ns × (0.98,1.02) 710ns × (1.00,1.01) +5.97% (p=0.000)
This CL is a bit larger than I would like, but the compiler, linker, runtime,
and package reflect all need to be in sync about the format of these programs,
so there is no easy way to split this into independent changes (at least
while keeping the build working at each change).
Fixes #9625.
Fixes #10524.
Change-Id: I9e3e20d6097099d0f8532d1cb5b1af528804989a
Reviewed-on: https://go-review.googlesource.com/9888
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
2015-05-08 01:43:18 -04:00
|
|
|
{"slice", &Debug_slice}, // print information about slice compilation
|
2015-03-20 00:06:10 -04:00
|
|
|
{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
|
2015-04-17 00:34:18 -04:00
|
|
|
{"wb", &Debug_wb}, // print information about write barriers
|
2015-08-13 19:05:37 -07:00
|
|
|
{"export", &Debug_export}, // print export data
|
2015-03-08 18:46:28 -04:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
EOF = -1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func usage() {
|
2015-08-22 20:29:33 +09:00
|
|
|
fmt.Printf("usage: compile [options] file.go...\n")
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagprint(1)
|
2015-02-23 10:22:26 -05:00
|
|
|
Exit(2)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 14:02:27 -05:00
|
|
|
func hidePanic() {
|
2015-05-24 03:58:03 -04:00
|
|
|
if Debug_panic == 0 && nsavederrors+nerrors > 0 {
|
2015-02-23 14:02:27 -05:00
|
|
|
// If we've already complained about things
|
|
|
|
|
// in the program, don't bother complaining
|
|
|
|
|
// about a panic too; let the user clean up
|
|
|
|
|
// the code and try again.
|
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func doversion() {
|
2015-02-23 16:07:24 -05:00
|
|
|
p := obj.Expstring()
|
2015-02-13 14:40:36 -05:00
|
|
|
if p == "X:none" {
|
|
|
|
|
p = ""
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
sep := ""
|
2015-02-23 14:02:27 -05:00
|
|
|
if p != "" {
|
2015-02-13 14:40:36 -05:00
|
|
|
sep = " "
|
|
|
|
|
}
|
2015-08-22 20:29:33 +09:00
|
|
|
fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
|
2015-02-13 14:40:36 -05:00
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Main() {
|
2015-02-23 14:02:27 -05:00
|
|
|
defer hidePanic()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
|
|
|
|
|
// but not other values.
|
2015-02-23 16:07:24 -05:00
|
|
|
p := obj.Getgoarch()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if !strings.HasPrefix(p, Thearch.Thestring) {
|
|
|
|
|
log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
|
|
|
|
|
}
|
|
|
|
|
goarch = p
|
|
|
|
|
|
|
|
|
|
Thearch.Linkarchinit()
|
|
|
|
|
Ctxt = obj.Linknew(Thearch.Thelinkarch)
|
2016-01-24 01:33:16 -05:00
|
|
|
Ctxt.DiagFunc = Yyerror
|
2015-02-13 14:40:36 -05:00
|
|
|
Ctxt.Bso = &bstdout
|
|
|
|
|
bstdout = *obj.Binitw(os.Stdout)
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
localpkg = mkpkg("")
|
2015-02-13 14:40:36 -05:00
|
|
|
localpkg.Prefix = "\"\""
|
|
|
|
|
|
|
|
|
|
// pseudo-package, for scoping
|
2015-03-02 16:03:26 -05:00
|
|
|
builtinpkg = mkpkg("go.builtin")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
|
|
|
|
|
|
|
|
|
|
// pseudo-package, accessed by import "unsafe"
|
2015-03-02 16:03:26 -05:00
|
|
|
unsafepkg = mkpkg("unsafe")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
unsafepkg.Name = "unsafe"
|
|
|
|
|
|
|
|
|
|
// real package, referred to by generated runtime calls
|
2015-03-02 16:03:26 -05:00
|
|
|
Runtimepkg = mkpkg("runtime")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
Runtimepkg.Name = "runtime"
|
|
|
|
|
|
|
|
|
|
// pseudo-packages used in symbol tables
|
2015-03-02 16:03:26 -05:00
|
|
|
gostringpkg = mkpkg("go.string")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gostringpkg.Name = "go.string"
|
|
|
|
|
gostringpkg.Prefix = "go.string" // not go%2estring
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
itabpkg = mkpkg("go.itab")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
itabpkg.Name = "go.itab"
|
|
|
|
|
itabpkg.Prefix = "go.itab" // not go%2eitab
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
typelinkpkg = mkpkg("go.typelink")
|
2015-02-13 14:40:36 -05:00
|
|
|
typelinkpkg.Name = "go.typelink"
|
|
|
|
|
typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
trackpkg = mkpkg("go.track")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
trackpkg.Name = "go.track"
|
|
|
|
|
trackpkg.Prefix = "go.track" // not go%2etrack
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
typepkg = mkpkg("type")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
typepkg.Name = "type"
|
|
|
|
|
|
|
|
|
|
goroot = obj.Getgoroot()
|
|
|
|
|
goos = obj.Getgoos()
|
|
|
|
|
|
|
|
|
|
Nacl = goos == "nacl"
|
|
|
|
|
if Nacl {
|
|
|
|
|
flag_largemodel = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outfile = ""
|
|
|
|
|
obj.Flagcount("+", "compiling runtime", &compiling_runtime)
|
|
|
|
|
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
|
|
|
|
|
obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
|
|
|
|
|
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("D", "set relative `path` for local imports", &localimport)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("E", "debug symbol export", &Debug['E'])
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagfn1("I", "add `directory` to import search path", addidir)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
|
|
|
|
|
obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
|
|
|
|
|
obj.Flagcount("M", "debug move generation", &Debug['M'])
|
|
|
|
|
obj.Flagcount("N", "disable optimizations", &Debug['N'])
|
|
|
|
|
obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
|
|
|
|
|
obj.Flagcount("R", "debug register optimizer", &Debug['R'])
|
|
|
|
|
obj.Flagcount("S", "print assembly listing", &Debug['S'])
|
|
|
|
|
obj.Flagfn0("V", "print compiler version", doversion)
|
|
|
|
|
obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
|
2015-04-19 23:56:30 -04:00
|
|
|
obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
|
|
|
|
|
obj.Flagcount("f", "debug stack frames", &Debug['f'])
|
|
|
|
|
obj.Flagcount("g", "debug code generation", &Debug['g'])
|
|
|
|
|
obj.Flagcount("h", "halt on error", &Debug['h'])
|
|
|
|
|
obj.Flagcount("i", "debug line number stack", &Debug['i'])
|
2015-06-09 12:08:59 -07:00
|
|
|
obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
|
|
|
|
|
obj.Flagcount("l", "disable inlining", &Debug['l'])
|
|
|
|
|
obj.Flagcount("live", "debug liveness analysis", &debuglive)
|
|
|
|
|
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
|
2015-10-21 07:04:10 -07:00
|
|
|
obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
|
2015-11-13 16:28:46 -08:00
|
|
|
obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("o", "write output to `file`", &outfile)
|
|
|
|
|
obj.Flagstr("p", "set expected package import `path`", &myimportpath)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("pack", "write package file instead of object file", &writearchive)
|
|
|
|
|
obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
|
|
|
|
|
obj.Flagcount("race", "enable race detector", &flag_race)
|
|
|
|
|
obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagcount("u", "reject unsafe code", &safemode)
|
|
|
|
|
obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
|
|
|
|
|
obj.Flagcount("w", "debug type checking", &Debug['w'])
|
|
|
|
|
use_writebarrier = 1
|
|
|
|
|
obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
|
|
|
|
|
obj.Flagcount("x", "debug lexer", &Debug['x'])
|
|
|
|
|
obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
|
2015-02-10 15:56:32 +13:00
|
|
|
var flag_shared int
|
2015-03-30 00:49:25 +00:00
|
|
|
var flag_dynlink bool
|
2015-10-28 17:57:30 -04:00
|
|
|
switch Thearch.Thechar {
|
2015-11-11 16:34:06 -05:00
|
|
|
case '5', '6', '7', '8', '9':
|
2015-09-01 14:03:38 +12:00
|
|
|
obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
if Thearch.Thechar == '6' {
|
|
|
|
|
obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
|
2015-09-23 21:02:50 +12:00
|
|
|
}
|
2015-10-29 20:24:29 +13:00
|
|
|
switch Thearch.Thechar {
|
|
|
|
|
case '5', '6', '7', '8', '9':
|
2015-03-30 00:49:25 +00:00
|
|
|
flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-01 16:14:50 -07:00
|
|
|
obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
|
|
|
|
|
obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
|
|
|
|
|
obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
|
2016-03-03 22:06:57 -08:00
|
|
|
flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
|
2015-02-13 14:40:36 -05:00
|
|
|
obj.Flagparse(usage)
|
2015-03-30 00:49:25 +00:00
|
|
|
|
|
|
|
|
if flag_dynlink {
|
|
|
|
|
flag_shared = 1
|
|
|
|
|
}
|
2015-02-10 15:56:32 +13:00
|
|
|
Ctxt.Flag_shared = int32(flag_shared)
|
2015-03-30 00:49:25 +00:00
|
|
|
Ctxt.Flag_dynlink = flag_dynlink
|
2016-02-23 10:54:36 -08:00
|
|
|
Ctxt.Flag_optimize = Debug['N'] == 0
|
2015-03-30 00:49:25 +00:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
Ctxt.Debugasm = int32(Debug['S'])
|
|
|
|
|
Ctxt.Debugvlog = int32(Debug['v'])
|
|
|
|
|
|
|
|
|
|
if flag.NArg() < 1 {
|
|
|
|
|
usage()
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 10:22:26 -05:00
|
|
|
startProfile()
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
if flag_race != 0 {
|
2015-03-02 16:03:26 -05:00
|
|
|
racepkg = mkpkg("runtime/race")
|
2015-02-13 14:40:36 -05:00
|
|
|
racepkg.Name = "race"
|
2015-10-21 07:04:10 -07:00
|
|
|
}
|
|
|
|
|
if flag_msan != 0 {
|
|
|
|
|
msanpkg = mkpkg("runtime/msan")
|
|
|
|
|
msanpkg.Name = "msan"
|
|
|
|
|
}
|
|
|
|
|
if flag_race != 0 && flag_msan != 0 {
|
2016-01-27 12:49:13 -08:00
|
|
|
log.Fatal("cannot use both -race and -msan")
|
2015-10-21 07:04:10 -07:00
|
|
|
} else if flag_race != 0 || flag_msan != 0 {
|
2015-10-20 10:00:07 -07:00
|
|
|
instrumenting = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parse -d argument
|
|
|
|
|
if debugstr != "" {
|
cmd/internal/gc: accept comma-separated list of name=value for -d
This should obviously have no performance impact.
Listing numbers just as a sanity check for the benchmark
comparison program: it should (and does) find nothing
to report.
name old new delta
BenchmarkBinaryTree17 18.0s × (0.99,1.01) 17.9s × (0.99,1.00) ~
BenchmarkFannkuch11 4.36s × (1.00,1.00) 4.35s × (1.00,1.00) ~
BenchmarkFmtFprintfEmpty 120ns × (0.99,1.06) 120ns × (0.94,1.05) ~
BenchmarkFmtFprintfString 480ns × (0.99,1.01) 477ns × (1.00,1.00) ~
BenchmarkFmtFprintfInt 451ns × (0.99,1.01) 450ns × (0.99,1.01) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 765ns × (0.99,1.01) ~
BenchmarkFmtFprintfPrefixedInt 569ns × (0.99,1.01) 569ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 728ns × (1.00,1.01) 728ns × (1.00,1.00) ~
BenchmarkFmtManyArgs 2.81µs × (1.00,1.01) 2.82µs × (0.99,1.01) ~
BenchmarkGobDecode 39.4ms × (0.99,1.01) 39.1ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (0.99,1.00) 39.4ms × (0.99,1.01) ~
BenchmarkGzip 660ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 143ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 133µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 57.3ms × (0.99,1.04) ~
BenchmarkJSONDecode 138ms × (1.00,1.01) 139ms × (0.99,1.00) ~
BenchmarkMandelbrot200 6.02ms × (1.00,1.00) 6.02ms × (1.00,1.00) ~
BenchmarkGoParse 9.79ms × (0.92,1.07) 9.72ms × (0.92,1.11) ~
BenchmarkRegexpMatchEasy0_32 210ns × (1.00,1.01) 209ns × (1.00,1.01) ~
BenchmarkRegexpMatchEasy0_1K 593ns × (0.99,1.01) 592ns × (0.99,1.00) ~
BenchmarkRegexpMatchEasy1_32 182ns × (0.99,1.01) 183ns × (0.98,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.01) 1.01µs × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_32 331ns × (1.00,1.00) 330ns × (1.00,1.00) ~
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.01) 92.4µs × (1.00,1.00) ~
BenchmarkRegexpMatchHard_32 4.58µs × (0.99,1.05) 4.77µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.01) 136µs × (1.00,1.00) ~
BenchmarkRevcomp 900ms × (0.99,1.06) 906ms × (0.99,1.05) ~
BenchmarkTemplate 171ms × (1.00,1.01) 171ms × (0.99,1.01) ~
BenchmarkTimeParse 637ns × (1.00,1.00) 638ns × (1.00,1.00) ~
BenchmarkTimeFormat 742ns × (1.00,1.00) 745ns × (0.99,1.02) ~
Change-Id: I59ec875715cb176bbffa709546370a6a7fc5a75d
Reviewed-on: https://go-review.googlesource.com/9309
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 11:45:11 -04:00
|
|
|
Split:
|
|
|
|
|
for _, name := range strings.Split(debugstr, ",") {
|
|
|
|
|
if name == "" {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
cmd/internal/gc: accept comma-separated list of name=value for -d
This should obviously have no performance impact.
Listing numbers just as a sanity check for the benchmark
comparison program: it should (and does) find nothing
to report.
name old new delta
BenchmarkBinaryTree17 18.0s × (0.99,1.01) 17.9s × (0.99,1.00) ~
BenchmarkFannkuch11 4.36s × (1.00,1.00) 4.35s × (1.00,1.00) ~
BenchmarkFmtFprintfEmpty 120ns × (0.99,1.06) 120ns × (0.94,1.05) ~
BenchmarkFmtFprintfString 480ns × (0.99,1.01) 477ns × (1.00,1.00) ~
BenchmarkFmtFprintfInt 451ns × (0.99,1.01) 450ns × (0.99,1.01) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 765ns × (0.99,1.01) ~
BenchmarkFmtFprintfPrefixedInt 569ns × (0.99,1.01) 569ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 728ns × (1.00,1.01) 728ns × (1.00,1.00) ~
BenchmarkFmtManyArgs 2.81µs × (1.00,1.01) 2.82µs × (0.99,1.01) ~
BenchmarkGobDecode 39.4ms × (0.99,1.01) 39.1ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (0.99,1.00) 39.4ms × (0.99,1.01) ~
BenchmarkGzip 660ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 143ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 133µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 57.3ms × (0.99,1.04) ~
BenchmarkJSONDecode 138ms × (1.00,1.01) 139ms × (0.99,1.00) ~
BenchmarkMandelbrot200 6.02ms × (1.00,1.00) 6.02ms × (1.00,1.00) ~
BenchmarkGoParse 9.79ms × (0.92,1.07) 9.72ms × (0.92,1.11) ~
BenchmarkRegexpMatchEasy0_32 210ns × (1.00,1.01) 209ns × (1.00,1.01) ~
BenchmarkRegexpMatchEasy0_1K 593ns × (0.99,1.01) 592ns × (0.99,1.00) ~
BenchmarkRegexpMatchEasy1_32 182ns × (0.99,1.01) 183ns × (0.98,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.01) 1.01µs × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_32 331ns × (1.00,1.00) 330ns × (1.00,1.00) ~
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.01) 92.4µs × (1.00,1.00) ~
BenchmarkRegexpMatchHard_32 4.58µs × (0.99,1.05) 4.77µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.01) 136µs × (1.00,1.00) ~
BenchmarkRevcomp 900ms × (0.99,1.06) 906ms × (0.99,1.05) ~
BenchmarkTemplate 171ms × (1.00,1.01) 171ms × (0.99,1.01) ~
BenchmarkTimeParse 637ns × (1.00,1.00) 638ns × (1.00,1.00) ~
BenchmarkTimeFormat 742ns × (1.00,1.00) 745ns × (0.99,1.02) ~
Change-Id: I59ec875715cb176bbffa709546370a6a7fc5a75d
Reviewed-on: https://go-review.googlesource.com/9309
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 11:45:11 -04:00
|
|
|
val := 1
|
|
|
|
|
if i := strings.Index(name, "="); i >= 0 {
|
|
|
|
|
var err error
|
|
|
|
|
val, err = strconv.Atoi(name[i+1:])
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("invalid debug value %v", name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
cmd/internal/gc: accept comma-separated list of name=value for -d
This should obviously have no performance impact.
Listing numbers just as a sanity check for the benchmark
comparison program: it should (and does) find nothing
to report.
name old new delta
BenchmarkBinaryTree17 18.0s × (0.99,1.01) 17.9s × (0.99,1.00) ~
BenchmarkFannkuch11 4.36s × (1.00,1.00) 4.35s × (1.00,1.00) ~
BenchmarkFmtFprintfEmpty 120ns × (0.99,1.06) 120ns × (0.94,1.05) ~
BenchmarkFmtFprintfString 480ns × (0.99,1.01) 477ns × (1.00,1.00) ~
BenchmarkFmtFprintfInt 451ns × (0.99,1.01) 450ns × (0.99,1.01) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 765ns × (0.99,1.01) ~
BenchmarkFmtFprintfPrefixedInt 569ns × (0.99,1.01) 569ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 728ns × (1.00,1.01) 728ns × (1.00,1.00) ~
BenchmarkFmtManyArgs 2.81µs × (1.00,1.01) 2.82µs × (0.99,1.01) ~
BenchmarkGobDecode 39.4ms × (0.99,1.01) 39.1ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (0.99,1.00) 39.4ms × (0.99,1.01) ~
BenchmarkGzip 660ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 143ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 133µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 57.3ms × (0.99,1.04) ~
BenchmarkJSONDecode 138ms × (1.00,1.01) 139ms × (0.99,1.00) ~
BenchmarkMandelbrot200 6.02ms × (1.00,1.00) 6.02ms × (1.00,1.00) ~
BenchmarkGoParse 9.79ms × (0.92,1.07) 9.72ms × (0.92,1.11) ~
BenchmarkRegexpMatchEasy0_32 210ns × (1.00,1.01) 209ns × (1.00,1.01) ~
BenchmarkRegexpMatchEasy0_1K 593ns × (0.99,1.01) 592ns × (0.99,1.00) ~
BenchmarkRegexpMatchEasy1_32 182ns × (0.99,1.01) 183ns × (0.98,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.01) 1.01µs × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_32 331ns × (1.00,1.00) 330ns × (1.00,1.00) ~
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.01) 92.4µs × (1.00,1.00) ~
BenchmarkRegexpMatchHard_32 4.58µs × (0.99,1.05) 4.77µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.01) 136µs × (1.00,1.00) ~
BenchmarkRevcomp 900ms × (0.99,1.06) 906ms × (0.99,1.05) ~
BenchmarkTemplate 171ms × (1.00,1.01) 171ms × (0.99,1.01) ~
BenchmarkTimeParse 637ns × (1.00,1.00) 638ns × (1.00,1.00) ~
BenchmarkTimeFormat 742ns × (1.00,1.00) 745ns × (0.99,1.02) ~
Change-Id: I59ec875715cb176bbffa709546370a6a7fc5a75d
Reviewed-on: https://go-review.googlesource.com/9309
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 11:45:11 -04:00
|
|
|
name = name[:i]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
cmd/internal/gc: accept comma-separated list of name=value for -d
This should obviously have no performance impact.
Listing numbers just as a sanity check for the benchmark
comparison program: it should (and does) find nothing
to report.
name old new delta
BenchmarkBinaryTree17 18.0s × (0.99,1.01) 17.9s × (0.99,1.00) ~
BenchmarkFannkuch11 4.36s × (1.00,1.00) 4.35s × (1.00,1.00) ~
BenchmarkFmtFprintfEmpty 120ns × (0.99,1.06) 120ns × (0.94,1.05) ~
BenchmarkFmtFprintfString 480ns × (0.99,1.01) 477ns × (1.00,1.00) ~
BenchmarkFmtFprintfInt 451ns × (0.99,1.01) 450ns × (0.99,1.01) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 765ns × (0.99,1.01) ~
BenchmarkFmtFprintfPrefixedInt 569ns × (0.99,1.01) 569ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 728ns × (1.00,1.01) 728ns × (1.00,1.00) ~
BenchmarkFmtManyArgs 2.81µs × (1.00,1.01) 2.82µs × (0.99,1.01) ~
BenchmarkGobDecode 39.4ms × (0.99,1.01) 39.1ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (0.99,1.00) 39.4ms × (0.99,1.01) ~
BenchmarkGzip 660ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 143ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 133µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 57.3ms × (0.99,1.04) ~
BenchmarkJSONDecode 138ms × (1.00,1.01) 139ms × (0.99,1.00) ~
BenchmarkMandelbrot200 6.02ms × (1.00,1.00) 6.02ms × (1.00,1.00) ~
BenchmarkGoParse 9.79ms × (0.92,1.07) 9.72ms × (0.92,1.11) ~
BenchmarkRegexpMatchEasy0_32 210ns × (1.00,1.01) 209ns × (1.00,1.01) ~
BenchmarkRegexpMatchEasy0_1K 593ns × (0.99,1.01) 592ns × (0.99,1.00) ~
BenchmarkRegexpMatchEasy1_32 182ns × (0.99,1.01) 183ns × (0.98,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.01) 1.01µs × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_32 331ns × (1.00,1.00) 330ns × (1.00,1.00) ~
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.01) 92.4µs × (1.00,1.00) ~
BenchmarkRegexpMatchHard_32 4.58µs × (0.99,1.05) 4.77µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.01) 136µs × (1.00,1.00) ~
BenchmarkRevcomp 900ms × (0.99,1.06) 906ms × (0.99,1.05) ~
BenchmarkTemplate 171ms × (1.00,1.01) 171ms × (0.99,1.01) ~
BenchmarkTimeParse 637ns × (1.00,1.00) 638ns × (1.00,1.00) ~
BenchmarkTimeFormat 742ns × (1.00,1.00) 745ns × (0.99,1.02) ~
Change-Id: I59ec875715cb176bbffa709546370a6a7fc5a75d
Reviewed-on: https://go-review.googlesource.com/9309
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 11:45:11 -04:00
|
|
|
for _, t := range debugtab {
|
|
|
|
|
if t.name == name {
|
|
|
|
|
if t.val != nil {
|
|
|
|
|
*t.val = val
|
|
|
|
|
continue Split
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
[dev.ssa] cmd/compile: enhance command line option processing for SSA
The -d compiler flag can also specify ssa phase and flag,
for example -d=ssa/generic_cse/time,ssa/generic_cse/stats
Spaces in the phase names can be specified with an
underscore. Flags currently parsed (not necessarily
recognized by the phases yet) are:
on, off, mem, time, debug, stats, and test
On, off and time are handled in the harness,
debug, stats, and test are interpreted by the phase itself.
The pass is now attached to the Func being compiled, and a
new method logStats(key, ...value) on *Func to encourage a
semi-standardized format for that output. Output fields
are separated by tabs to ease digestion by awk and
spreadsheets. For example,
if f.pass.stats > 0 {
f.logStat("CSE REWRITES", rewrites)
}
Change-Id: I16db2b5af64c50ca9a47efeb51d961147a903abc
Reviewed-on: https://go-review.googlesource.com/19885
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Todd Neal <todd@tneal.org>
2016-02-25 13:10:51 -05:00
|
|
|
// special case for ssa for now
|
|
|
|
|
if strings.HasPrefix(name, "ssa/") {
|
|
|
|
|
// expect form ssa/phase/flag
|
|
|
|
|
// e.g. -d=ssa/generic_cse/time
|
|
|
|
|
// _ in phase name also matches space
|
|
|
|
|
phase := name[4:]
|
|
|
|
|
flag := "debug" // default flag is debug
|
|
|
|
|
if i := strings.Index(phase, "/"); i >= 0 {
|
|
|
|
|
flag = phase[i+1:]
|
|
|
|
|
phase = phase[:i]
|
|
|
|
|
}
|
|
|
|
|
err := ssa.PhaseOption(phase, flag, val)
|
|
|
|
|
if err != "" {
|
|
|
|
|
log.Fatalf(err)
|
|
|
|
|
}
|
|
|
|
|
continue Split
|
|
|
|
|
}
|
cmd/internal/gc: accept comma-separated list of name=value for -d
This should obviously have no performance impact.
Listing numbers just as a sanity check for the benchmark
comparison program: it should (and does) find nothing
to report.
name old new delta
BenchmarkBinaryTree17 18.0s × (0.99,1.01) 17.9s × (0.99,1.00) ~
BenchmarkFannkuch11 4.36s × (1.00,1.00) 4.35s × (1.00,1.00) ~
BenchmarkFmtFprintfEmpty 120ns × (0.99,1.06) 120ns × (0.94,1.05) ~
BenchmarkFmtFprintfString 480ns × (0.99,1.01) 477ns × (1.00,1.00) ~
BenchmarkFmtFprintfInt 451ns × (0.99,1.01) 450ns × (0.99,1.01) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 765ns × (0.99,1.01) ~
BenchmarkFmtFprintfPrefixedInt 569ns × (0.99,1.01) 569ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 728ns × (1.00,1.01) 728ns × (1.00,1.00) ~
BenchmarkFmtManyArgs 2.81µs × (1.00,1.01) 2.82µs × (0.99,1.01) ~
BenchmarkGobDecode 39.4ms × (0.99,1.01) 39.1ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (0.99,1.00) 39.4ms × (0.99,1.01) ~
BenchmarkGzip 660ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 143ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 133µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 57.3ms × (0.99,1.04) ~
BenchmarkJSONDecode 138ms × (1.00,1.01) 139ms × (0.99,1.00) ~
BenchmarkMandelbrot200 6.02ms × (1.00,1.00) 6.02ms × (1.00,1.00) ~
BenchmarkGoParse 9.79ms × (0.92,1.07) 9.72ms × (0.92,1.11) ~
BenchmarkRegexpMatchEasy0_32 210ns × (1.00,1.01) 209ns × (1.00,1.01) ~
BenchmarkRegexpMatchEasy0_1K 593ns × (0.99,1.01) 592ns × (0.99,1.00) ~
BenchmarkRegexpMatchEasy1_32 182ns × (0.99,1.01) 183ns × (0.98,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.01) 1.01µs × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_32 331ns × (1.00,1.00) 330ns × (1.00,1.00) ~
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.01) 92.4µs × (1.00,1.00) ~
BenchmarkRegexpMatchHard_32 4.58µs × (0.99,1.05) 4.77µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.01) 136µs × (1.00,1.00) ~
BenchmarkRevcomp 900ms × (0.99,1.06) 906ms × (0.99,1.05) ~
BenchmarkTemplate 171ms × (1.00,1.01) 171ms × (0.99,1.01) ~
BenchmarkTimeParse 637ns × (1.00,1.00) 638ns × (1.00,1.00) ~
BenchmarkTimeFormat 742ns × (1.00,1.00) 745ns × (0.99,1.02) ~
Change-Id: I59ec875715cb176bbffa709546370a6a7fc5a75d
Reviewed-on: https://go-review.googlesource.com/9309
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 11:45:11 -04:00
|
|
|
log.Fatalf("unknown debug key -d %s\n", name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// enable inlining. for now:
|
|
|
|
|
// default: inlining on. (debug['l'] == 1)
|
|
|
|
|
// -l: inlining off (debug['l'] == 0)
|
|
|
|
|
// -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
|
|
|
|
|
if Debug['l'] <= 1 {
|
|
|
|
|
Debug['l'] = 1 - Debug['l']
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Betypeinit()
|
|
|
|
|
if Widthptr == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("betypeinit failed")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lexinit()
|
|
|
|
|
typeinit()
|
|
|
|
|
lexinit1()
|
|
|
|
|
|
|
|
|
|
blockgen = 1
|
|
|
|
|
dclcontext = PEXTERN
|
|
|
|
|
nerrors = 0
|
|
|
|
|
lexlineno = 1
|
|
|
|
|
|
2015-12-01 12:02:42 -08:00
|
|
|
loadsys()
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
for _, infile = range flag.Args() {
|
2015-11-23 14:11:15 -08:00
|
|
|
if trace && Debug['x'] != 0 {
|
2015-11-04 09:21:49 -08:00
|
|
|
fmt.Printf("--- %s ---\n", infile)
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-20 13:32:40 -07:00
|
|
|
linehistpush(infile)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-19 18:47:01 -08:00
|
|
|
bin, err := obj.Bopenr(infile)
|
2015-02-13 14:40:36 -05:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("open %s: %v\n", infile, err)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip initial BOM if present.
|
2016-02-19 18:47:01 -08:00
|
|
|
if obj.Bgetrune(bin) != BOM {
|
|
|
|
|
obj.Bungetrune(bin)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block = 1
|
|
|
|
|
iota_ = -1000000
|
|
|
|
|
|
2015-09-11 00:03:19 +02:00
|
|
|
imported_unsafe = false
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-19 18:47:01 -08:00
|
|
|
parse_file(bin)
|
2015-02-13 14:40:36 -05:00
|
|
|
if nsyntaxerrors != 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 11:53:20 -08:00
|
|
|
// Instead of converting EOF into '\n' in getc and count it as an extra line
|
|
|
|
|
// for the line history to work, and which then has to be corrected elsewhere,
|
|
|
|
|
// just add a line here.
|
|
|
|
|
lexlineno++
|
|
|
|
|
|
2015-04-20 13:32:40 -07:00
|
|
|
linehistpop()
|
2016-02-19 18:47:01 -08:00
|
|
|
obj.Bterm(bin)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
testdclstack()
|
|
|
|
|
mkpackage(localpkg.Name) // final import not used checks
|
|
|
|
|
lexfini()
|
|
|
|
|
|
2015-08-30 23:56:40 +02:00
|
|
|
typecheckok = true
|
2015-02-13 14:40:36 -05:00
|
|
|
if Debug['f'] != 0 {
|
|
|
|
|
frame(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process top-level declarations in phases.
|
|
|
|
|
|
|
|
|
|
// Phase 1: const, type, and names and types of funcs.
|
|
|
|
|
// This will gather all the information about types
|
|
|
|
|
// and methods but doesn't depend on any of it.
|
|
|
|
|
defercheckwidth()
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-06-05 10:39:23 -07:00
|
|
|
if l.N.Op != ODCL && l.N.Op != OAS && l.N.Op != OAS2 {
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&l.N, Etop)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 2: Variable assignments.
|
|
|
|
|
// To check interface assignments, depends on phase 1.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-06-05 10:39:23 -07:00
|
|
|
if l.N.Op == ODCL || l.N.Op == OAS || l.N.Op == OAS2 {
|
2015-02-13 14:40:36 -05:00
|
|
|
typecheck(&l.N, Etop)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
resumecheckwidth()
|
|
|
|
|
|
|
|
|
|
// Phase 3: Type check function bodies.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE {
|
|
|
|
|
Curfn = l.N
|
|
|
|
|
decldepth = 1
|
|
|
|
|
saveerrors()
|
2016-03-08 10:26:20 -08:00
|
|
|
typechecklist(l.N.Nbody.Slice(), Etop)
|
2015-02-13 14:40:36 -05:00
|
|
|
checkreturn(l.N)
|
|
|
|
|
if nerrors != 0 {
|
2016-02-27 14:31:33 -08:00
|
|
|
l.N.Nbody.Set(nil) // type errors; do not compile
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 4: Decide how to capture closed variables.
|
|
|
|
|
// This needs to run before escape analysis,
|
|
|
|
|
// because variables captured by value do not escape.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-05-27 00:44:05 -04:00
|
|
|
if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
Curfn = l.N
|
|
|
|
|
capturevars(l.N)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Curfn = nil
|
|
|
|
|
|
|
|
|
|
if nsavederrors+nerrors != 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 5: Inlining
|
|
|
|
|
if Debug['l'] > 1 {
|
|
|
|
|
// Typecheck imported function bodies if debug['l'] > 1,
|
|
|
|
|
// otherwise lazily when used or re-exported.
|
2015-09-06 22:38:49 +02:00
|
|
|
for _, n := range importlist {
|
2016-02-27 14:31:33 -08:00
|
|
|
if len(n.Func.Inl.Slice()) != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
saveerrors()
|
2015-09-06 22:38:49 +02:00
|
|
|
typecheckinl(n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nsavederrors+nerrors != 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Debug['l'] != 0 {
|
|
|
|
|
// Find functions that can be inlined and clone them before walk expands them.
|
2015-09-05 12:30:13 +10:00
|
|
|
visitBottomUp(xtop, func(list []*Node, recursive bool) {
|
|
|
|
|
// TODO: use a range statement here if the order does not matter
|
|
|
|
|
for i := len(list) - 1; i >= 0; i-- {
|
|
|
|
|
n := list[i]
|
|
|
|
|
if n.Op == ODCLFUNC {
|
|
|
|
|
caninl(n)
|
|
|
|
|
inlcalls(n)
|
2015-02-24 12:19:01 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-24 12:19:01 -05:00
|
|
|
})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 6: Escape analysis.
|
|
|
|
|
// Required for moving heap allocations onto stack,
|
|
|
|
|
// which in turn is required by the closure implementation,
|
|
|
|
|
// which stores the addresses of stack variables into the closure.
|
|
|
|
|
// If the closure does not escape, it needs to be on the stack
|
|
|
|
|
// or else the stack copier will not update it.
|
2015-05-20 15:16:34 -04:00
|
|
|
// Large values are also moved off stack in escape analysis;
|
|
|
|
|
// because large values may contain pointers, it must happen early.
|
2015-02-13 14:40:36 -05:00
|
|
|
escapes(xtop)
|
|
|
|
|
|
|
|
|
|
// Phase 7: Transform closure bodies to properly reference captured variables.
|
|
|
|
|
// This needs to happen before walk, because closures must be transformed
|
|
|
|
|
// before walk reaches a call of a closure.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-05-27 00:44:05 -04:00
|
|
|
if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
Curfn = l.N
|
|
|
|
|
transformclosure(l.N)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Curfn = nil
|
|
|
|
|
|
|
|
|
|
// Phase 8: Compile top level functions.
|
2015-02-23 16:07:24 -05:00
|
|
|
for l := xtop; l != nil; l = l.Next {
|
2015-02-13 14:40:36 -05:00
|
|
|
if l.N.Op == ODCLFUNC {
|
|
|
|
|
funccompile(l.N)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
|
|
|
|
fninit(xtop)
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-02 16:45:07 -05:00
|
|
|
if compiling_runtime != 0 {
|
|
|
|
|
checknowritebarrierrec()
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// Phase 9: Check external declarations.
|
2015-09-10 15:57:39 +10:00
|
|
|
for i, n := range externdcl {
|
|
|
|
|
if n.Op == ONAME {
|
|
|
|
|
typecheck(&externdcl[i], Erv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nerrors+nsavederrors != 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dumpobj()
|
|
|
|
|
|
|
|
|
|
if asmhdr != "" {
|
|
|
|
|
dumpasmhdr()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nerrors+nsavederrors != 0 {
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Flusherrors()
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-09 12:08:59 -07:00
|
|
|
var importMap = map[string]string{}
|
|
|
|
|
|
|
|
|
|
func addImportMap(s string) {
|
|
|
|
|
if strings.Count(s, "=") != 1 {
|
|
|
|
|
log.Fatal("-importmap argument must be of the form source=actual")
|
|
|
|
|
}
|
|
|
|
|
i := strings.Index(s, "=")
|
|
|
|
|
source, actual := s[:i], s[i+1:]
|
|
|
|
|
if source == "" || actual == "" {
|
|
|
|
|
log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
|
|
|
|
|
}
|
|
|
|
|
importMap[source] = actual
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func saveerrors() {
|
|
|
|
|
nsavederrors += nerrors
|
|
|
|
|
nerrors = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func arsize(b *obj.Biobuf, name string) int {
|
|
|
|
|
var buf [ArhdrSize]byte
|
|
|
|
|
if _, err := io.ReadFull(b, buf[:]); err != nil {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
aname := strings.Trim(string(buf[0:16]), " ")
|
|
|
|
|
if !strings.HasPrefix(aname, name) {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
asize := strings.Trim(string(buf[48:58]), " ")
|
|
|
|
|
i, _ := strconv.Atoi(asize)
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func skiptopkgdef(b *obj.Biobuf) bool {
|
2015-10-22 09:51:12 +09:00
|
|
|
// archive header
|
2015-02-23 16:07:24 -05:00
|
|
|
p := obj.Brdline(b, '\n')
|
2015-02-13 14:40:36 -05:00
|
|
|
if p == "" {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if obj.Blinelen(b) != 8 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if p != "!<arch>\n" {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 14:58:03 -08:00
|
|
|
// package export block should be first
|
|
|
|
|
sz := arsize(b, "__.PKGDEF")
|
|
|
|
|
return sz > 0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 23:01:10 -08:00
|
|
|
var idirs []string
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-19 23:01:10 -08:00
|
|
|
func addidir(dir string) {
|
|
|
|
|
if dir != "" {
|
|
|
|
|
idirs = append(idirs, dir)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isDriveLetter(b byte) bool {
|
|
|
|
|
return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// is this path a local name? begins with ./ or ../ or /
|
2015-03-02 16:03:26 -05:00
|
|
|
func islocalname(name string) bool {
|
|
|
|
|
return strings.HasPrefix(name, "/") ||
|
2016-02-22 23:07:30 -08:00
|
|
|
Ctxt.Windows != 0 && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
|
2015-03-02 16:03:26 -05:00
|
|
|
strings.HasPrefix(name, "./") || name == "." ||
|
|
|
|
|
strings.HasPrefix(name, "../") || name == ".."
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
func findpkg(name string) (file string, ok bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if islocalname(name) {
|
|
|
|
|
if safemode != 0 || nolocalimports != 0 {
|
2015-03-06 12:02:24 -08:00
|
|
|
return "", false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try .a before .6. important for building libraries:
|
|
|
|
|
// if there is an array.6 in the array.a library,
|
|
|
|
|
// want to find all of array.a, not just array.6.
|
2015-03-06 12:02:24 -08:00
|
|
|
file = fmt.Sprintf("%s.a", name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-21 13:28:17 -04:00
|
|
|
file = fmt.Sprintf("%s.o", name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-06 12:02:24 -08:00
|
|
|
return "", false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// local imports should be canonicalized already.
|
|
|
|
|
// don't want to see "encoding/../encoding/base64"
|
|
|
|
|
// as different from "encoding/base64".
|
2015-10-07 22:25:25 +00:00
|
|
|
if q := path.Clean(name); q != name {
|
2015-03-02 16:03:26 -05:00
|
|
|
Yyerror("non-canonical import path %q (should be %q)", name, q)
|
2015-03-06 12:02:24 -08:00
|
|
|
return "", false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 23:01:10 -08:00
|
|
|
for _, dir := range idirs {
|
|
|
|
|
file = fmt.Sprintf("%s/%s.a", dir, name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-19 23:01:10 -08:00
|
|
|
file = fmt.Sprintf("%s/%s.o", dir, name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if goroot != "" {
|
2015-02-23 16:07:24 -05:00
|
|
|
suffix := ""
|
|
|
|
|
suffixsep := ""
|
2015-02-13 14:40:36 -05:00
|
|
|
if flag_installsuffix != "" {
|
|
|
|
|
suffixsep = "_"
|
|
|
|
|
suffix = flag_installsuffix
|
|
|
|
|
} else if flag_race != 0 {
|
|
|
|
|
suffixsep = "_"
|
|
|
|
|
suffix = "race"
|
2015-10-21 07:04:10 -07:00
|
|
|
} else if flag_msan != 0 {
|
|
|
|
|
suffixsep = "_"
|
|
|
|
|
suffix = "msan"
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-21 13:28:17 -04:00
|
|
|
file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
|
2015-09-07 15:00:52 +12:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
2015-03-06 12:02:24 -08:00
|
|
|
return file, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
return "", false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:02:42 -08:00
|
|
|
// loadsys loads the definitions for the low-level runtime and unsafe functions,
|
|
|
|
|
// so that the compiler can generate calls to them,
|
|
|
|
|
// but does not make the names "runtime" or "unsafe" visible as packages.
|
|
|
|
|
func loadsys() {
|
|
|
|
|
if Debug['A'] != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block = 1
|
|
|
|
|
iota_ = -1000000
|
2016-02-19 18:47:01 -08:00
|
|
|
incannedimport = 1
|
2015-12-01 12:02:42 -08:00
|
|
|
|
|
|
|
|
importpkg = Runtimepkg
|
2016-02-19 18:51:24 -08:00
|
|
|
parse_import(obj.Binitr(strings.NewReader(runtimeimport)), nil)
|
2015-12-01 12:02:42 -08:00
|
|
|
|
|
|
|
|
importpkg = unsafepkg
|
2016-02-19 18:51:24 -08:00
|
|
|
parse_import(obj.Binitr(strings.NewReader(unsafeimport)), nil)
|
2015-12-01 12:02:42 -08:00
|
|
|
|
|
|
|
|
importpkg = nil
|
2016-02-19 18:47:01 -08:00
|
|
|
incannedimport = 0
|
2015-12-01 12:02:42 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 18:51:24 -08:00
|
|
|
func importfile(f *Val, indent []byte) {
|
2015-12-01 12:19:36 -08:00
|
|
|
if importpkg != nil {
|
|
|
|
|
Fatalf("importpkg not nil")
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:15:25 -08:00
|
|
|
path_, ok := f.U.(string)
|
|
|
|
|
if !ok {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("import statement not a string")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:15:25 -08:00
|
|
|
if len(path_) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("import path is empty")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:15:25 -08:00
|
|
|
if isbadimport(path_) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The package name main is no longer reserved,
|
|
|
|
|
// but we reserve the import path "main" to identify
|
|
|
|
|
// the main package, just as we reserve the import
|
|
|
|
|
// path "math" to identify the standard math package.
|
2015-12-01 12:15:25 -08:00
|
|
|
if path_ == "main" {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("cannot import \"main\"")
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:15:25 -08:00
|
|
|
if myimportpath != "" && path_ == myimportpath {
|
|
|
|
|
Yyerror("import %q while compiling that package (import cycle)", path_)
|
2015-02-13 14:40:36 -05:00
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-08 11:36:36 -05:00
|
|
|
if mapped, ok := importMap[path_]; ok {
|
|
|
|
|
path_ = mapped
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if path_ == "unsafe" {
|
2015-02-13 14:40:36 -05:00
|
|
|
if safemode != 0 {
|
|
|
|
|
Yyerror("cannot import package unsafe")
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 12:02:42 -08:00
|
|
|
importpkg = unsafepkg
|
2015-09-11 00:03:19 +02:00
|
|
|
imported_unsafe = true
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if islocalname(path_) {
|
2015-03-02 16:03:26 -05:00
|
|
|
if path_[0] == '/' {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("import path cannot be absolute path")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
prefix := Ctxt.Pathname
|
2015-02-13 14:40:36 -05:00
|
|
|
if localimport != "" {
|
|
|
|
|
prefix = localimport
|
|
|
|
|
}
|
2016-02-23 02:14:32 -08:00
|
|
|
path_ = path.Join(prefix, path_)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if isbadimport(path_) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
file, found := findpkg(path_)
|
|
|
|
|
if !found {
|
2015-12-01 12:15:25 -08:00
|
|
|
Yyerror("can't find import: %q", path_)
|
2015-02-13 14:40:36 -05:00
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
importpkg = mkpkg(path_)
|
|
|
|
|
|
2015-09-08 05:46:31 +02:00
|
|
|
if importpkg.Imported {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-08 05:46:31 +02:00
|
|
|
importpkg.Imported = true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-12-01 12:19:36 -08:00
|
|
|
imp, err := obj.Bopenr(file)
|
2015-02-13 14:40:36 -05:00
|
|
|
if err != nil {
|
2015-12-01 12:15:25 -08:00
|
|
|
Yyerror("can't open import: %q: %v", path_, err)
|
2015-02-13 14:40:36 -05:00
|
|
|
errorexit()
|
|
|
|
|
}
|
2015-12-01 12:19:36 -08:00
|
|
|
defer obj.Bterm(imp)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
if strings.HasSuffix(file, ".a") {
|
2015-02-17 22:13:49 -05:00
|
|
|
if !skiptopkgdef(imp) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("import %s: not a package file", file)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check object header
|
2015-02-23 16:07:24 -05:00
|
|
|
p := obj.Brdstr(imp, '\n', 1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if p != "empty archive" {
|
|
|
|
|
if !strings.HasPrefix(p, "go object ") {
|
|
|
|
|
Yyerror("import %s: not a go object file", file)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
2015-02-13 14:40:36 -05:00
|
|
|
if p[10:] != q {
|
|
|
|
|
Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assume files move (get installed)
|
|
|
|
|
// so don't record the full path.
|
2015-04-20 13:32:40 -07:00
|
|
|
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
// In the importfile, if we find:
|
|
|
|
|
// $$\n (old format): position the input right after $$\n and return
|
|
|
|
|
// $$B\n (new format): import directly, then feed the lexer a dummy statement
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
// look for $$
|
|
|
|
|
var c int
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
2015-08-13 19:05:37 -07:00
|
|
|
c = obj.Bgetc(imp)
|
|
|
|
|
if c < 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
2015-08-13 19:05:37 -07:00
|
|
|
if c == '$' {
|
|
|
|
|
c = obj.Bgetc(imp)
|
|
|
|
|
if c == '$' || c < 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
// get character after $$
|
|
|
|
|
if c >= 0 {
|
|
|
|
|
c = obj.Bgetc(imp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch c {
|
|
|
|
|
case '\n':
|
|
|
|
|
// old export format
|
2016-02-19 18:51:24 -08:00
|
|
|
parse_import(imp, indent)
|
2015-11-04 09:21:49 -08:00
|
|
|
|
2015-08-13 19:05:37 -07:00
|
|
|
case 'B':
|
|
|
|
|
// new export format
|
|
|
|
|
obj.Bgetc(imp) // skip \n after $$B
|
|
|
|
|
Import(imp)
|
|
|
|
|
|
|
|
|
|
default:
|
2015-12-01 12:15:25 -08:00
|
|
|
Yyerror("no import in %q", path_)
|
2015-12-01 12:19:36 -08:00
|
|
|
errorexit()
|
2015-08-13 19:05:37 -07:00
|
|
|
}
|
2015-11-04 09:21:49 -08:00
|
|
|
|
2015-12-01 12:19:36 -08:00
|
|
|
if safemode != 0 && !importpkg.Safe {
|
|
|
|
|
Yyerror("cannot import unsafe package %q", importpkg.Path)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isSpace(c rune) bool {
|
2015-09-24 15:41:05 +02:00
|
|
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isLetter(c rune) bool {
|
|
|
|
|
return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
|
2015-09-24 15:41:05 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func isDigit(c rune) bool {
|
2015-09-24 15:41:05 +02:00
|
|
|
return '0' <= c && c <= '9'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func plan9quote(s string) string {
|
|
|
|
|
if s == "" {
|
|
|
|
|
return "''"
|
|
|
|
|
}
|
|
|
|
|
for _, c := range s {
|
|
|
|
|
if c <= ' ' || c == '\'' {
|
|
|
|
|
return "'" + strings.Replace(s, "'", "''", -1) + "'"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 17:49:31 -08:00
|
|
|
type Pragma uint16
|
2016-02-26 13:32:28 -08:00
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
Nointerface Pragma = 1 << iota
|
|
|
|
|
Noescape // func parameters don't escape
|
|
|
|
|
Norace // func must not have race detector annotations
|
|
|
|
|
Nosplit // func should not execute on separate stack
|
|
|
|
|
Noinline // func should not be inlined
|
|
|
|
|
Systemstack // func must run on system stack
|
|
|
|
|
Nowritebarrier // emit compiler error instead of write barrier
|
|
|
|
|
Nowritebarrierrec // error on write barrier in this or recursive callees
|
2016-02-27 17:49:31 -08:00
|
|
|
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
|
2016-02-26 13:32:28 -08:00
|
|
|
)
|
|
|
|
|
|
2016-02-20 11:06:35 -08:00
|
|
|
type lexer struct {
|
2016-02-22 11:53:20 -08:00
|
|
|
// source
|
|
|
|
|
bin *obj.Biobuf
|
2016-02-22 23:07:30 -08:00
|
|
|
peekr1 rune
|
|
|
|
|
peekr2 rune // second peekc for ...
|
2016-02-22 11:53:20 -08:00
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
nlsemi bool // if set, '\n' and EOF translate to ';'
|
2016-02-20 11:06:35 -08:00
|
|
|
|
2016-02-26 13:32:28 -08:00
|
|
|
// pragma flags
|
|
|
|
|
// accumulated by lexer; reset by parser
|
|
|
|
|
pragma Pragma
|
|
|
|
|
|
2016-02-20 11:06:35 -08:00
|
|
|
// current token
|
|
|
|
|
tok int32
|
2016-02-25 17:27:10 -08:00
|
|
|
sym_ *Sym // valid if tok == LNAME
|
|
|
|
|
val Val // valid if tok == LLITERAL
|
2016-03-01 14:47:26 -08:00
|
|
|
op Op // valid if tok == LOPER, LASOP, or LINCOP, or prec > 0
|
2016-02-25 17:27:10 -08:00
|
|
|
prec OpPrec // operator precedence; 0 if not a binary operator
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
type OpPrec int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// Precedences of binary operators (must be > 0).
|
|
|
|
|
PCOMM OpPrec = 1 + iota
|
|
|
|
|
POROR
|
|
|
|
|
PANDAND
|
|
|
|
|
PCMP
|
|
|
|
|
PADD
|
|
|
|
|
PMUL
|
|
|
|
|
)
|
|
|
|
|
|
2015-11-23 14:11:15 -08:00
|
|
|
const (
|
2016-02-24 16:17:49 -08:00
|
|
|
// The value of single-char tokens is just their character's Unicode value.
|
|
|
|
|
// They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
|
2016-03-01 14:47:26 -08:00
|
|
|
|
|
|
|
|
// names and literals
|
|
|
|
|
LNAME = utf8.RuneSelf + iota
|
|
|
|
|
LLITERAL
|
|
|
|
|
|
|
|
|
|
// operator-based operations
|
|
|
|
|
LOPER
|
2015-11-23 14:11:15 -08:00
|
|
|
LASOP
|
2016-03-01 14:47:26 -08:00
|
|
|
LINCOP
|
|
|
|
|
|
|
|
|
|
// miscellaneous
|
2015-11-23 14:11:15 -08:00
|
|
|
LCOLAS
|
2016-03-01 14:47:26 -08:00
|
|
|
LCOMM
|
|
|
|
|
LDDD
|
|
|
|
|
|
|
|
|
|
// keywords
|
2015-11-23 14:11:15 -08:00
|
|
|
LBREAK
|
|
|
|
|
LCASE
|
|
|
|
|
LCHAN
|
|
|
|
|
LCONST
|
|
|
|
|
LCONTINUE
|
|
|
|
|
LDEFAULT
|
|
|
|
|
LDEFER
|
|
|
|
|
LELSE
|
|
|
|
|
LFALL
|
|
|
|
|
LFOR
|
|
|
|
|
LFUNC
|
|
|
|
|
LGO
|
|
|
|
|
LGOTO
|
|
|
|
|
LIF
|
|
|
|
|
LIMPORT
|
|
|
|
|
LINTERFACE
|
|
|
|
|
LMAP
|
|
|
|
|
LPACKAGE
|
|
|
|
|
LRANGE
|
|
|
|
|
LRETURN
|
|
|
|
|
LSELECT
|
|
|
|
|
LSTRUCT
|
|
|
|
|
LSWITCH
|
|
|
|
|
LTYPE
|
|
|
|
|
LVAR
|
2016-03-01 14:47:26 -08:00
|
|
|
|
2015-11-23 14:11:15 -08:00
|
|
|
LIGNORE
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
func (l *lexer) next() {
|
|
|
|
|
nlsemi := l.nlsemi
|
|
|
|
|
l.nlsemi = false
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = 0
|
2016-02-20 12:53:34 -08:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
l0:
|
2016-02-20 12:53:34 -08:00
|
|
|
// skip white space
|
2016-02-22 23:07:30 -08:00
|
|
|
c := l.getr()
|
2016-02-20 12:53:34 -08:00
|
|
|
for isSpace(c) {
|
|
|
|
|
if c == '\n' && nlsemi {
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
cmd/compile: rationalize (lex)?lineno handling
Previously, many error messages inconsistantly used either lexlineno
and lineno. In general this works out okay because they're almost
always the same. The only exceptional case is after lexing a
multi-line raw string literal, where lineno will be the line number of
the opening quote and lexlineno is the line number of the closing
quote.
This CL makes the compiler's error message more consistent:
- Lexer error messages related to invalid byte sequences (i.e., NUL
bytes, bad UTF-8 sequences, and non-initial BOMs) are emitted at
lexlineno (i.e., the source line that contains the invalid byte
sequence).
- All other error messages (notably the parser's "syntax errors") now
use lineno. The minor change from this is that bogus input like:
package `
bogus`
will emit "syntax error: unexpected string literal, expecting name"
error at line 1, instead of line 2.
- Instead of maintaining prevlineno all the time, just record it
when/where actually needed and not already available elsewhere (which
turns out to be just one function).
- Lastly, we remove the legacy "syntax error near ..." fallback in
Yerror, now that the parser always emits more detailed syntax error
messages.
Change-Id: Iaf5f784223d0385fa3a5b09ef2b2ad447feab02f
Reviewed-on: https://go-review.googlesource.com/19925
Reviewed-by: Robert Griesemer <gri@golang.org>
2016-02-25 16:07:04 -08:00
|
|
|
// Insert implicit semicolon on previous line,
|
|
|
|
|
// before the newline character.
|
|
|
|
|
lineno = lexlineno - 1
|
2016-02-20 12:53:34 -08:00
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
// start of token
|
|
|
|
|
lineno = lexlineno
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
// identifiers and keywords
|
|
|
|
|
// (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
|
|
|
|
|
if isLetter(c) || c >= utf8.RuneSelf {
|
2016-02-23 22:04:20 -08:00
|
|
|
l.ident(c)
|
|
|
|
|
if l.tok == LIGNORE {
|
2016-02-22 23:07:30 -08:00
|
|
|
goto l0
|
|
|
|
|
}
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-24 16:17:49 -08:00
|
|
|
// c < utf8.RuneSelf
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
var c1 rune
|
|
|
|
|
var op Op
|
2016-02-25 17:27:10 -08:00
|
|
|
var prec OpPrec
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch c {
|
|
|
|
|
case EOF:
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(EOF) // return EOF again in future next call
|
2016-02-20 12:53:34 -08:00
|
|
|
// Treat EOF as "end of line" for the purposes
|
|
|
|
|
// of inserting a semicolon.
|
|
|
|
|
if nlsemi {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
|
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
l.tok = -1
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
|
|
|
l.number(c)
|
|
|
|
|
return
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
case '.':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-09-11 00:03:19 +02:00
|
|
|
if isDigit(c1) {
|
2016-02-23 22:04:20 -08:00
|
|
|
l.ungetr(c1)
|
|
|
|
|
l.number('.')
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '.' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '.' {
|
|
|
|
|
c = LDDD
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c1)
|
2015-02-13 14:40:36 -05:00
|
|
|
c1 = '.'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '"':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.stdString()
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '`':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.rawString()
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\'':
|
2016-02-23 22:04:20 -08:00
|
|
|
l.rune()
|
2016-02-20 12:53:34 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '/':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '*' {
|
2016-02-25 22:10:48 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
2016-02-25 22:10:48 -08:00
|
|
|
if c == '*' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c == '/' {
|
2016-02-25 22:10:48 -08:00
|
|
|
break
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if c == EOF {
|
|
|
|
|
Yyerror("eof in comment")
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-25 22:10:48 -08:00
|
|
|
|
|
|
|
|
// A comment containing newlines acts like a newline.
|
|
|
|
|
if lexlineno > lineno && nlsemi {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: implicit semi\n")
|
|
|
|
|
}
|
|
|
|
|
l.tok = ';'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
goto l0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '/' {
|
2016-02-22 11:53:20 -08:00
|
|
|
c = l.getlinepragma()
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
|
|
|
|
if c == '\n' || c == EOF {
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
goto l0
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = ODIV
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case ':':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = LCOLAS
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '*':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OMUL
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '%':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OMOD
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '+':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OADD
|
|
|
|
|
goto incop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '-':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OSUB
|
|
|
|
|
goto incop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '>':
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '>' {
|
2016-02-25 17:27:10 -08:00
|
|
|
op = ORSH
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-02-25 17:27:10 -08:00
|
|
|
l.op = OGE
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
2016-02-25 17:27:10 -08:00
|
|
|
l.op = OGT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '<':
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '<' {
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OLSH
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '-' {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = LCOMM
|
2016-02-25 17:27:10 -08:00
|
|
|
// Not a binary operator, but parsed as one
|
|
|
|
|
// so we can give a good error message when used
|
|
|
|
|
// in an expression context.
|
|
|
|
|
l.prec = PCOMM
|
|
|
|
|
l.op = OSEND
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
if c1 == '=' {
|
|
|
|
|
l.op = OLE
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
l.op = OLT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '=':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
l.op = OEQ
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '!':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '=' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PCMP
|
|
|
|
|
l.op = ONE
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '&':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '&' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = PANDAND
|
|
|
|
|
l.op = OANDAND
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c1 == '^' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OANDNOT
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OAND
|
|
|
|
|
prec = PMUL
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '|':
|
2016-02-22 23:07:30 -08:00
|
|
|
c1 = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c1 == '|' {
|
2016-03-01 14:47:26 -08:00
|
|
|
c = LOPER
|
2016-02-25 17:27:10 -08:00
|
|
|
l.prec = POROR
|
|
|
|
|
l.op = OOROR
|
2015-02-13 14:40:36 -05:00
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OOR
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop1
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '^':
|
2016-02-25 17:27:10 -08:00
|
|
|
op = OXOR
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
case '(', '[', '{', ',', ';':
|
|
|
|
|
goto lx
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
case ')', ']', '}':
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
goto lx
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
case '#', '$', '?', '@', '\\':
|
|
|
|
|
if importpkg != nil {
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2016-02-22 23:07:30 -08:00
|
|
|
// anything else is illegal
|
|
|
|
|
Yyerror("syntax error: illegal character %#U", c)
|
|
|
|
|
goto l0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
lx:
|
2015-11-27 16:11:05 -08:00
|
|
|
if Debug['x'] != 0 {
|
2016-02-25 17:27:10 -08:00
|
|
|
if c >= utf8.RuneSelf {
|
2016-03-02 11:30:29 -08:00
|
|
|
fmt.Printf("%v lex: TOKEN %s\n", linestr(lineno), lexname(c))
|
2015-11-27 16:11:05 -08:00
|
|
|
} else {
|
2016-03-02 11:30:29 -08:00
|
|
|
fmt.Printf("%v lex: TOKEN '%c'\n", linestr(lineno), c)
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
l.tok = c
|
2016-02-20 12:53:34 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 17:27:10 -08:00
|
|
|
incop:
|
|
|
|
|
c1 = l.getr()
|
|
|
|
|
if c1 == c {
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.op = op
|
|
|
|
|
c = LINCOP
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
prec = PADD
|
|
|
|
|
goto binop1
|
|
|
|
|
|
|
|
|
|
binop:
|
|
|
|
|
c1 = l.getr()
|
|
|
|
|
binop1:
|
|
|
|
|
if c1 != '=' {
|
|
|
|
|
l.ungetr(c1)
|
|
|
|
|
l.op = op
|
|
|
|
|
l.prec = prec
|
|
|
|
|
goto lx
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
l.op = op
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
2015-11-27 16:11:05 -08:00
|
|
|
fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2016-02-20 12:53:34 -08:00
|
|
|
l.tok = LASOP
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) ident(c rune) {
|
|
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
|
|
|
|
// accelerate common case (7bit ASCII)
|
|
|
|
|
for isLetter(c) || isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// general case
|
|
|
|
|
for {
|
|
|
|
|
if c >= utf8.RuneSelf {
|
|
|
|
|
if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
|
|
|
|
|
if cp.Len() == 0 && unicode.IsDigit(c) {
|
|
|
|
|
Yyerror("identifier cannot begin with digit %#U", c)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Yyerror("invalid identifier character %#U", c)
|
|
|
|
|
}
|
|
|
|
|
cp.WriteRune(c)
|
|
|
|
|
} else if isLetter(c) || isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
cp = nil
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-26 01:37:28 -08:00
|
|
|
name := lexbuf.Bytes()
|
|
|
|
|
|
|
|
|
|
if len(name) >= 2 {
|
|
|
|
|
if tok, ok := keywords[string(name)]; ok {
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: %s\n", lexname(tok))
|
|
|
|
|
}
|
|
|
|
|
switch tok {
|
|
|
|
|
case LBREAK, LCONTINUE, LFALL, LRETURN:
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
}
|
|
|
|
|
l.tok = tok
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := LookupBytes(name)
|
2016-02-23 22:04:20 -08:00
|
|
|
if Debug['x'] != 0 {
|
2016-02-26 01:37:28 -08:00
|
|
|
fmt.Printf("lex: ident %s\n", s)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
l.sym_ = s
|
2016-02-26 01:37:28 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LNAME
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var keywords = map[string]int32{
|
|
|
|
|
"break": LBREAK,
|
|
|
|
|
"case": LCASE,
|
|
|
|
|
"chan": LCHAN,
|
|
|
|
|
"const": LCONST,
|
|
|
|
|
"continue": LCONTINUE,
|
|
|
|
|
"default": LDEFAULT,
|
|
|
|
|
"defer": LDEFER,
|
|
|
|
|
"else": LELSE,
|
|
|
|
|
"fallthrough": LFALL,
|
|
|
|
|
"for": LFOR,
|
|
|
|
|
"func": LFUNC,
|
|
|
|
|
"go": LGO,
|
|
|
|
|
"goto": LGOTO,
|
|
|
|
|
"if": LIF,
|
|
|
|
|
"import": LIMPORT,
|
|
|
|
|
"interface": LINTERFACE,
|
|
|
|
|
"map": LMAP,
|
|
|
|
|
"package": LPACKAGE,
|
|
|
|
|
"range": LRANGE,
|
|
|
|
|
"return": LRETURN,
|
|
|
|
|
"select": LSELECT,
|
|
|
|
|
"struct": LSTRUCT,
|
|
|
|
|
"switch": LSWITCH,
|
|
|
|
|
"type": LTYPE,
|
|
|
|
|
"var": LVAR,
|
|
|
|
|
|
|
|
|
|
// 💩
|
|
|
|
|
"notwithstanding": LIGNORE,
|
|
|
|
|
"thetruthofthematter": LIGNORE,
|
|
|
|
|
"despiteallobjections": LIGNORE,
|
|
|
|
|
"whereas": LIGNORE,
|
|
|
|
|
"insofaras": LIGNORE,
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
func (l *lexer) number(c rune) {
|
|
|
|
|
var str string
|
|
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// parse mantissa before decimal point or exponent
|
|
|
|
|
isInt := false
|
|
|
|
|
malformedOctal := false
|
2016-02-23 22:04:20 -08:00
|
|
|
if c != '.' {
|
|
|
|
|
if c != '0' {
|
2016-02-24 12:53:28 -08:00
|
|
|
// decimal or float
|
2016-02-23 22:04:20 -08:00
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// c == 0
|
|
|
|
|
cp.WriteByte('0')
|
|
|
|
|
c = l.getr()
|
|
|
|
|
if c == 'x' || c == 'X' {
|
|
|
|
|
isInt = true // must be int
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
if lexbuf.Len() == 2 {
|
|
|
|
|
Yyerror("malformed hex constant")
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// decimal 0, octal, or float
|
|
|
|
|
for isDigit(c) {
|
|
|
|
|
if c > '7' {
|
|
|
|
|
malformedOctal = true
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// unless we have a hex number, parse fractional part or exponent, if any
|
|
|
|
|
if !isInt {
|
|
|
|
|
isInt = true // assume int unless proven otherwise
|
|
|
|
|
|
|
|
|
|
// fraction
|
|
|
|
|
if c == '.' {
|
|
|
|
|
isInt = false
|
|
|
|
|
cp.WriteByte('.')
|
|
|
|
|
c = l.getr()
|
|
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
|
|
|
|
// Falling through to exponent parsing here permits invalid
|
|
|
|
|
// floating-point numbers with fractional mantissa and base-2
|
|
|
|
|
// (p or P) exponent. We don't care because base-2 exponents
|
|
|
|
|
// can only show up in machine-generated textual export data
|
|
|
|
|
// which will use correct formatting.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// exponent
|
|
|
|
|
// base-2 exponent (p or P) is only allowed in export data (see #9036)
|
|
|
|
|
// TODO(gri) Once we switch to binary import data, importpkg will
|
|
|
|
|
// always be nil in this function. Simplify the code accordingly.
|
|
|
|
|
if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
|
|
|
|
|
isInt = false
|
2016-02-23 22:04:20 -08:00
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
2016-02-24 12:53:28 -08:00
|
|
|
if c == '+' || c == '-' {
|
2016-02-23 22:04:20 -08:00
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
|
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
if !isDigit(c) {
|
|
|
|
|
Yyerror("malformed floating point constant exponent")
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
for isDigit(c) {
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
c = l.getr()
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
// imaginary constant
|
|
|
|
|
if c == 'i' {
|
|
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := new(Mpcplx)
|
|
|
|
|
Mpmovecflt(&x.Real, 0.0)
|
|
|
|
|
mpatoflt(&x.Imag, str)
|
|
|
|
|
if x.Imag.Val.IsInf() {
|
|
|
|
|
Yyerror("overflow in imaginary constant")
|
|
|
|
|
Mpmovecflt(&x.Imag, 0.0)
|
|
|
|
|
}
|
|
|
|
|
l.val.U = x
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: imaginary literal\n")
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2016-02-24 12:53:28 -08:00
|
|
|
goto done
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
2015-02-23 17:34:49 -05:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if isInt {
|
|
|
|
|
if malformedOctal {
|
|
|
|
|
Yyerror("malformed octal constant")
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := new(Mpint)
|
|
|
|
|
mpatofix(x, str)
|
|
|
|
|
if x.Ovf {
|
|
|
|
|
Yyerror("overflow in constant")
|
|
|
|
|
Mpmovecfix(x, 0)
|
|
|
|
|
}
|
|
|
|
|
l.val.U = x
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: integer literal\n")
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
} else { // float
|
2016-02-23 22:04:20 -08:00
|
|
|
|
2016-02-24 12:53:28 -08:00
|
|
|
str = lexbuf.String()
|
|
|
|
|
x := newMpflt()
|
|
|
|
|
mpatoflt(x, str)
|
|
|
|
|
if x.Val.IsInf() {
|
|
|
|
|
Yyerror("overflow in float constant")
|
|
|
|
|
Mpmovecflt(x, 0.0)
|
|
|
|
|
}
|
|
|
|
|
l.val.U = x
|
|
|
|
|
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: floating literal\n")
|
|
|
|
|
}
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
2015-02-24 20:54:57 +00:00
|
|
|
litbuf = "literal " + str
|
2016-02-20 12:53:34 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) stdString() {
|
|
|
|
|
lexbuf.Reset()
|
|
|
|
|
lexbuf.WriteString(`"<string>"`)
|
|
|
|
|
|
|
|
|
|
cp := &strbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
for {
|
|
|
|
|
r, b, ok := l.onechar('"')
|
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if r == 0 {
|
|
|
|
|
cp.WriteByte(b)
|
2016-02-23 22:04:20 -08:00
|
|
|
} else {
|
2016-02-24 11:49:31 -08:00
|
|
|
cp.WriteRune(r)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l.val.U = internString(cp.Bytes())
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: string literal\n")
|
|
|
|
|
}
|
|
|
|
|
litbuf = "string literal"
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) rawString() {
|
|
|
|
|
lexbuf.Reset()
|
|
|
|
|
lexbuf.WriteString("`<string>`")
|
|
|
|
|
|
|
|
|
|
cp := &strbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
c := l.getr()
|
|
|
|
|
if c == '\r' {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if c == EOF {
|
|
|
|
|
Yyerror("eof in string")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if c == '`' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
cp.WriteRune(c)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-20 12:53:34 -08:00
|
|
|
l.val.U = internString(cp.Bytes())
|
2015-02-23 17:34:49 -05:00
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: string literal\n")
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
litbuf = "string literal"
|
2016-02-20 12:53:34 -08:00
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 22:04:20 -08:00
|
|
|
func (l *lexer) rune() {
|
2016-02-24 11:49:31 -08:00
|
|
|
r, b, ok := l.onechar('\'')
|
|
|
|
|
if !ok {
|
2016-02-23 22:04:20 -08:00
|
|
|
Yyerror("empty character literal or unescaped ' in character literal")
|
2016-02-24 11:49:31 -08:00
|
|
|
r = '\''
|
|
|
|
|
}
|
|
|
|
|
if r == 0 {
|
|
|
|
|
r = rune(b)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
if c := l.getr(); c != '\'' {
|
2016-02-23 22:04:20 -08:00
|
|
|
Yyerror("missing '")
|
2016-02-24 11:49:31 -08:00
|
|
|
l.ungetr(c)
|
2016-02-23 22:04:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x := new(Mpint)
|
|
|
|
|
l.val.U = x
|
2016-02-24 11:49:31 -08:00
|
|
|
Mpmovecfix(x, int64(r))
|
2016-02-23 22:04:20 -08:00
|
|
|
x.Rune = true
|
|
|
|
|
if Debug['x'] != 0 {
|
|
|
|
|
fmt.Printf("lex: codepoint literal\n")
|
|
|
|
|
}
|
|
|
|
|
litbuf = "rune literal"
|
|
|
|
|
l.nlsemi = true
|
|
|
|
|
l.tok = LLITERAL
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
var internedStrings = map[string]string{}
|
|
|
|
|
|
|
|
|
|
func internString(b []byte) string {
|
|
|
|
|
s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
|
2016-02-22 11:53:20 -08:00
|
|
|
if !ok {
|
|
|
|
|
s = string(b)
|
|
|
|
|
internedStrings[s] = s
|
2015-03-02 16:03:26 -05:00
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func more(pp *string) bool {
|
|
|
|
|
p := *pp
|
2016-02-22 23:07:30 -08:00
|
|
|
for p != "" && isSpace(rune(p[0])) {
|
2015-02-13 14:40:36 -05:00
|
|
|
p = p[1:]
|
|
|
|
|
}
|
|
|
|
|
*pp = p
|
|
|
|
|
return p != ""
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// read and interpret syntax that looks like
|
|
|
|
|
// //line parse.y:15
|
|
|
|
|
// as a discontinuity in sequential line numbers.
|
|
|
|
|
// the next line of input comes from parse.y:15
|
2016-02-22 23:07:30 -08:00
|
|
|
func (l *lexer) getlinepragma() rune {
|
|
|
|
|
c := l.getr()
|
2015-06-08 10:17:38 -07:00
|
|
|
if c == 'g' { // check for //go: directive
|
2015-03-02 12:35:15 -05:00
|
|
|
cp := &lexbuf
|
|
|
|
|
cp.Reset()
|
|
|
|
|
cp.WriteByte('g') // already read
|
|
|
|
|
for {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-03-02 12:35:15 -05:00
|
|
|
if c == EOF || c >= utf8.RuneSelf {
|
|
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
if c == '\n' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
}
|
|
|
|
|
cp = nil
|
|
|
|
|
|
2015-07-17 22:29:44 -07:00
|
|
|
text := strings.TrimSuffix(lexbuf.String(), "\r")
|
2015-03-08 22:41:48 -04:00
|
|
|
|
|
|
|
|
if strings.HasPrefix(text, "go:cgo_") {
|
|
|
|
|
pragcgo(text)
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
verb := text
|
|
|
|
|
if i := strings.Index(text, " "); i >= 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
verb = verb[:i]
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
switch verb {
|
|
|
|
|
case "go:linkname":
|
2015-09-11 00:03:19 +02:00
|
|
|
if !imported_unsafe {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
|
|
|
|
|
}
|
2015-06-08 10:17:38 -07:00
|
|
|
f := strings.Fields(text)
|
2015-03-02 12:35:15 -05:00
|
|
|
if len(f) != 3 {
|
|
|
|
|
Yyerror("usage: //go:linkname localname linkname")
|
2015-06-08 10:17:38 -07:00
|
|
|
break
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
Lookup(f[1]).Linkname = f[2]
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nointerface":
|
|
|
|
|
if obj.Fieldtrack_enabled != 0 {
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nointerface
|
2015-06-08 10:17:38 -07:00
|
|
|
}
|
|
|
|
|
case "go:noescape":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Noescape
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:norace":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Norace
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nosplit":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nosplit
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:noinline":
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Noinline
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:systemstack":
|
2015-09-03 17:39:20 -04:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:systemstack only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Systemstack
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nowritebarrier":
|
2015-03-02 12:35:15 -05:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:nowritebarrier only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nowritebarrier
|
2015-06-08 10:17:38 -07:00
|
|
|
case "go:nowritebarrierrec":
|
2015-11-02 16:45:07 -05:00
|
|
|
if compiling_runtime == 0 {
|
|
|
|
|
Yyerror("//go:nowritebarrierrec only allowed in runtime")
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
|
2016-02-27 17:49:31 -08:00
|
|
|
case "go:cgo_unsafe_args":
|
|
|
|
|
l.pragma |= CgoUnsafeArgs
|
2015-11-02 16:45:07 -05:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-06-08 10:17:38 -07:00
|
|
|
|
|
|
|
|
// check for //line directive
|
2015-02-13 14:40:36 -05:00
|
|
|
if c != 'l' {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 1; i < 5; i++ {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
|
|
|
|
if c != rune("line "[i]) {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
cp := &lexbuf
|
2015-02-13 14:40:36 -05:00
|
|
|
cp.Reset()
|
2015-03-02 12:35:15 -05:00
|
|
|
linep := 0
|
2015-02-13 14:40:36 -05:00
|
|
|
for {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
if c == EOF {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if c == '\n' {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if c == ' ' {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if c == ':' {
|
|
|
|
|
linep = cp.Len() + 1
|
|
|
|
|
}
|
|
|
|
|
cp.WriteByte(byte(c))
|
|
|
|
|
}
|
|
|
|
|
cp = nil
|
|
|
|
|
|
|
|
|
|
if linep == 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-07-17 22:29:44 -07:00
|
|
|
text := strings.TrimSuffix(lexbuf.String(), "\r")
|
2015-06-08 10:17:38 -07:00
|
|
|
n, err := strconv.Atoi(text[linep:])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return c // todo: make this an error instead? it is almost certainly a bug.
|
|
|
|
|
}
|
|
|
|
|
if n > 1e8 {
|
|
|
|
|
Yyerror("line number out of range")
|
|
|
|
|
errorexit()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n <= 0 {
|
2015-03-02 12:35:15 -05:00
|
|
|
return c
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 10:17:38 -07:00
|
|
|
linehistupdate(text[:linep-1], n)
|
2015-02-13 14:40:36 -05:00
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getimpsym(pp *string) string {
|
|
|
|
|
more(pp) // skip spaces
|
|
|
|
|
p := *pp
|
|
|
|
|
if p == "" || p[0] == '"' {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
i := 0
|
2016-02-22 23:07:30 -08:00
|
|
|
for i < len(p) && !isSpace(rune(p[i])) && p[i] != '"' {
|
2015-02-13 14:40:36 -05:00
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
sym := p[:i]
|
|
|
|
|
*pp = p[i:]
|
|
|
|
|
return sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getquoted(pp *string) (string, bool) {
|
|
|
|
|
more(pp) // skip spaces
|
|
|
|
|
p := *pp
|
|
|
|
|
if p == "" || p[0] != '"' {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
p = p[1:]
|
|
|
|
|
i := strings.Index(p, `"`)
|
|
|
|
|
if i < 0 {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
*pp = p[i+1:]
|
|
|
|
|
return p[:i], true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copied nearly verbatim from the C compiler's #pragma parser.
|
|
|
|
|
// TODO: Rewrite more cleanly once the compiler is written in Go.
|
|
|
|
|
func pragcgo(text string) {
|
|
|
|
|
var q string
|
|
|
|
|
|
|
|
|
|
if i := strings.Index(text, " "); i >= 0 {
|
|
|
|
|
text, q = text[:i], text[i:]
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
verb := text[3:] // skip "go:"
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
|
2015-09-11 00:03:19 +02:00
|
|
|
p, ok := getquoted(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if !ok {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "dynexport" {
|
|
|
|
|
verb = "cgo_export_dynamic"
|
|
|
|
|
}
|
|
|
|
|
if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
|
|
|
|
var remote string
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" {
|
|
|
|
|
goto err2
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remote = getimpsym(&q)
|
|
|
|
|
if remote == "" {
|
|
|
|
|
goto err2
|
|
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
err2:
|
|
|
|
|
Yyerror("usage: //go:%s local [remote]", verb)
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_import_dynamic" || verb == "dynimport" {
|
|
|
|
|
var ok bool
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
|
|
|
|
var p string
|
|
|
|
|
var remote string
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remote = getimpsym(&q)
|
|
|
|
|
if remote == "" {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
if !more(&q) {
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p, ok = getquoted(&q)
|
|
|
|
|
if !ok {
|
|
|
|
|
goto err3
|
|
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
err3:
|
|
|
|
|
Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_import_static" {
|
2015-02-23 16:07:24 -05:00
|
|
|
local := getimpsym(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if local == "" || more(&q) {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_import_static local")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if verb == "cgo_ldflag" {
|
2015-09-11 00:03:19 +02:00
|
|
|
p, ok := getquoted(&q)
|
2015-02-13 14:40:36 -05:00
|
|
|
if !ok {
|
2015-03-02 12:35:15 -05:00
|
|
|
Yyerror("usage: //go:cgo_ldflag \"arg\"")
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func (l *lexer) getr() rune {
|
|
|
|
|
// unread rune != 0 available
|
|
|
|
|
if r := l.peekr1; r != 0 {
|
|
|
|
|
l.peekr1 = l.peekr2
|
|
|
|
|
l.peekr2 = 0
|
|
|
|
|
if r == '\n' && importpkg == nil {
|
|
|
|
|
lexlineno++
|
|
|
|
|
}
|
|
|
|
|
return r
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
redo:
|
|
|
|
|
// common case: 7bit ASCII
|
|
|
|
|
c := obj.Bgetc(l.bin)
|
|
|
|
|
if c < utf8.RuneSelf {
|
|
|
|
|
if c == 0 {
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lexlineno, "illegal NUL byte")
|
2016-02-22 23:07:30 -08:00
|
|
|
return 0
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
if c == '\n' && importpkg == nil {
|
|
|
|
|
lexlineno++
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
return rune(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
// c >= utf8.RuneSelf
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
// uncommon case: non-ASCII
|
|
|
|
|
var buf [utf8.UTFMax]byte
|
|
|
|
|
buf[0] = byte(c)
|
|
|
|
|
buf[1] = byte(obj.Bgetc(l.bin))
|
|
|
|
|
i := 2
|
|
|
|
|
for ; i < len(buf) && !utf8.FullRune(buf[:i]); i++ {
|
|
|
|
|
buf[i] = byte(obj.Bgetc(l.bin))
|
2016-02-22 11:53:20 -08:00
|
|
|
}
|
2016-02-22 23:07:30 -08:00
|
|
|
|
|
|
|
|
r, w := utf8.DecodeRune(buf[:i])
|
|
|
|
|
if r == utf8.RuneError && w == 1 {
|
|
|
|
|
// The string conversion here makes a copy for passing
|
|
|
|
|
// to fmt.Printf, so that buf itself does not escape and
|
|
|
|
|
// can be allocated on the stack.
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lexlineno, "illegal UTF-8 sequence % x", string(buf[:i]))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
if r == BOM {
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file")
|
2016-02-22 23:07:30 -08:00
|
|
|
goto redo
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
return r
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func (l *lexer) ungetr(r rune) {
|
|
|
|
|
l.peekr2 = l.peekr1
|
|
|
|
|
l.peekr1 = r
|
|
|
|
|
if r == '\n' && importpkg == nil {
|
|
|
|
|
lexlineno--
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
// onechar lexes a single character within a rune or interpreted string literal,
|
|
|
|
|
// handling escape sequences as necessary.
|
|
|
|
|
func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
|
2016-02-22 23:07:30 -08:00
|
|
|
c := l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
switch c {
|
|
|
|
|
case EOF:
|
|
|
|
|
Yyerror("eof in string")
|
2016-02-24 11:49:31 -08:00
|
|
|
l.ungetr(EOF)
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
|
Yyerror("newline in string")
|
2016-02-24 11:49:31 -08:00
|
|
|
l.ungetr('\n')
|
|
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case '\\':
|
|
|
|
|
break
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
case quote:
|
|
|
|
|
return
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2016-02-24 11:49:31 -08:00
|
|
|
return c, 0, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-02-13 14:40:36 -05:00
|
|
|
switch c {
|
|
|
|
|
case 'x':
|
2016-02-24 11:49:31 -08:00
|
|
|
return 0, byte(l.hexchar(2)), true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'u':
|
2016-02-24 11:49:31 -08:00
|
|
|
return l.unichar(4), 0, true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'U':
|
2016-02-24 11:49:31 -08:00
|
|
|
return l.unichar(8), 0, true
|
|
|
|
|
|
|
|
|
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
|
|
|
|
x := c - '0'
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 2; i > 0; i-- {
|
2016-02-22 23:07:30 -08:00
|
|
|
c = l.getr()
|
2015-03-02 12:35:15 -05:00
|
|
|
if c >= '0' && c <= '7' {
|
2016-02-24 11:49:31 -08:00
|
|
|
x = x*8 + c - '0'
|
2015-03-02 12:35:15 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Yyerror("non-octal character in escape sequence: %c", c)
|
2016-02-22 23:07:30 -08:00
|
|
|
l.ungetr(c)
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 11:53:20 -08:00
|
|
|
if x > 255 {
|
|
|
|
|
Yyerror("octal escape value > 255: %d", x)
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return 0, byte(x), true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
|
c = '\a'
|
|
|
|
|
case 'b':
|
|
|
|
|
c = '\b'
|
|
|
|
|
case 'f':
|
|
|
|
|
c = '\f'
|
|
|
|
|
case 'n':
|
|
|
|
|
c = '\n'
|
|
|
|
|
case 'r':
|
|
|
|
|
c = '\r'
|
|
|
|
|
case 't':
|
|
|
|
|
c = '\t'
|
|
|
|
|
case 'v':
|
|
|
|
|
c = '\v'
|
|
|
|
|
case '\\':
|
|
|
|
|
c = '\\'
|
|
|
|
|
|
|
|
|
|
default:
|
2016-02-24 11:49:31 -08:00
|
|
|
if c != quote {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("unknown escape sequence: %c", c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return c, 0, true
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
func (l *lexer) unichar(n int) rune {
|
|
|
|
|
x := l.hexchar(n)
|
|
|
|
|
if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
|
2016-02-22 11:53:20 -08:00
|
|
|
Yyerror("invalid Unicode code point in escape sequence: %#x", x)
|
|
|
|
|
x = utf8.RuneError
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-24 11:49:31 -08:00
|
|
|
return rune(x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *lexer) hexchar(n int) uint32 {
|
|
|
|
|
var x uint32
|
|
|
|
|
|
|
|
|
|
for ; n > 0; n-- {
|
|
|
|
|
var d uint32
|
|
|
|
|
switch c := l.getr(); {
|
|
|
|
|
case isDigit(c):
|
|
|
|
|
d = uint32(c - '0')
|
|
|
|
|
case 'a' <= c && c <= 'f':
|
|
|
|
|
d = uint32(c - 'a' + 10)
|
|
|
|
|
case 'A' <= c && c <= 'F':
|
|
|
|
|
d = uint32(c - 'A' + 10)
|
|
|
|
|
default:
|
|
|
|
|
Yyerror("non-hex character in escape sequence: %c", c)
|
|
|
|
|
l.ungetr(c)
|
|
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
x = x*16 + d
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-24 11:49:31 -08:00
|
|
|
return x
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-26 02:10:29 -08:00
|
|
|
var basicTypes = [...]struct {
|
2016-02-26 01:37:28 -08:00
|
|
|
name string
|
|
|
|
|
etype EType
|
2015-02-13 14:40:36 -05:00
|
|
|
}{
|
2016-02-26 02:10:29 -08:00
|
|
|
{"int8", TINT8},
|
|
|
|
|
{"int16", TINT16},
|
|
|
|
|
{"int32", TINT32},
|
|
|
|
|
{"int64", TINT64},
|
|
|
|
|
{"uint8", TUINT8},
|
|
|
|
|
{"uint16", TUINT16},
|
|
|
|
|
{"uint32", TUINT32},
|
|
|
|
|
{"uint64", TUINT64},
|
|
|
|
|
{"float32", TFLOAT32},
|
|
|
|
|
{"float64", TFLOAT64},
|
|
|
|
|
{"complex64", TCOMPLEX64},
|
|
|
|
|
{"complex128", TCOMPLEX128},
|
|
|
|
|
{"bool", TBOOL},
|
|
|
|
|
{"string", TSTRING},
|
|
|
|
|
{"any", TANY},
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-02 18:03:50 -08:00
|
|
|
var typedefs = [...]struct {
|
|
|
|
|
name string
|
|
|
|
|
etype EType
|
|
|
|
|
width *int
|
|
|
|
|
sameas32 EType
|
|
|
|
|
sameas64 EType
|
|
|
|
|
}{
|
|
|
|
|
{"int", TINT, &Widthint, TINT32, TINT64},
|
|
|
|
|
{"uint", TUINT, &Widthint, TUINT32, TUINT64},
|
|
|
|
|
{"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-26 02:10:29 -08:00
|
|
|
var builtinFuncs = [...]struct {
|
|
|
|
|
name string
|
|
|
|
|
op Op
|
|
|
|
|
}{
|
|
|
|
|
{"append", OAPPEND},
|
|
|
|
|
{"cap", OCAP},
|
|
|
|
|
{"close", OCLOSE},
|
|
|
|
|
{"complex", OCOMPLEX},
|
|
|
|
|
{"copy", OCOPY},
|
|
|
|
|
{"delete", ODELETE},
|
|
|
|
|
{"imag", OIMAG},
|
|
|
|
|
{"len", OLEN},
|
|
|
|
|
{"make", OMAKE},
|
|
|
|
|
{"new", ONEW},
|
|
|
|
|
{"panic", OPANIC},
|
|
|
|
|
{"print", OPRINT},
|
|
|
|
|
{"println", OPRINTN},
|
|
|
|
|
{"real", OREAL},
|
|
|
|
|
{"recover", ORECOVER},
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-08 22:22:44 +02:00
|
|
|
// lexinit initializes known symbols and the basic types.
|
2015-02-13 14:40:36 -05:00
|
|
|
func lexinit() {
|
2016-02-26 02:10:29 -08:00
|
|
|
for _, s := range basicTypes {
|
|
|
|
|
etype := s.etype
|
|
|
|
|
if int(etype) >= len(Types) {
|
|
|
|
|
Fatalf("lexinit: %s bad etype", s.name)
|
|
|
|
|
}
|
|
|
|
|
s2 := Pkglookup(s.name, builtinpkg)
|
|
|
|
|
t := Types[etype]
|
|
|
|
|
if t == nil {
|
|
|
|
|
t = typ(etype)
|
|
|
|
|
t.Sym = s2
|
|
|
|
|
if etype != TANY && etype != TSTRING {
|
|
|
|
|
dowidth(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-26 02:10:29 -08:00
|
|
|
Types[etype] = t
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-26 02:10:29 -08:00
|
|
|
s2.Def = typenod(t)
|
|
|
|
|
s2.Def.Name = new(Name)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-26 02:10:29 -08:00
|
|
|
for _, s := range builtinFuncs {
|
2015-09-24 23:21:18 +02:00
|
|
|
// TODO(marvin): Fix Node.EType type union.
|
2016-02-26 02:10:29 -08:00
|
|
|
s2 := Pkglookup(s.name, builtinpkg)
|
|
|
|
|
s2.Def = Nod(ONAME, nil, nil)
|
|
|
|
|
s2.Def.Sym = s2
|
|
|
|
|
s2.Def.Etype = EType(s.op)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idealstring = typ(TSTRING)
|
|
|
|
|
idealbool = typ(TBOOL)
|
|
|
|
|
|
2015-09-08 22:22:44 +02:00
|
|
|
s := Pkglookup("true", builtinpkg)
|
2015-02-17 22:13:49 -05:00
|
|
|
s.Def = Nodbool(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
s.Def.Sym = Lookup("true")
|
2015-05-26 23:08:39 -04:00
|
|
|
s.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
s.Def.Type = idealbool
|
|
|
|
|
|
|
|
|
|
s = Pkglookup("false", builtinpkg)
|
2015-02-17 22:13:49 -05:00
|
|
|
s.Def = Nodbool(false)
|
2015-02-13 14:40:36 -05:00
|
|
|
s.Def.Sym = Lookup("false")
|
2015-05-26 23:08:39 -04:00
|
|
|
s.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
s.Def.Type = idealbool
|
|
|
|
|
|
|
|
|
|
s = Lookup("_")
|
|
|
|
|
s.Block = -100
|
|
|
|
|
s.Def = Nod(ONAME, nil, nil)
|
|
|
|
|
s.Def.Sym = s
|
|
|
|
|
Types[TBLANK] = typ(TBLANK)
|
|
|
|
|
s.Def.Type = Types[TBLANK]
|
|
|
|
|
nblank = s.Def
|
|
|
|
|
|
|
|
|
|
s = Pkglookup("_", builtinpkg)
|
|
|
|
|
s.Block = -100
|
|
|
|
|
s.Def = Nod(ONAME, nil, nil)
|
|
|
|
|
s.Def.Sym = s
|
|
|
|
|
Types[TBLANK] = typ(TBLANK)
|
|
|
|
|
s.Def.Type = Types[TBLANK]
|
|
|
|
|
|
|
|
|
|
Types[TNIL] = typ(TNIL)
|
|
|
|
|
s = Pkglookup("nil", builtinpkg)
|
2015-02-23 16:07:24 -05:00
|
|
|
var v Val
|
2015-05-26 22:50:45 -04:00
|
|
|
v.U = new(NilVal)
|
2015-02-13 14:40:36 -05:00
|
|
|
s.Def = nodlit(v)
|
|
|
|
|
s.Def.Sym = s
|
2015-05-26 23:08:39 -04:00
|
|
|
s.Def.Name = new(Name)
|
2016-02-26 02:10:29 -08:00
|
|
|
|
|
|
|
|
s = Pkglookup("iota", builtinpkg)
|
|
|
|
|
s.Def = Nod(OIOTA, nil, nil)
|
|
|
|
|
s.Def.Sym = s
|
|
|
|
|
s.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func lexinit1() {
|
|
|
|
|
// t = interface { Error() string }
|
2015-02-23 16:07:24 -05:00
|
|
|
rcvr := typ(TSTRUCT)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
rcvr.Type = typ(TFIELD)
|
|
|
|
|
rcvr.Type.Type = Ptrto(typ(TSTRUCT))
|
2015-09-08 03:51:30 +02:00
|
|
|
rcvr.Funarg = true
|
2015-02-23 16:07:24 -05:00
|
|
|
in := typ(TSTRUCT)
|
2015-09-08 03:51:30 +02:00
|
|
|
in.Funarg = true
|
2015-02-23 16:07:24 -05:00
|
|
|
out := typ(TSTRUCT)
|
2015-02-13 14:40:36 -05:00
|
|
|
out.Type = typ(TFIELD)
|
|
|
|
|
out.Type.Type = Types[TSTRING]
|
2015-09-08 03:51:30 +02:00
|
|
|
out.Funarg = true
|
2015-02-23 16:07:24 -05:00
|
|
|
f := typ(TFUNC)
|
2016-03-09 20:54:59 -08:00
|
|
|
*f.RecvsP() = rcvr
|
2016-03-08 16:31:28 -08:00
|
|
|
*f.ResultsP() = out
|
|
|
|
|
*f.ParamsP() = in
|
2015-02-13 14:40:36 -05:00
|
|
|
f.Thistuple = 1
|
|
|
|
|
f.Intuple = 0
|
2015-09-08 03:51:30 +02:00
|
|
|
f.Outnamed = false
|
2015-02-13 14:40:36 -05:00
|
|
|
f.Outtuple = 1
|
2015-02-23 16:07:24 -05:00
|
|
|
t := typ(TINTER)
|
2015-02-13 14:40:36 -05:00
|
|
|
t.Type = typ(TFIELD)
|
|
|
|
|
t.Type.Sym = Lookup("Error")
|
|
|
|
|
t.Type.Type = f
|
|
|
|
|
|
|
|
|
|
// error type
|
2016-02-26 01:37:28 -08:00
|
|
|
s := Pkglookup("error", builtinpkg)
|
2015-02-13 14:40:36 -05:00
|
|
|
errortype = t
|
2016-02-26 01:37:28 -08:00
|
|
|
errortype.Sym = s
|
|
|
|
|
s.Def = typenod(errortype)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// byte alias
|
2016-02-26 01:37:28 -08:00
|
|
|
s = Pkglookup("byte", builtinpkg)
|
2015-02-13 14:40:36 -05:00
|
|
|
bytetype = typ(TUINT8)
|
2016-02-26 01:37:28 -08:00
|
|
|
bytetype.Sym = s
|
|
|
|
|
s.Def = typenod(bytetype)
|
|
|
|
|
s.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// rune alias
|
2016-02-26 01:37:28 -08:00
|
|
|
s = Pkglookup("rune", builtinpkg)
|
2015-02-13 14:40:36 -05:00
|
|
|
runetype = typ(TINT32)
|
2016-02-26 01:37:28 -08:00
|
|
|
runetype.Sym = s
|
|
|
|
|
s.Def = typenod(runetype)
|
|
|
|
|
s.Def.Name = new(Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-02 18:03:50 -08:00
|
|
|
// backend-dependent builtin types (e.g. int).
|
|
|
|
|
for _, s := range typedefs {
|
|
|
|
|
s1 := Pkglookup(s.name, builtinpkg)
|
|
|
|
|
|
|
|
|
|
sameas := s.sameas32
|
|
|
|
|
if *s.width == 8 {
|
|
|
|
|
sameas = s.sameas64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Simtype[s.etype] = sameas
|
|
|
|
|
minfltval[s.etype] = minfltval[sameas]
|
|
|
|
|
maxfltval[s.etype] = maxfltval[sameas]
|
|
|
|
|
Minintval[s.etype] = Minintval[sameas]
|
|
|
|
|
Maxintval[s.etype] = Maxintval[sameas]
|
|
|
|
|
|
|
|
|
|
t := typ(s.etype)
|
|
|
|
|
t.Sym = s1
|
|
|
|
|
Types[s.etype] = t
|
|
|
|
|
s1.Def = typenod(t)
|
|
|
|
|
s1.Def.Name = new(Name)
|
|
|
|
|
s1.Origpkg = builtinpkg
|
|
|
|
|
|
|
|
|
|
dowidth(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-26 02:10:29 -08:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-26 02:10:29 -08:00
|
|
|
func lexfini() {
|
|
|
|
|
for _, s := range builtinpkg.Syms {
|
2016-03-04 16:39:07 -08:00
|
|
|
if s.Def == nil || (s.Name == "any" && Debug['A'] == 0) {
|
2016-02-26 02:10:29 -08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
s1 := Lookup(s.Name)
|
|
|
|
|
if s1.Def != nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-26 02:10:29 -08:00
|
|
|
s1.Def = s.Def
|
|
|
|
|
s1.Block = s.Block
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodfp = Nod(ONAME, nil, nil)
|
|
|
|
|
nodfp.Type = Types[TINT32]
|
|
|
|
|
nodfp.Xoffset = 0
|
|
|
|
|
nodfp.Class = PPARAM
|
|
|
|
|
nodfp.Sym = Lookup(".fp")
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
var lexn = map[rune]string{
|
2016-03-01 14:47:26 -08:00
|
|
|
LNAME: "NAME",
|
|
|
|
|
LLITERAL: "LITERAL",
|
|
|
|
|
|
|
|
|
|
LOPER: "OPER",
|
|
|
|
|
LASOP: "ASOP",
|
|
|
|
|
LINCOP: "INCOP",
|
|
|
|
|
|
|
|
|
|
LCOLAS: "COLAS",
|
|
|
|
|
LCOMM: "COMM",
|
|
|
|
|
LDDD: "DDD",
|
|
|
|
|
|
2015-09-08 22:22:44 +02:00
|
|
|
LBREAK: "BREAK",
|
|
|
|
|
LCASE: "CASE",
|
|
|
|
|
LCHAN: "CHAN",
|
|
|
|
|
LCONST: "CONST",
|
|
|
|
|
LCONTINUE: "CONTINUE",
|
|
|
|
|
LDEFAULT: "DEFAULT",
|
|
|
|
|
LDEFER: "DEFER",
|
|
|
|
|
LELSE: "ELSE",
|
|
|
|
|
LFALL: "FALL",
|
|
|
|
|
LFOR: "FOR",
|
|
|
|
|
LFUNC: "FUNC",
|
|
|
|
|
LGO: "GO",
|
|
|
|
|
LGOTO: "GOTO",
|
|
|
|
|
LIF: "IF",
|
|
|
|
|
LIMPORT: "IMPORT",
|
|
|
|
|
LINTERFACE: "INTERFACE",
|
|
|
|
|
LMAP: "MAP",
|
|
|
|
|
LPACKAGE: "PACKAGE",
|
|
|
|
|
LRANGE: "RANGE",
|
|
|
|
|
LRETURN: "RETURN",
|
|
|
|
|
LSELECT: "SELECT",
|
|
|
|
|
LSTRUCT: "STRUCT",
|
|
|
|
|
LSWITCH: "SWITCH",
|
|
|
|
|
LTYPE: "TYPE",
|
|
|
|
|
LVAR: "VAR",
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:07:30 -08:00
|
|
|
func lexname(lex rune) string {
|
2015-09-08 22:22:44 +02:00
|
|
|
if s, ok := lexn[lex]; ok {
|
|
|
|
|
return s
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-04-20 13:50:46 -07:00
|
|
|
return fmt.Sprintf("LEX-%d", lex)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-02 11:01:25 -08:00
|
|
|
func pkgnotused(lineno int32, path string, name string) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// If the package was imported with a name other than the final
|
|
|
|
|
// import path element, show it explicitly in the error message.
|
|
|
|
|
// Note that this handles both renamed imports and imports of
|
|
|
|
|
// packages containing unconventional package declarations.
|
|
|
|
|
// Note that this uses / always, even on Windows, because Go import
|
|
|
|
|
// paths always use forward slashes.
|
2015-03-02 16:03:26 -05:00
|
|
|
elem := path
|
2015-02-13 14:40:36 -05:00
|
|
|
if i := strings.LastIndex(elem, "/"); i >= 0 {
|
|
|
|
|
elem = elem[i+1:]
|
|
|
|
|
}
|
|
|
|
|
if name == "" || elem == name {
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lineno, "imported and not used: %q", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-03-02 11:01:25 -08:00
|
|
|
yyerrorl(lineno, "imported and not used: %q as %s", path, name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mkpackage(pkgname string) {
|
|
|
|
|
if localpkg.Name == "" {
|
|
|
|
|
if pkgname == "_" {
|
|
|
|
|
Yyerror("invalid package name _")
|
|
|
|
|
}
|
|
|
|
|
localpkg.Name = pkgname
|
|
|
|
|
} else {
|
|
|
|
|
if pkgname != localpkg.Name {
|
|
|
|
|
Yyerror("package %s; expected %s", pkgname, localpkg.Name)
|
|
|
|
|
}
|
2015-03-02 16:21:15 -05:00
|
|
|
for _, s := range localpkg.Syms {
|
|
|
|
|
if s.Def == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if s.Def.Op == OPACK {
|
|
|
|
|
// throw away top-level package name leftover
|
|
|
|
|
// from previous file.
|
|
|
|
|
// leave s->block set to cause redeclaration
|
|
|
|
|
// errors if a conflicting top-level name is
|
|
|
|
|
// introduced by a different file.
|
2015-03-06 21:18:41 +11:00
|
|
|
if !s.Def.Used && nsyntaxerrors == 0 {
|
2016-03-02 11:01:25 -08:00
|
|
|
pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-02 16:21:15 -05:00
|
|
|
s.Def = nil
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-02 16:21:15 -05:00
|
|
|
if s.Def.Sym != s {
|
|
|
|
|
// throw away top-level name left over
|
|
|
|
|
// from previous import . "x"
|
2015-05-26 23:08:39 -04:00
|
|
|
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
|
2016-03-02 11:01:25 -08:00
|
|
|
pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "")
|
2015-05-26 23:08:39 -04:00
|
|
|
s.Def.Name.Pack.Used = true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-02 16:21:15 -05:00
|
|
|
|
|
|
|
|
s.Def = nil
|
|
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if outfile == "" {
|
2015-02-23 16:07:24 -05:00
|
|
|
p := infile
|
2015-02-13 14:40:36 -05:00
|
|
|
if i := strings.LastIndex(p, "/"); i >= 0 {
|
|
|
|
|
p = p[i+1:]
|
|
|
|
|
}
|
|
|
|
|
if Ctxt.Windows != 0 {
|
|
|
|
|
if i := strings.LastIndex(p, `\`); i >= 0 {
|
|
|
|
|
p = p[i+1:]
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-06 12:02:24 -08:00
|
|
|
if i := strings.LastIndex(p, "."); i >= 0 {
|
|
|
|
|
p = p[:i]
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-05-21 14:11:33 -04:00
|
|
|
suffix := ".o"
|
|
|
|
|
if writearchive > 0 {
|
|
|
|
|
suffix = ".a"
|
|
|
|
|
}
|
|
|
|
|
outfile = p + suffix
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|