diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 6390818e16..4ff4f7a2c8 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -853,7 +853,7 @@ func gen(n *Node) { cgen_dcl(n.Left) case OAS: - if gen_as_init(n) { + if gen_as_init(n, false) { break } Cgen_as(n.Left, n.Right) diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index 7875d16380..099c10a8bc 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -1236,6 +1236,7 @@ func getlit(lit *Node) int { return -1 } +// stataddr sets nam to the static address of n and reports whether it succeeeded. func stataddr(nam *Node, n *Node) bool { if n == nil { return false @@ -1408,7 +1409,9 @@ func entry(p *InitPlan) *InitEntry { return &p.E[len(p.E)-1] } -func gen_as_init(n *Node) bool { +// gen_as_init attempts to emit static data for n and reports whether it succeeded. +// If reportOnly is true, it does not emit static data and does not modify the AST. +func gen_as_init(n *Node, reportOnly bool) bool { var nr *Node var nl *Node var nam Node @@ -1457,7 +1460,9 @@ func gen_as_init(n *Node) bool { case OSLICEARR: if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil { nr = nr.Left - gused(nil) // in case the data is the dest of a goto + if !reportOnly { + gused(nil) // in case the data is the dest of a goto + } nl := nr if nr == nil || nr.Op != OADDR { goto no @@ -1472,16 +1477,18 @@ func gen_as_init(n *Node) bool { goto no } - nam.Xoffset += int64(Array_array) - gdata(&nam, nl, int(Types[Tptr].Width)) + if !reportOnly { + nam.Xoffset += int64(Array_array) + gdata(&nam, nl, int(Types[Tptr].Width)) - nam.Xoffset += int64(Array_nel) - int64(Array_array) - var nod1 Node - Nodconst(&nod1, Types[TINT], nr.Type.Bound) - gdata(&nam, &nod1, Widthint) + nam.Xoffset += int64(Array_nel) - int64(Array_array) + var nod1 Node + Nodconst(&nod1, Types[TINT], nr.Type.Bound) + gdata(&nam, &nod1, Widthint) - nam.Xoffset += int64(Array_cap) - int64(Array_nel) - gdata(&nam, &nod1, Widthint) + nam.Xoffset += int64(Array_cap) - int64(Array_nel) + gdata(&nam, &nod1, Widthint) + } return true } @@ -1512,13 +1519,19 @@ func gen_as_init(n *Node) bool { TPTR64, TFLOAT32, TFLOAT64: - gdata(&nam, nr, int(nr.Type.Width)) + if !reportOnly { + gdata(&nam, nr, int(nr.Type.Width)) + } case TCOMPLEX64, TCOMPLEX128: - gdatacomplex(&nam, nr.Val().U.(*Mpcplx)) + if !reportOnly { + gdatacomplex(&nam, nr.Val().U.(*Mpcplx)) + } case TSTRING: - gdatastring(&nam, nr.Val().U.(string)) + if !reportOnly { + gdatastring(&nam, nr.Val().U.(string)) + } } return true diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index b6b345f205..29b6a141a5 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -462,6 +462,17 @@ func (s *state) stmt(n *Node) { addEdge(b, lab.target) case OAS, OASWB: + // Check whether we can generate static data rather than code. + // If so, ignore n and defer data generation until codegen. + // Failure to do this causes writes to readonly symbols. + if gen_as_init(n, true) { + var data []*Node + if s.f.StaticData != nil { + data = s.f.StaticData.([]*Node) + } + s.f.StaticData = append(data, n) + return + } s.assign(n.Op, n.Left, n.Right) case OIF: @@ -1484,6 +1495,15 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { Pc.As = obj.ARET // overwrite AEND + // Emit static data + if f.StaticData != nil { + for _, n := range f.StaticData.([]*Node) { + if !gen_as_init(n, false) { + Fatal("non-static data marked as static: %v\n\n", n, f) + } + } + } + // TODO: liveness // TODO: gcargs // TODO: gclocals diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 34d2780104..e0f7c9ff60 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -9,13 +9,14 @@ import "sync" // A Func represents a Go func declaration (or function literal) and // its body. This package compiles each Func independently. type Func struct { - Config *Config // architecture information - Name string // e.g. bytes·Compare - Type Type // type signature of the function. - Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID) - Entry *Block // the entry basic block - bid idAlloc // block ID allocator - vid idAlloc // value ID allocator + Config *Config // architecture information + Name string // e.g. bytes·Compare + Type Type // type signature of the function. + StaticData interface{} // associated static data, untouched by the ssa package + Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID) + Entry *Block // the entry basic block + bid idAlloc // block ID allocator + vid idAlloc // value ID allocator // when register allocation is done, maps value ids to locations RegAlloc []Location