From f154da9e12608589e8d5f0508f908a0c3e88a1bb Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Thu, 15 Jan 2015 11:54:00 -0700 Subject: Imported Upstream version 1.4 --- src/cmd/5a/a.y | 2 +- src/cmd/5a/lex.c | 5 +- src/cmd/5a/y.tab.c | 2 +- src/cmd/5c/cgen.c | 38 +- src/cmd/5c/gc.h | 5 +- src/cmd/5c/peep.c | 4 + src/cmd/5c/reg.c | 19 +- src/cmd/5c/sgen.c | 2 +- src/cmd/5c/swt.c | 11 +- src/cmd/5c/txt.c | 40 +- src/cmd/5g/cgen.c | 81 +- src/cmd/5g/galign.c | 8 +- src/cmd/5g/gg.h | 12 +- src/cmd/5g/ggen.c | 25 +- src/cmd/5g/gsubr.c | 27 +- src/cmd/5g/opt.h | 20 + src/cmd/5g/peep.c | 6 + src/cmd/5g/reg.c | 12 +- src/cmd/5l/5.out.h | 166 +- src/cmd/5l/asm.c | 75 +- src/cmd/5l/l.h | 76 - src/cmd/5l/mkenam | 45 - src/cmd/5l/noop.c | 43 - src/cmd/5l/obj.c | 13 +- src/cmd/6a/a.y | 2 +- src/cmd/6a/lex.c | 35 +- src/cmd/6a/y.tab.c | 2 +- src/cmd/6c/cgen.c | 36 +- src/cmd/6c/gc.h | 5 +- src/cmd/6c/reg.c | 14 +- src/cmd/6c/sgen.c | 9 +- src/cmd/6c/swt.c | 9 +- src/cmd/6c/txt.c | 40 +- src/cmd/6g/cgen.c | 10 +- src/cmd/6g/galign.c | 8 +- src/cmd/6g/gg.h | 2 - src/cmd/6g/ggen.c | 61 +- src/cmd/6g/gsubr.c | 29 +- src/cmd/6g/opt.h | 20 + src/cmd/6g/reg.c | 8 +- src/cmd/6l/6.out.h | 2 +- src/cmd/6l/asm.c | 17 +- src/cmd/6l/l.h | 10 - src/cmd/6l/mkenam | 45 - src/cmd/8a/a.y | 2 +- src/cmd/8a/lex.c | 35 +- src/cmd/8a/y.tab.c | 2 +- src/cmd/8c/cgen.c | 38 +- src/cmd/8c/gc.h | 5 +- src/cmd/8c/reg.c | 9 +- src/cmd/8c/sgen.c | 2 +- src/cmd/8c/swt.c | 9 +- src/cmd/8c/txt.c | 40 +- src/cmd/8g/cgen.c | 88 +- src/cmd/8g/galign.c | 8 +- src/cmd/8g/gg.h | 1 - src/cmd/8g/ggen.c | 49 +- src/cmd/8g/gsubr.c | 26 +- src/cmd/8g/opt.h | 20 + src/cmd/8g/peep.c | 4 +- src/cmd/8g/reg.c | 6 + src/cmd/8l/8.out.h | 2 +- src/cmd/8l/asm.c | 18 +- src/cmd/8l/l.h | 7 - src/cmd/8l/mkenam | 45 - src/cmd/addr2line/addr2line_test.go | 5 +- src/cmd/addr2line/main.go | 166 +- src/cmd/api/goapi.go | 158 +- src/cmd/api/goapi_test.go | 24 +- src/cmd/api/run.go | 9 +- src/cmd/cc/bv.c | 45 - src/cmd/cc/cc.h | 8 +- src/cmd/cc/cc.y | 1 + src/cmd/cc/dcl.c | 25 +- src/cmd/cc/godefs.c | 67 +- src/cmd/cc/lex.c | 3 + src/cmd/cc/pgen.c | 202 +- src/cmd/cc/y.tab.c | 1147 +- src/cmd/cc/y.tab.h | 68 +- src/cmd/cgo/ast.go | 5 +- src/cmd/cgo/doc.go | 2 +- src/cmd/cgo/gcc.go | 187 +- src/cmd/cgo/out.go | 243 +- src/cmd/dist/a.h | 4 +- src/cmd/dist/arm.c | 3 +- src/cmd/dist/buf.c | 2 +- src/cmd/dist/build.c | 267 +- src/cmd/dist/buildgc.c | 38 +- src/cmd/dist/buildruntime.c | 84 +- src/cmd/dist/goc2c.c | 833 -- src/cmd/dist/plan9.c | 6 +- src/cmd/dist/unix.c | 16 +- src/cmd/dist/windows.c | 6 +- src/cmd/fix/doc.go | 2 +- src/cmd/fix/fix.go | 2 +- src/cmd/gc/align.c | 4 +- src/cmd/gc/bisonerrors | 18 +- src/cmd/gc/builtin.c | 33 +- src/cmd/gc/bv.c | 5 +- src/cmd/gc/const.c | 9 +- src/cmd/gc/dcl.c | 14 + src/cmd/gc/esc.c | 3 +- src/cmd/gc/fmt.c | 36 +- src/cmd/gc/gen.c | 75 +- src/cmd/gc/go.h | 17 +- src/cmd/gc/go.y | 15 +- src/cmd/gc/lex.c | 363 +- src/cmd/gc/md5.c | 12 +- src/cmd/gc/mparith1.c | 2 +- src/cmd/gc/mparith2.c | 4 +- src/cmd/gc/mparith3.c | 4 +- src/cmd/gc/obj.c | 9 +- src/cmd/gc/order.c | 48 +- src/cmd/gc/pgen.c | 57 +- src/cmd/gc/plive.c | 34 +- src/cmd/gc/popt.c | 6 +- src/cmd/gc/racewalk.c | 26 +- src/cmd/gc/range.c | 48 +- src/cmd/gc/reflect.c | 591 +- src/cmd/gc/runtime.go | 40 +- src/cmd/gc/select.c | 65 +- src/cmd/gc/sinit.c | 32 +- src/cmd/gc/subr.c | 193 +- src/cmd/gc/swt.c | 1 + src/cmd/gc/typecheck.c | 122 +- src/cmd/gc/walk.c | 543 +- src/cmd/gc/y.tab.c | 2566 ++-- src/cmd/gc/yerr.h | 84 +- src/cmd/go/build.go | 226 +- src/cmd/go/doc.go | 206 +- src/cmd/go/generate.go | 398 + src/cmd/go/generate_test.go | 48 + src/cmd/go/get.go | 35 +- src/cmd/go/go_windows_test.go | 55 + src/cmd/go/help.go | 29 +- src/cmd/go/list.go | 39 +- src/cmd/go/main.go | 5 +- src/cmd/go/mkdoc.sh | 2 +- src/cmd/go/pkg.go | 180 +- src/cmd/go/test.bash | 405 +- src/cmd/go/test.go | 178 +- src/cmd/go/testdata/generate/test1.go | 13 + src/cmd/go/testdata/generate/test2.go | 10 + src/cmd/go/testdata/generate/test3.go | 9 + src/cmd/go/testdata/importcom/bad.go | 3 + src/cmd/go/testdata/importcom/conflict.go | 3 + src/cmd/go/testdata/importcom/src/bad/bad.go | 1 + src/cmd/go/testdata/importcom/src/conflict/a.go | 1 + src/cmd/go/testdata/importcom/src/conflict/b.go | 1 + src/cmd/go/testdata/importcom/src/works/x/x.go | 1 + src/cmd/go/testdata/importcom/src/works/x/x1.go | 1 + src/cmd/go/testdata/importcom/src/wrongplace/x.go | 1 + src/cmd/go/testdata/importcom/works.go | 3 + src/cmd/go/testdata/importcom/wrongplace.go | 3 + src/cmd/go/testdata/norunexample/example_test.go | 11 + src/cmd/go/testdata/norunexample/test_test.go | 10 + src/cmd/go/testdata/src/badc/x.c | 1 + src/cmd/go/testdata/src/badc/x.go | 1 + src/cmd/go/testdata/src/badtest/badexec/x_test.go | 5 + src/cmd/go/testdata/src/badtest/badsyntax/x.go | 1 + .../go/testdata/src/badtest/badsyntax/x_test.go | 3 + src/cmd/go/testdata/src/badtest/badvar/x.go | 1 + src/cmd/go/testdata/src/badtest/badvar/x_test.go | 5 + src/cmd/go/testdata/src/vetpkg/a_test.go | 1 + src/cmd/go/testdata/src/vetpkg/b.go | 7 + src/cmd/go/testdata/testinternal/p.go | 3 + src/cmd/go/testdata/testinternal2/p.go | 3 + .../testdata/testinternal2/x/y/z/internal/w/w.go | 1 + src/cmd/go/testflag.go | 7 +- src/cmd/go/testgo.go | 21 + src/cmd/go/tool.go | 14 +- src/cmd/go/vcs.go | 149 +- src/cmd/go/vcs_test.go | 124 + src/cmd/go/vet.go | 25 +- src/cmd/gofmt/doc.go | 2 +- src/cmd/gofmt/gofmt.go | 193 +- src/cmd/gofmt/gofmt_test.go | 121 +- src/cmd/gofmt/long_test.go | 4 +- src/cmd/gofmt/rewrite.go | 3 - src/cmd/gofmt/simplify.go | 50 +- src/cmd/gofmt/testdata/composites.golden | 2 + src/cmd/gofmt/testdata/composites.input | 2 + src/cmd/gofmt/testdata/crlf.golden | 1 + src/cmd/gofmt/testdata/crlf.input | 1 + src/cmd/gofmt/testdata/emptydecl.golden | 14 + src/cmd/gofmt/testdata/emptydecl.input | 16 + src/cmd/gofmt/testdata/ranges.golden | 30 + src/cmd/gofmt/testdata/ranges.input | 20 + src/cmd/gofmt/testdata/rewrite1.golden | 2 + src/cmd/gofmt/testdata/rewrite1.input | 2 + src/cmd/gofmt/testdata/rewrite2.golden | 2 + src/cmd/gofmt/testdata/rewrite2.input | 2 + src/cmd/gofmt/testdata/rewrite3.golden | 2 + src/cmd/gofmt/testdata/rewrite3.input | 2 + src/cmd/gofmt/testdata/rewrite4.golden | 2 + src/cmd/gofmt/testdata/rewrite4.input | 2 + src/cmd/gofmt/testdata/rewrite5.golden | 2 + src/cmd/gofmt/testdata/rewrite5.input | 2 + src/cmd/gofmt/testdata/rewrite6.golden | 2 + src/cmd/gofmt/testdata/rewrite6.input | 2 + src/cmd/gofmt/testdata/rewrite7.golden | 2 + src/cmd/gofmt/testdata/rewrite7.input | 2 + src/cmd/gofmt/testdata/rewrite8.golden | 2 + src/cmd/gofmt/testdata/rewrite8.input | 2 + src/cmd/gofmt/testdata/slices1.golden | 8 + src/cmd/gofmt/testdata/slices1.input | 8 + src/cmd/gofmt/testdata/slices2.golden | 2 + src/cmd/gofmt/testdata/slices2.input | 2 + src/cmd/gofmt/testdata/stdin1.golden | 2 + src/cmd/gofmt/testdata/stdin1.golden.gofmt | 3 - src/cmd/gofmt/testdata/stdin1.input | 2 + src/cmd/gofmt/testdata/stdin1.input.gofmt | 3 - src/cmd/gofmt/testdata/stdin2.golden | 2 +- src/cmd/gofmt/testdata/stdin2.golden.gofmt | 10 - src/cmd/gofmt/testdata/stdin2.input | 2 +- src/cmd/gofmt/testdata/stdin2.input.gofmt | 11 - src/cmd/gofmt/testdata/stdin3.golden | 1 + src/cmd/gofmt/testdata/stdin3.golden.gofmt | 7 - src/cmd/gofmt/testdata/stdin3.input | 1 + src/cmd/gofmt/testdata/stdin3.input.gofmt | 7 - src/cmd/gofmt/testdata/stdin4.golden | 2 + src/cmd/gofmt/testdata/stdin4.golden.gofmt | 3 - src/cmd/gofmt/testdata/stdin4.input | 2 + src/cmd/gofmt/testdata/stdin4.input.gofmt | 3 - src/cmd/gofmt/testdata/stdin5.golden | 3 + src/cmd/gofmt/testdata/stdin5.input | 3 + src/cmd/gofmt/testdata/stdin6.golden | 19 + src/cmd/gofmt/testdata/stdin6.input | 21 + src/cmd/gofmt/testdata/stdin7.golden | 19 + src/cmd/gofmt/testdata/stdin7.input | 21 + src/cmd/internal/goobj/read.go | 666 + src/cmd/internal/goobj/read_test.go | 28 + src/cmd/internal/objfile/disasm.go | 248 + src/cmd/internal/objfile/elf.go | 104 + src/cmd/internal/objfile/goobj.go | 93 + src/cmd/internal/objfile/macho.go | 116 + src/cmd/internal/objfile/objfile.go | 94 + src/cmd/internal/objfile/pe.go | 201 + src/cmd/internal/objfile/plan9obj.go | 146 + src/cmd/internal/rsc.io/arm/armasm/Makefile | 2 + src/cmd/internal/rsc.io/arm/armasm/decode.go | 567 + src/cmd/internal/rsc.io/arm/armasm/decode_test.go | 69 + src/cmd/internal/rsc.io/arm/armasm/ext_test.go | 614 + src/cmd/internal/rsc.io/arm/armasm/gnu.go | 164 + src/cmd/internal/rsc.io/arm/armasm/inst.go | 438 + src/cmd/internal/rsc.io/arm/armasm/objdump_test.go | 258 + .../internal/rsc.io/arm/armasm/objdumpext_test.go | 260 + src/cmd/internal/rsc.io/arm/armasm/plan9x.go | 211 + src/cmd/internal/rsc.io/arm/armasm/tables.go | 9448 +++++++++++++ .../internal/rsc.io/arm/armasm/testdata/Makefile | 5 + .../internal/rsc.io/arm/armasm/testdata/decode.txt | 306 + src/cmd/internal/rsc.io/x86/x86asm/Makefile | 3 + src/cmd/internal/rsc.io/x86/x86asm/decode.go | 1616 +++ src/cmd/internal/rsc.io/x86/x86asm/decode_test.go | 71 + src/cmd/internal/rsc.io/x86/x86asm/ext_test.go | 811 ++ src/cmd/internal/rsc.io/x86/x86asm/gnu.go | 926 ++ src/cmd/internal/rsc.io/x86/x86asm/inst.go | 641 + src/cmd/internal/rsc.io/x86/x86asm/inst_test.go | 20 + src/cmd/internal/rsc.io/x86/x86asm/intel.go | 518 + src/cmd/internal/rsc.io/x86/x86asm/objdump_test.go | 383 + .../internal/rsc.io/x86/x86asm/objdumpext_test.go | 314 + .../internal/rsc.io/x86/x86asm/plan9ext_test.go | 120 + src/cmd/internal/rsc.io/x86/x86asm/plan9x.go | 346 + src/cmd/internal/rsc.io/x86/x86asm/plan9x_test.go | 54 + src/cmd/internal/rsc.io/x86/x86asm/tables.go | 9760 +++++++++++++ .../internal/rsc.io/x86/x86asm/testdata/Makefile | 12 + .../internal/rsc.io/x86/x86asm/testdata/decode.txt | 6731 +++++++++ src/cmd/internal/rsc.io/x86/x86asm/xed_test.go | 211 + src/cmd/internal/rsc.io/x86/x86asm/xedext_test.go | 206 + src/cmd/ld/data.c | 357 +- src/cmd/ld/decodesym.c | 38 +- src/cmd/ld/doc.go | 6 +- src/cmd/ld/dwarf.c | 156 +- src/cmd/ld/elf.c | 3 +- src/cmd/ld/ldelf.c | 8 +- src/cmd/ld/ldmacho.c | 4 +- src/cmd/ld/ldpe.c | 32 +- src/cmd/ld/lib.c | 91 +- src/cmd/ld/lib.h | 14 +- src/cmd/ld/macho.c | 3 +- src/cmd/ld/pass.c | 104 - src/cmd/ld/pcln.c | 6 +- src/cmd/ld/pobj.c | 22 +- src/cmd/ld/symtab.c | 55 +- src/cmd/ld/textflag.h | 13 + src/cmd/nm/debug_goobj.go | 670 - src/cmd/nm/elf.go | 57 - src/cmd/nm/goobj.go | 67 - src/cmd/nm/macho.go | 69 - src/cmd/nm/nm.go | 57 +- src/cmd/nm/nm_test.go | 11 +- src/cmd/nm/pe.go | 98 - src/cmd/nm/plan9obj.go | 48 - src/cmd/objdump/Makefile | 10 - src/cmd/objdump/armasm.go | 10821 --------------- src/cmd/objdump/elf.go | 65 - src/cmd/objdump/macho.go | 77 - src/cmd/objdump/main.go | 456 +- src/cmd/objdump/objdump_test.go | 122 +- src/cmd/objdump/pe.go | 99 - src/cmd/objdump/plan9obj.go | 63 - src/cmd/objdump/x86.go | 13800 ------------------- src/cmd/pack/doc.go | 4 + src/cmd/pack/pack.go | 50 +- src/cmd/pack/pack_test.go | 33 +- src/cmd/pprof/README | 8 + src/cmd/pprof/doc.go | 12 + src/cmd/pprof/internal/commands/commands.go | 215 + src/cmd/pprof/internal/driver/driver.go | 1036 ++ src/cmd/pprof/internal/driver/interactive.go | 492 + src/cmd/pprof/internal/fetch/fetch.go | 82 + src/cmd/pprof/internal/plugin/plugin.go | 213 + src/cmd/pprof/internal/profile/encode.go | 470 + src/cmd/pprof/internal/profile/filter.go | 157 + src/cmd/pprof/internal/profile/legacy_profile.go | 1250 ++ src/cmd/pprof/internal/profile/profile.go | 567 + src/cmd/pprof/internal/profile/proto.go | 298 + src/cmd/pprof/internal/profile/prune.go | 97 + src/cmd/pprof/internal/report/report.go | 1718 +++ src/cmd/pprof/internal/report/source.go | 450 + src/cmd/pprof/internal/report/source_html.go | 77 + src/cmd/pprof/internal/svg/svg.go | 75 + src/cmd/pprof/internal/symbolizer/symbolizer.go | 195 + src/cmd/pprof/internal/symbolz/symbolz.go | 111 + src/cmd/pprof/internal/tempfile/tempfile.go | 45 + src/cmd/pprof/pprof.go | 237 + src/cmd/yacc/Makefile | 12 - src/cmd/yacc/doc.go | 5 +- src/cmd/yacc/expr.y | 205 - src/cmd/yacc/testdata/expr/README | 20 + src/cmd/yacc/testdata/expr/expr.y | 202 + src/cmd/yacc/testdata/expr/main.go | 15 + src/cmd/yacc/yacc.go | 90 +- 333 files changed, 52860 insertions(+), 32995 deletions(-) delete mode 100644 src/cmd/5l/mkenam delete mode 100644 src/cmd/5l/noop.c delete mode 100644 src/cmd/6l/mkenam delete mode 100644 src/cmd/8l/mkenam delete mode 100644 src/cmd/cc/bv.c delete mode 100644 src/cmd/dist/goc2c.c create mode 100644 src/cmd/go/generate.go create mode 100644 src/cmd/go/generate_test.go create mode 100644 src/cmd/go/go_windows_test.go create mode 100644 src/cmd/go/testdata/generate/test1.go create mode 100644 src/cmd/go/testdata/generate/test2.go create mode 100644 src/cmd/go/testdata/generate/test3.go create mode 100644 src/cmd/go/testdata/importcom/bad.go create mode 100644 src/cmd/go/testdata/importcom/conflict.go create mode 100644 src/cmd/go/testdata/importcom/src/bad/bad.go create mode 100644 src/cmd/go/testdata/importcom/src/conflict/a.go create mode 100644 src/cmd/go/testdata/importcom/src/conflict/b.go create mode 100644 src/cmd/go/testdata/importcom/src/works/x/x.go create mode 100644 src/cmd/go/testdata/importcom/src/works/x/x1.go create mode 100644 src/cmd/go/testdata/importcom/src/wrongplace/x.go create mode 100644 src/cmd/go/testdata/importcom/works.go create mode 100644 src/cmd/go/testdata/importcom/wrongplace.go create mode 100644 src/cmd/go/testdata/norunexample/example_test.go create mode 100644 src/cmd/go/testdata/norunexample/test_test.go create mode 100644 src/cmd/go/testdata/src/badc/x.c create mode 100644 src/cmd/go/testdata/src/badc/x.go create mode 100644 src/cmd/go/testdata/src/badtest/badexec/x_test.go create mode 100644 src/cmd/go/testdata/src/badtest/badsyntax/x.go create mode 100644 src/cmd/go/testdata/src/badtest/badsyntax/x_test.go create mode 100644 src/cmd/go/testdata/src/badtest/badvar/x.go create mode 100644 src/cmd/go/testdata/src/badtest/badvar/x_test.go create mode 100644 src/cmd/go/testdata/src/vetpkg/a_test.go create mode 100644 src/cmd/go/testdata/src/vetpkg/b.go create mode 100644 src/cmd/go/testdata/testinternal/p.go create mode 100644 src/cmd/go/testdata/testinternal2/p.go create mode 100644 src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go create mode 100644 src/cmd/go/testgo.go create mode 100644 src/cmd/go/vcs_test.go create mode 100644 src/cmd/gofmt/testdata/emptydecl.golden create mode 100644 src/cmd/gofmt/testdata/emptydecl.input create mode 100644 src/cmd/gofmt/testdata/ranges.golden create mode 100644 src/cmd/gofmt/testdata/ranges.input delete mode 100644 src/cmd/gofmt/testdata/stdin1.golden.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin1.input.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin2.golden.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin2.input.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin3.golden.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin3.input.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin4.golden.gofmt delete mode 100644 src/cmd/gofmt/testdata/stdin4.input.gofmt create mode 100644 src/cmd/gofmt/testdata/stdin5.golden create mode 100644 src/cmd/gofmt/testdata/stdin5.input create mode 100644 src/cmd/gofmt/testdata/stdin6.golden create mode 100644 src/cmd/gofmt/testdata/stdin6.input create mode 100644 src/cmd/gofmt/testdata/stdin7.golden create mode 100644 src/cmd/gofmt/testdata/stdin7.input create mode 100644 src/cmd/internal/goobj/read.go create mode 100644 src/cmd/internal/goobj/read_test.go create mode 100644 src/cmd/internal/objfile/disasm.go create mode 100644 src/cmd/internal/objfile/elf.go create mode 100644 src/cmd/internal/objfile/goobj.go create mode 100644 src/cmd/internal/objfile/macho.go create mode 100644 src/cmd/internal/objfile/objfile.go create mode 100644 src/cmd/internal/objfile/pe.go create mode 100644 src/cmd/internal/objfile/plan9obj.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/Makefile create mode 100644 src/cmd/internal/rsc.io/arm/armasm/decode.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/decode_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/ext_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/gnu.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/inst.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/objdump_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/plan9x.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/tables.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/testdata/Makefile create mode 100644 src/cmd/internal/rsc.io/arm/armasm/testdata/decode.txt create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/Makefile create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/decode.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/decode_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/ext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/gnu.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/inst.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/inst_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/intel.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/objdump_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/objdumpext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9ext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9x.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9x_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/tables.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/testdata/Makefile create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/testdata/decode.txt create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/xed_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/xedext_test.go delete mode 100644 src/cmd/ld/pass.c delete mode 100644 src/cmd/nm/debug_goobj.go delete mode 100644 src/cmd/nm/elf.go delete mode 100644 src/cmd/nm/goobj.go delete mode 100644 src/cmd/nm/macho.go delete mode 100644 src/cmd/nm/pe.go delete mode 100644 src/cmd/nm/plan9obj.go delete mode 100644 src/cmd/objdump/Makefile delete mode 100644 src/cmd/objdump/armasm.go delete mode 100644 src/cmd/objdump/elf.go delete mode 100644 src/cmd/objdump/macho.go delete mode 100644 src/cmd/objdump/pe.go delete mode 100644 src/cmd/objdump/plan9obj.go delete mode 100644 src/cmd/objdump/x86.go create mode 100644 src/cmd/pprof/README create mode 100644 src/cmd/pprof/doc.go create mode 100644 src/cmd/pprof/internal/commands/commands.go create mode 100644 src/cmd/pprof/internal/driver/driver.go create mode 100644 src/cmd/pprof/internal/driver/interactive.go create mode 100644 src/cmd/pprof/internal/fetch/fetch.go create mode 100644 src/cmd/pprof/internal/plugin/plugin.go create mode 100644 src/cmd/pprof/internal/profile/encode.go create mode 100644 src/cmd/pprof/internal/profile/filter.go create mode 100644 src/cmd/pprof/internal/profile/legacy_profile.go create mode 100644 src/cmd/pprof/internal/profile/profile.go create mode 100644 src/cmd/pprof/internal/profile/proto.go create mode 100644 src/cmd/pprof/internal/profile/prune.go create mode 100644 src/cmd/pprof/internal/report/report.go create mode 100644 src/cmd/pprof/internal/report/source.go create mode 100644 src/cmd/pprof/internal/report/source_html.go create mode 100644 src/cmd/pprof/internal/svg/svg.go create mode 100644 src/cmd/pprof/internal/symbolizer/symbolizer.go create mode 100644 src/cmd/pprof/internal/symbolz/symbolz.go create mode 100644 src/cmd/pprof/internal/tempfile/tempfile.go create mode 100644 src/cmd/pprof/pprof.go delete mode 100644 src/cmd/yacc/Makefile delete mode 100644 src/cmd/yacc/expr.y create mode 100644 src/cmd/yacc/testdata/expr/README create mode 100644 src/cmd/yacc/testdata/expr/expr.y create mode 100644 src/cmd/yacc/testdata/expr/main.go (limited to 'src/cmd') diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y index 56d0c563d..ad647606e 100644 --- a/src/cmd/5a/a.y +++ b/src/cmd/5a/a.y @@ -33,7 +33,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" %} %union { diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c index 571fdf7f2..9c6970947 100644 --- a/src/cmd/5a/lex.c +++ b/src/cmd/5a/lex.c @@ -85,6 +85,7 @@ main(int argc, char *argv[]) ctxt = linknew(&linkarm); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit5(); fmtinstall('L', Lconv); @@ -199,8 +200,8 @@ struct "R6", LREG, 6, "R7", LREG, 7, "R8", LREG, 8, - "m", LREG, 9, // avoid unintentionally clobber m/g using R9/R10 - "g", LREG, 10, + "R9", LREG, 9, + "g", LREG, 10, // avoid unintentionally clobber g using R10 "R11", LREG, 11, "R12", LREG, 12, "R13", LREG, 13, diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c index 0bc8c34e1..a6251b835 100644 --- a/src/cmd/5a/y.tab.c +++ b/src/cmd/5a/y.tab.c @@ -69,7 +69,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" /* Line 371 of yacc.c */ #line 76 "y.tab.c" diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c index 08ed36055..5a049ae62 100644 --- a/src/cmd/5c/cgen.c +++ b/src/cmd/5c/cgen.c @@ -29,7 +29,7 @@ // THE SOFTWARE. #include "gc.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" void _cgen(Node *n, Node *nn, int inrel) @@ -46,7 +46,7 @@ _cgen(Node *n, Node *nn, int inrel) } if(n == Z || n->type == T) return; - if(typesuv[n->type->etype]) { + if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) { sugen(n, nn, n->type->width); return; } @@ -75,7 +75,7 @@ _cgen(Node *n, Node *nn, int inrel) if(r != Z && r->complex >= FNX) switch(o) { default: - regret(&nod, r); + regret(&nod, r, 0, 0); cgen(r, &nod); regsalloc(&nod1, r); @@ -107,7 +107,7 @@ _cgen(Node *n, Node *nn, int inrel) if(l->addable >= INDEXED && l->complex < FNX) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) - regret(&nod, r); + regret(&nod, r, 0, 0); else regalloc(&nod, r, nn); cgen(r, &nod); @@ -348,7 +348,7 @@ _cgen(Node *n, Node *nn, int inrel) if(l->op != OIND) diag(n, "bad function call"); - regret(&nod, l->left); + regret(&nod, l->left, 0, 0); cgen(l->left, &nod); regsalloc(&nod1, l->left); gopcode(OAS, &nod, Z, &nod1); @@ -366,22 +366,20 @@ _cgen(Node *n, Node *nn, int inrel) if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; - if(nn != Z) { - regret(&nod, n); - gopcode(OAS, &nod, Z, nn); + regret(&nod, n, l->type, 1); + if(nn != Z) + gmove(&nod, nn); + if(nod.op == OREGISTER) regfree(&nod); - } break; case OIND: @@ -823,7 +821,7 @@ boolgen(Node *n, int true, Node *nn) if(true) o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { - regret(&nod, r); + regret(&nod, r, 0, 0); cgenrel(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); @@ -957,7 +955,7 @@ sugen(Node *n, Node *nn, int32 w) if(nn != Z && side(nn)) { nod1 = *n; nod1.type = typ(TIND, n->type); - regret(&nod2, &nod1); + regret(&nod2, &nod1, 0, 0); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); gopcode(OAS, &nod2, Z, &nod0); @@ -1036,6 +1034,20 @@ sugen(Node *n, Node *nn, int32 w) break; case OFUNC: + if(!hasdotdotdot(n->left->type)) { + cgen(n, Z); + if(nn != Z) { + curarg -= n->type->width; + regret(&nod1, n, n->left->type, 1); + if(nn->complex >= FNX) { + regsalloc(&nod2, n); + cgen(&nod1, &nod2); + nod1 = nod2; + } + cgen(&nod1, nn); + } + break; + } if(nn == Z) { sugen(n, nodrat, w); break; diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h index 40d3a2b07..7417b7dbe 100644 --- a/src/cmd/5c/gc.h +++ b/src/cmd/5c/gc.h @@ -144,7 +144,6 @@ EXTERN Prog* lastp; EXTERN int32 maxargsafe; EXTERN int mnstring; EXTERN Multab multab[20]; -EXTERN int retok; extern int hintabsize; EXTERN Node* nodrat; EXTERN Node* nodret; @@ -211,7 +210,7 @@ void usedset(Node*, int); void xcom(Node*); int bcomplex(Node*, Node*); Prog* gtext(Sym*, int32); -vlong argsize(void); +vlong argsize(int); /* * cgen.c @@ -237,7 +236,7 @@ Node* nodconst(int32); Node* nod32const(vlong); Node* nodfconst(double); void nodreg(Node*, Node*, int); -void regret(Node*, Node*); +void regret(Node*, Node*, Type*, int); int tmpreg(void); void regalloc(Node*, Node*, Node*); void regfree(Node*); diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c index 143400a63..1de56b594 100644 --- a/src/cmd/5c/peep.c +++ b/src/cmd/5c/peep.c @@ -853,11 +853,15 @@ xtramodes(Reg *r, Addr *a) switch (p1->from.type) { case D_REG: /* register offset */ + if(nacl) + return 0; a->type = D_SHIFT; a->offset = p1->from.reg; break; case D_SHIFT: /* scaled register offset */ + if(nacl) + return 0; a->type = D_SHIFT; case D_CONST: /* immediate offset */ diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c index b9ac21abd..9024d5f49 100644 --- a/src/cmd/5c/reg.c +++ b/src/cmd/5c/reg.c @@ -204,6 +204,16 @@ regopt(Prog *p) break; } + /* the mod/div runtime routines smash R12 */ + switch(p->as) { + case AMOD: + case AMODU: + case ADIV: + case ADIVU: + regbits |= RtoB(12); + break; + } + if(p->as == AMOVM) { if(p->from.type == D_CONST) z = p->from.offset; @@ -396,7 +406,7 @@ loop2: rgp->cost = change; nregion++; if(nregion >= NRGN) { - warn(Z, "too many regions"); + fatal(Z, "too many regions"); goto brk; } rgp++; @@ -632,11 +642,8 @@ mkvar(Addr *a, int docon) if(s) if(s->name[0] == '.') goto none; - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c index efcc0437b..a36612caa 100644 --- a/src/cmd/5c/sgen.c +++ b/src/cmd/5c/sgen.c @@ -36,7 +36,7 @@ gtext(Sym *s, int32 stkoff) { int32 a; - a = argsize(); + a = argsize(1); if((textflag & NOSPLIT) != 0 && stkoff >= 128) yyerror("stack frame too large for NOSPLIT function"); diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c index fd81a4e68..f39963b8f 100644 --- a/src/cmd/5c/swt.c +++ b/src/cmd/5c/swt.c @@ -60,7 +60,7 @@ swit2(C1 *q, int nc, int32 def, Node *n) if(nc >= 3) { i = (q+nc-1)->val - (q+0)->val; - if(i > 0 && i < nc*2) + if(!nacl && i > 0 && i < nc*2) goto direct; } if(nc < 5) { @@ -374,10 +374,11 @@ align(int32 i, Type *t, int op, int32 *maxalign) { int32 o; Type *v; - int w; + int w, packw; o = i; w = 1; + packw = 0; switch(op) { default: diag(Z, "unknown align opcode %d", op); @@ -388,7 +389,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1) w = 1; if(packflg) - w = packflg; + packw = packflg; break; case Ael1: /* initial align of struct element */ @@ -404,7 +405,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1 || w > SZ_LONG) fatal(Z, "align"); if(packflg) - w = packflg; + packw = packflg; break; case Ael2: /* width of a struct element */ @@ -440,6 +441,8 @@ align(int32 i, Type *t, int op, int32 *maxalign) w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */ break; } + if(packw != 0 && xround(o, w) != xround(o, packw)) + diag(Z, "#pragma pack changes offset of %T", t); o = xround(o, w); if(maxalign != nil && *maxalign < w) *maxalign = w; diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c index a753510ca..af40220cc 100644 --- a/src/cmd/5c/txt.c +++ b/src/cmd/5c/txt.c @@ -274,15 +274,43 @@ nodreg(Node *n, Node *nn, int reg) } void -regret(Node *n, Node *nn) +regret(Node *n, Node *nn, Type *t, int mode) { int r; - r = REGRET; - if(typefd[nn->type->etype]) - r = FREGRET+NREG; - nodreg(n, nn, r); - reg[r]++; + if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) { + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET+NREG; + nodreg(n, nn, r); + reg[r]++; + return; + } + + if(mode == 1) { + // fetch returned value after call. + // already called gargs, so curarg is set. + curarg = (curarg+3) & ~3; + regaalloc(n, nn); + return; + } + + if(mode == 2) { + // store value to be returned. + // must compute arg offset. + if(t->etype != TFUNC) + fatal(Z, "bad regret func %T", t); + *n = *nn; + n->op = ONAME; + n->class = CPARAM; + n->sym = slookup(".ret"); + n->complex = nodret->complex; + n->xoffset = argsize(0); + n->addable = 20; + return; + } + + fatal(Z, "bad regret"); } int diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 9011b2022..c535cfbef 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -254,7 +254,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); goto sbop; @@ -1107,11 +1106,10 @@ bgen(Node *n, int true, int likely, Prog *to) { int et, a; Node *nl, *nr, *r; - Node n1, n2, n3, n4, tmp; + Node n1, n2, n3, tmp; NodeList *ll; Prog *p1, *p2; - USED(n4); // in unreachable code below if(debug['g']) { dump("\nbgen", n); } @@ -1497,7 +1495,7 @@ sgen(Node *n, Node *res, int64 w) if(osrc < odst && odst < osrc+w) dir = -dir; - if(op == AMOVW && dir > 0 && c >= 4 && c <= 128) { + if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) { r0.op = OREGISTER; r0.val.u.reg = REGALLOC_R0; r1.op = OREGISTER; @@ -1524,7 +1522,7 @@ sgen(Node *n, Node *res, int64 w) f = sysfunc("duffcopy"); p = gins(ADUFFCOPY, N, f); afunclit(&p->to, f); - // 8 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + // 8 and 128 = magic constants: see ../../runtime/asm_arm.s p->to.offset = 8*(128-c); regfree(&tmp); @@ -1636,7 +1634,10 @@ int componentgen(Node *nr, Node *nl) { Node nodl, nodr, tmp; + Type *t; int freel, freer; + vlong fldcount; + vlong loffset, roffset; freel = 0; freer = 0; @@ -1646,8 +1647,33 @@ componentgen(Node *nr, Node *nl) goto no; case TARRAY: - if(!isslice(nl->type)) + t = nl->type; + + // Slices are ok. + if(isslice(t)) + break; + // Small arrays are ok. + if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) + break; + + goto no; + + case TSTRUCT: + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + fldcount = 0; + for(t=nl->type->type; t; t=t->down) { + if(isfat(t->type)) + goto no; + if(t->etype != TFIELD) + fatal("componentgen: not a TFIELD: %lT", t); + fldcount++; + } + if(fldcount == 0 || fldcount > 4) goto no; + + break; + case TSTRING: case TINTER: break; @@ -1675,6 +1701,7 @@ componentgen(Node *nr, Node *nl) freer = 1; } + // nl and nr are 'cadable' which basically means they are names (variables) now. // If they are the same variable, don't generate any code, because the // VARDEF we generate will mark the old value as dead incorrectly. @@ -1684,8 +1711,25 @@ componentgen(Node *nr, Node *nl) switch(nl->type->etype) { case TARRAY: + // componentgen for arrays. if(nl->op == ONAME) gvardef(nl); + t = nl->type; + if(!isslice(t)) { + nodl.type = t->type; + nodr.type = nodl.type; + for(fldcount=0; fldcount < t->bound; fldcount++) { + if(nr == N) + clearslim(&nodl); + else + gmove(&nodr, &nodl); + nodl.xoffset += t->type->width; + nodr.xoffset += t->type->width; + } + goto yes; + } + + // componentgen for slices. nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1760,6 +1804,31 @@ componentgen(Node *nr, Node *nl) gmove(&nodr, &nodl); goto yes; + + case TSTRUCT: + if(nl->op == ONAME) + gvardef(nl); + loffset = nodl.xoffset; + roffset = nodr.xoffset; + // funarg structs may not begin at offset zero. + if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) + loffset -= nl->type->type->width; + if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) + roffset -= nr->type->type->width; + + for(t=nl->type->type; t; t=t->down) { + nodl.xoffset = loffset + t->width; + nodl.type = t->type; + + if(nr == N) + clearslim(&nodl); + else { + nodr.xoffset = roffset + t->width; + nodr.type = nodl.type; + gmove(&nodr, &nodl); + } + } + goto yes; } no: diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index a62102ef8..b4c45da69 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -23,10 +23,10 @@ vlong MAXWIDTH = (1LL<<32) - 1; */ Typedef typedefs[] = { - "int", TINT, TINT32, - "uint", TUINT, TUINT32, - "uintptr", TUINTPTR, TUINT32, - 0 + {"int", TINT, TINT32}, + {"uint", TUINT, TUINT32}, + {"uintptr", TUINTPTR, TUINT32}, + {0} }; void diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 413e93c24..00914bfa3 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -11,10 +11,13 @@ #define TEXTFLAG reg -#define REGALLOC_R0 0 -#define REGALLOC_RMAX REGEXT -#define REGALLOC_F0 NREG -#define REGALLOC_FMAX (REGALLOC_F0 + FREGEXT) +enum +{ + REGALLOC_R0 = 0, + REGALLOC_RMAX = REGEXT, + REGALLOC_F0 = NREG, + REGALLOC_FMAX = REGALLOC_F0 + FREGEXT, +}; EXTERN int32 dynloc; EXTERN uchar reg[REGALLOC_FMAX+1]; @@ -106,7 +109,6 @@ void split64(Node*, Node*, Node*); void splitclean(void); Node* ncon(uint32 i); void gtrack(Sym*); -void gargsize(int32); /* * obj.c diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index fb32c2f36..53cddb760 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -76,7 +76,7 @@ zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0) if(cnt < 4*widthptr) { for(i = 0; i < cnt; i += widthptr) p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i); - } else if(cnt <= 128*widthptr) { + } else if(!nacl && (cnt <= 128*widthptr)) { p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0); p->reg = REGSP; p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0); @@ -179,28 +179,12 @@ fixautoused(Prog* p) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node n1, r, r1, con; if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 3*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -297,9 +281,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* @@ -906,11 +887,11 @@ clearfat(Node *nl) patch(gbranch(ABNE, T, 0), pl); regfree(&end); - } else if(q >= 4) { + } else if(q >= 4 && !nacl) { f = sysfunc("duffzero"); p = gins(ADUFFZERO, N, f); afunclit(&p->to, f); - // 4 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s + // 4 and 128 = magic constants: see ../../runtime/asm_arm.s p->to.offset = 4*(128-q); } else while(q > 0) { diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index f66c87b5a..06e274e14 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -31,11 +31,11 @@ #include #include #include "gg.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" // TODO(rsc): Can make this bigger if we move // the text segment up higher in 5l for all GOOS. -// At the same time, can raise StackBig in ../../pkg/runtime/stack.h. +// At the same time, can raise StackBig in ../../runtime/stack.h. long unmappedzero = 4096; void @@ -206,17 +206,7 @@ ggloblnod(Node *nam) } void -gargsize(int32 size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - -void -ggloblsym(Sym *s, int32 width, int dupok, int rodata) +ggloblsym(Sym *s, int32 width, int8 flags) { Prog *p; @@ -227,10 +217,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p->to.type = D_CONST; p->to.name = D_NONE; p->to.offset = width; - if(dupok) - p->reg |= DUPOK; - if(rodata) - p->reg |= RODATA; + p->reg = flags; } void @@ -374,7 +361,7 @@ regalloc(Node *n, Type *t, Node *o) print("registers allocated at\n"); for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) print("%d %p\n", i, regpc[i]); - yyerror("out of fixed registers"); + fatal("out of fixed registers"); goto err; case TFLOAT32: @@ -387,7 +374,7 @@ regalloc(Node *n, Type *t, Node *o) for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) if(reg[i] == 0) goto out; - yyerror("out of floating point registers"); + fatal("out of floating point registers"); goto err; case TCOMPLEX64: @@ -636,6 +623,7 @@ splitclean(void) } #define CASE(a,b) (((a)<<16)|((b)<<0)) +/*c2go int CASE(int, int); */ void gmove(Node *f, Node *t) @@ -1601,7 +1589,6 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADD; break; diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index e3e3f78ed..1946c1d33 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -49,6 +49,24 @@ typedef struct Reg Reg; typedef struct Rgn Rgn; +/*c2go +extern Node *Z; +enum +{ + D_HI = D_NONE, + D_LO = D_NONE, + CLOAD = 5, + CREF = 5, + CINF = 1000, + LOOP = 3, +}; + +uint32 BLOAD(Reg*); +uint32 BSTORE(Reg*); +uint32 LOAD(Reg*); +uint32 STORE(Reg*); +*/ + // A Reg is a wrapper around a single Prog (one instruction) that holds // register optimization information while the optimizer runs. // r->prog is the instruction. @@ -71,8 +89,10 @@ struct Reg int32 regu; // register used bitmap }; #define R ((Reg*)0) +/*c2go extern Reg *R; */ #define NRGN 600 +/*c2go enum { NRGN = 600 }; */ struct Rgn { Reg* enter; diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index 4aa645206..639f4c5f6 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -564,6 +564,8 @@ gotit: * .. */ #define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; } +/*c2go void FAIL(char*); */ + int shiftprop(Flow *r) { @@ -875,11 +877,15 @@ xtramodes(Graph *g, Flow *r, Adr *a) switch (p1->from.type) { case D_REG: /* register offset */ + if(nacl) + return 0; a->type = D_SHIFT; a->offset = p1->from.reg; break; case D_SHIFT: /* scaled register offset */ + if(nacl) + return 0; a->type = D_SHIFT; case D_CONST: /* immediate offset */ diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 4762df506..b78c268df 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -36,6 +36,11 @@ #define NREGVAR 32 #define REGBITS ((uint32)0xffffffff) +/*c2go enum { + NREGVAR = 32, + REGBITS = 0xffffffff, +}; +*/ void addsplits(void); static Reg* firstr; @@ -194,7 +199,7 @@ regopt(Prog *firstp) proginfo(&info, p); // Avoid making variables for direct-called functions. - if(p->as == ABL && p->to.type == D_EXTERN) + if(p->as == ABL && p->to.name == D_EXTERN) continue; bit = mkvar(r, &p->from); @@ -222,6 +227,10 @@ regopt(Prog *firstp) for(z=0; zset.b[z] |= bit.b[z]; } + + /* the mod/div runtime routines smash R12 */ + if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU) + r->set.b[0] |= RtoB(12); } if(firstr == R) return; @@ -1306,6 +1315,7 @@ void addreg(Adr *a, int rn) { a->sym = nil; + a->node = nil; a->name = D_NONE; a->type = D_REG; a->reg = rn; diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index 9e8aceecb..7b16ac446 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -28,34 +28,94 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#define NSNAME 8 -#define NSYM 50 -#define NREG 16 +enum +{ + NSNAME = 8, + NSYM = 50, + NREG = 16, +}; #include "../ld/textflag.h" -#define REGRET 0 /* -1 disables use of REGARG */ #define REGARG -1 -/* compiler allocates R1 up as temps */ -/* compiler allocates register variables R3 up */ -#define REGEXT 10 -/* these two registers are declared in runtime.h */ -#define REGG (REGEXT-0) -#define REGM (REGEXT-1) -/* compiler allocates external registers R10 down */ -#define REGTMP 11 -#define REGSP 13 -#define REGLINK 14 -#define REGPC 15 - -#define NFREG 16 -#define FREGRET 0 -#define FREGEXT 7 -#define FREGTMP 15 +/*c2go enum { REGARG = -1 }; */ + +enum +{ + REGRET = 0, + /* compiler allocates R1 up as temps */ + /* compiler allocates register variables R3 up */ + /* compiler allocates external registers R10 down */ + REGEXT = 10, + /* these two registers are declared in runtime.h */ + REGG = REGEXT-0, + REGM = REGEXT-1, + + REGTMP = 11, + REGSP = 13, + REGLINK = 14, + REGPC = 15, + + NFREG = 16, + FREGRET = 0, + FREGEXT = 7, + FREGTMP = 15, +}; /* compiler allocates register variables F0 up */ /* compiler allocates external registers F7 down */ -enum as +enum +{ + C_NONE, + C_REG, + C_REGREG, + C_REGREG2, + C_SHIFT, + C_FREG, + C_PSR, + C_FCR, + + C_RCON, /* 0xff rotated */ + C_NCON, /* ~RCON */ + C_SCON, /* 0xffff */ + C_LCON, + C_LCONADDR, + C_ZFCON, + C_SFCON, + C_LFCON, + + C_RACON, + C_LACON, + + C_SBRA, + C_LBRA, + + C_HAUTO, /* halfword insn offset (-0xff to 0xff) */ + C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */ + C_HFAUTO, /* both H and F */ + C_SAUTO, /* -0xfff to 0xfff */ + C_LAUTO, + + C_HOREG, + C_FOREG, + C_HFOREG, + C_SOREG, + C_ROREG, + C_SROREG, /* both nil and R */ + C_LOREG, + + C_PC, + C_SP, + C_HREG, + + C_ADDR, /* reference to relocatable address */ + + C_GOK, + + C_NCLASS, /* must be the last */ +}; + +enum { AXXX, @@ -202,6 +262,8 @@ enum as AVARKILL, ADUFFCOPY, ADUFFZERO, + ADATABUNDLE, + ADATABUNDLEEND, AMRC, // MRC/MCR @@ -209,35 +271,38 @@ enum as }; /* scond byte */ -#define C_SCOND ((1<<4)-1) -#define C_SBIT (1<<4) -#define C_PBIT (1<<5) -#define C_WBIT (1<<6) -#define C_FBIT (1<<7) /* psr flags-only */ -#define C_UBIT (1<<7) /* up bit, unsigned bit */ - -#define C_SCOND_EQ 0 -#define C_SCOND_NE 1 -#define C_SCOND_HS 2 -#define C_SCOND_LO 3 -#define C_SCOND_MI 4 -#define C_SCOND_PL 5 -#define C_SCOND_VS 6 -#define C_SCOND_VC 7 -#define C_SCOND_HI 8 -#define C_SCOND_LS 9 -#define C_SCOND_GE 10 -#define C_SCOND_LT 11 -#define C_SCOND_GT 12 -#define C_SCOND_LE 13 -#define C_SCOND_NONE 14 -#define C_SCOND_NV 15 - -/* D_SHIFT type */ -#define SHIFT_LL 0<<5 -#define SHIFT_LR 1<<5 -#define SHIFT_AR 2<<5 -#define SHIFT_RR 3<<5 +enum +{ + C_SCOND = (1<<4)-1, + C_SBIT = 1<<4, + C_PBIT = 1<<5, + C_WBIT = 1<<6, + C_FBIT = 1<<7, /* psr flags-only */ + C_UBIT = 1<<7, /* up bit, unsigned bit */ + + C_SCOND_EQ = 0, + C_SCOND_NE = 1, + C_SCOND_HS = 2, + C_SCOND_LO = 3, + C_SCOND_MI = 4, + C_SCOND_PL = 5, + C_SCOND_VS = 6, + C_SCOND_VC = 7, + C_SCOND_HI = 8, + C_SCOND_LS = 9, + C_SCOND_GE = 10, + C_SCOND_LT = 11, + C_SCOND_GT = 12, + C_SCOND_LE = 13, + C_SCOND_NONE = 14, + C_SCOND_NV = 15, + + /* D_SHIFT type */ + SHIFT_LL = 0<<5, + SHIFT_LR = 1<<5, + SHIFT_AR = 2<<5, + SHIFT_RR = 3<<5, +}; enum { @@ -279,3 +344,4 @@ enum * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" +/*c2go extern char SYMDEF[]; */ diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index e87921218..9c1c04e2d 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -648,19 +648,20 @@ asmb(void) switch(HEADTYPE) { default: case Hplan9: /* plan 9 */ - lput(0x647); /* magic */ - lput(segtext.filelen); /* sizes */ - lput(segdata.filelen); - lput(segdata.len - segdata.filelen); - lput(symsize); /* nsyms */ - lput(entryvalue()); /* va of entry */ - lput(0L); - lput(lcsize); + LPUT(0x647); /* magic */ + LPUT(segtext.filelen); /* sizes */ + LPUT(segdata.filelen); + LPUT(segdata.len - segdata.filelen); + LPUT(symsize); /* nsyms */ + LPUT(entryvalue()); /* va of entry */ + LPUT(0L); + LPUT(lcsize); break; case Hlinux: case Hfreebsd: case Hnetbsd: case Hopenbsd: + case Hnacl: asmbelf(symo); break; } @@ -675,64 +676,6 @@ asmb(void) } } -/* -void -cput(int32 c) -{ - *cbp++ = c; - if(--cbc <= 0) - cflush(); -} -*/ - -void -wput(int32 l) -{ - - cbp[0] = l>>8; - cbp[1] = l; - cbp += 2; - cbc -= 2; - if(cbc <= 0) - cflush(); -} - - -void -hput(int32 l) -{ - - cbp[0] = l>>8; - cbp[1] = l; - cbp += 2; - cbc -= 2; - if(cbc <= 0) - cflush(); -} - -void -lput(int32 l) -{ - - cbp[0] = l>>24; - cbp[1] = l>>16; - cbp[2] = l>>8; - cbp[3] = l; - cbp += 4; - cbc -= 4; - if(cbc <= 0) - cflush(); -} - -void -nopstat(char *f, Count *c) -{ - if(c->outof) - Bprint(&bso, "%s delay %d/%d (%.2f)\n", f, - c->outof - c->count, c->outof, - (double)(c->outof - c->count)/c->outof); -} - int32 rnd(int32 v, int32 r) { diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 761bc861a..c881a544a 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -48,23 +48,8 @@ enum #define EXTERN extern #endif -/* do not undefine this - code will be removed eventually */ -#define CALLEEBX - -#define dynptrsize 0 - #define P ((Prog*)0) #define S ((LSym*)0) -#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) - -#define SIGNINTERN (1729*325*1729) - -typedef struct Count Count; -struct Count -{ - int32 count; - int32 outof; -}; enum { @@ -73,62 +58,9 @@ enum LABEL = 1<<1, LEAF = 1<<2, - STRINGSZ = 200, - MINSIZ = 64, - NENT = 100, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ MINLC = 4, - - C_NONE = 0, - C_REG, - C_REGREG, - C_REGREG2, - C_SHIFT, - C_FREG, - C_PSR, - C_FCR, - - C_RCON, /* 0xff rotated */ - C_NCON, /* ~RCON */ - C_SCON, /* 0xffff */ - C_LCON, - C_LCONADDR, - C_ZFCON, - C_SFCON, - C_LFCON, - - C_RACON, - C_LACON, - - C_SBRA, - C_LBRA, - - C_HAUTO, /* halfword insn offset (-0xff to 0xff) */ - C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */ - C_HFAUTO, /* both H and F */ - C_SAUTO, /* -0xfff to 0xfff */ - C_LAUTO, - - C_HOREG, - C_FOREG, - C_HFOREG, - C_SOREG, - C_ROREG, - C_SROREG, /* both nil and R */ - C_LOREG, - - C_PC, - C_SP, - C_HREG, - - C_ADDR, /* reference to relocatable address */ - - C_GOK, }; -#ifndef COFFCVT - EXTERN int32 autosize; EXTERN LSym* datap; EXTERN int debug[128]; @@ -152,26 +84,18 @@ void adddynrela(LSym *rel, LSym *s, Reloc *r); void adddynsym(Link *ctxt, LSym *s); int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void cput(int32 c); int elfreloc1(Reloc *r, vlong sectoff); void elfsetupplt(void); -void hput(int32 l); void listinit(void); -void lput(int32 l); int machoreloc1(Reloc *r, vlong sectoff); void main(int argc, char *argv[]); -void noops(void); -void nopstat(char *f, Count *c); int32 rnd(int32 v, int32 r); -void wput(int32 l); /* Native is little-endian */ #define LPUT(a) lputl(a) #define WPUT(a) wputl(a) #define VPUT(a) abort() -#endif - /* Used by ../ld/dwarf.c */ enum { diff --git a/src/cmd/5l/mkenam b/src/cmd/5l/mkenam deleted file mode 100644 index 6cccb0263..000000000 --- a/src/cmd/5l/mkenam +++ /dev/null @@ -1,45 +0,0 @@ -# Inferno utils/5c/mkenam -# http://code.google.com/p/inferno-os/source/browse/utils/5c/mkenam -# -# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -# Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -# Portions Copyright © 1997-1999 Vita Nuova Limited -# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -# Portions Copyright © 2004,2006 Bruce Ellis -# Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -# Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -# Portions Copyright © 2009 The Go Authors. All rights reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -awk ' -BEGIN { - print "char* anames[] =" - print "{" -} - -/^ A/ { - name=$1 - sub(/,/, "", name) - sub(/^A/, "", name) - print "\t\"" name "\"," -} - -END { print "};" } -' ../5l/5.out.h >enam.c diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c deleted file mode 100644 index d42c86289..000000000 --- a/src/cmd/5l/noop.c +++ /dev/null @@ -1,43 +0,0 @@ -// Inferno utils/5l/noop.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Code transformations. - -#include "l.h" -#include "../ld/lib.h" - -void -noops(void) -{ - LSym *s; - - for(s = ctxt->textp; s != nil; s = s->next) - ctxt->arch->addstacksplit(ctxt, s); -} diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index 86a0ece2e..c6f60ee7c 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -63,6 +63,7 @@ archinit(void) break; case Hlinux: case Hfreebsd: + case Hnacl: break; } @@ -82,7 +83,6 @@ archinit(void) case Hlinux: /* arm elf */ case Hfreebsd: case Hnetbsd: - case Hnacl: debug['d'] = 0; // with dynamic linking elfinit(); HEADR = ELFRESERVE; @@ -93,6 +93,17 @@ archinit(void) if(INITRND == -1) INITRND = 4096; break; + case Hnacl: + elfinit(); + HEADR = 0x10000; + funcalign = 16; + if(INITTEXT == -1) + INITTEXT = 0x20000; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 0x10000; + break; } if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%ux is ignored because of -R0x%ux\n", diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y index 6fd491067..1089d4061 100644 --- a/src/cmd/6a/a.y +++ b/src/cmd/6a/a.y @@ -33,7 +33,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" %} %union { Sym *sym; diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c index 167e6b6c1..8973d6974 100644 --- a/src/cmd/6a/lex.c +++ b/src/cmd/6a/lex.c @@ -101,6 +101,7 @@ main(int argc, char *argv[]) ctxt = linknew(thelinkarch); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit6(); fmtinstall('L', Lconv); @@ -435,49 +436,49 @@ struct "IRETQ", LTYPE0, AIRETQ, "IRETW", LTYPE0, AIRETW, - "JOS", LTYPER, AJOS, + "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */ "JO", LTYPER, AJOS, /* alternate */ - "JOC", LTYPER, AJOC, + "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */ "JNO", LTYPER, AJOC, /* alternate */ - "JCS", LTYPER, AJCS, + "JCS", LTYPER, AJCS, /* carry set (CF = 1) */ "JB", LTYPER, AJCS, /* alternate */ "JC", LTYPER, AJCS, /* alternate */ "JNAE", LTYPER, AJCS, /* alternate */ "JLO", LTYPER, AJCS, /* alternate */ - "JCC", LTYPER, AJCC, + "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */ "JAE", LTYPER, AJCC, /* alternate */ "JNB", LTYPER, AJCC, /* alternate */ "JNC", LTYPER, AJCC, /* alternate */ "JHS", LTYPER, AJCC, /* alternate */ - "JEQ", LTYPER, AJEQ, + "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */ "JE", LTYPER, AJEQ, /* alternate */ "JZ", LTYPER, AJEQ, /* alternate */ - "JNE", LTYPER, AJNE, + "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */ "JNZ", LTYPER, AJNE, /* alternate */ - "JLS", LTYPER, AJLS, + "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ "JBE", LTYPER, AJLS, /* alternate */ "JNA", LTYPER, AJLS, /* alternate */ - "JHI", LTYPER, AJHI, + "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */ "JA", LTYPER, AJHI, /* alternate */ "JNBE", LTYPER, AJHI, /* alternate */ - "JMI", LTYPER, AJMI, + "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */ "JS", LTYPER, AJMI, /* alternate */ - "JPL", LTYPER, AJPL, + "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */ "JNS", LTYPER, AJPL, /* alternate */ - "JPS", LTYPER, AJPS, + "JPS", LTYPER, AJPS, /* parity set (PF = 1) */ "JP", LTYPER, AJPS, /* alternate */ "JPE", LTYPER, AJPS, /* alternate */ - "JPC", LTYPER, AJPC, + "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */ "JNP", LTYPER, AJPC, /* alternate */ "JPO", LTYPER, AJPC, /* alternate */ - "JLT", LTYPER, AJLT, + "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */ "JL", LTYPER, AJLT, /* alternate */ "JNGE", LTYPER, AJLT, /* alternate */ - "JGE", LTYPER, AJGE, + "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */ "JNL", LTYPER, AJGE, /* alternate */ - "JLE", LTYPER, AJLE, + "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */ "JNG", LTYPER, AJLE, /* alternate */ - "JGT", LTYPER, AJGT, + "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */ "JG", LTYPER, AJGT, /* alternate */ "JNLE", LTYPER, AJGT, /* alternate */ "JCXZL", LTYPER, AJCXZL, @@ -612,7 +613,7 @@ struct "SCASL", LTYPE0, ASCASL, "SCASQ", LTYPE0, ASCASQ, "SCASW", LTYPE0, ASCASW, - "SETCC", LTYPE1, ASETCC, + "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */ "SETCS", LTYPE1, ASETCS, "SETEQ", LTYPE1, ASETEQ, "SETGE", LTYPE1, ASETGE, diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c index a4f0f74cc..b69fd95b5 100644 --- a/src/cmd/6a/y.tab.c +++ b/src/cmd/6a/y.tab.c @@ -150,7 +150,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" /* Enabling traces. */ diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c index bdef76ff0..68dd7bb5f 100644 --- a/src/cmd/6c/cgen.c +++ b/src/cmd/6c/cgen.c @@ -29,7 +29,7 @@ // THE SOFTWARE. #include "gc.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" /* ,x/^(print|prtree)\(/i/\/\/ */ int castup(Type*, Type*); @@ -51,7 +51,7 @@ cgen(Node *n, Node *nn) } if(n == Z || n->type == T) return; - if(typesu[n->type->etype]) { + if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) { sugen(n, nn, n->type->width); return; } @@ -88,7 +88,7 @@ cgen(Node *n, Node *nn) if(cond(o) && typesu[l->type->etype]) break; - regret(&nod, r); + regret(&nod, r, 0, 0); cgen(r, &nod); regsalloc(&nod1, r); @@ -135,7 +135,7 @@ cgen(Node *n, Node *nn) if(!hardleft) { if(nn != Z || r->addable < INDEXED || hardconst(r)) { if(r->complex >= FNX && nn == Z) - regret(&nod, r); + regret(&nod, r, 0, 0); else regalloc(&nod, r, nn); cgen(r, &nod); @@ -929,7 +929,7 @@ cgen(Node *n, Node *nn) if(l->op != OIND) diag(n, "bad function call"); - regret(&nod, l->left); + regret(&nod, l->left, 0, 0); cgen(l->left, &nod); regsalloc(&nod1, l->left); gmove(&nod, &nod1); @@ -945,7 +945,6 @@ cgen(Node *n, Node *nn) return; } gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; @@ -953,14 +952,13 @@ cgen(Node *n, Node *nn) regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0 && reg[REGARG]) reg[REGARG]--; - if(nn != Z) { - regret(&nod, n); + regret(&nod, n, l->type, 1); // update maxarg if nothing else + if(nn != Z) gmove(&nod, nn); + if(nod.op == OREGISTER) regfree(&nod); - } break; case OIND: @@ -1382,7 +1380,7 @@ boolgen(Node *n, int true, Node *nn) if(true) o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { - regret(&nod, r); + regret(&nod, r, 0, 0); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); @@ -1535,7 +1533,7 @@ sugen(Node *n, Node *nn, int32 w) if(nn != Z && side(nn)) { nod1 = *n; nod1.type = typ(TIND, n->type); - regret(&nod2, &nod1); + regret(&nod2, &nod1, 0, 0); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); cgen(&nod2, &nod0); @@ -1617,6 +1615,20 @@ sugen(Node *n, Node *nn, int32 w) break; case OFUNC: + if(!hasdotdotdot(n->left->type)) { + cgen(n, Z); + if(nn != Z) { + curarg -= n->type->width; + regret(&nod1, n, n->left->type, 1); + if(nn->complex >= FNX) { + regsalloc(&nod2, n); + cgen(&nod1, &nod2); + nod1 = nod2; + } + cgen(&nod1, nn); + } + break; + } if(nn == Z) { sugen(n, nodrat, w); break; diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h index a196e55a8..aa9d95d21 100644 --- a/src/cmd/6c/gc.h +++ b/src/cmd/6c/gc.h @@ -143,7 +143,6 @@ EXTERN int32 cursafe; EXTERN Prog* lastp; EXTERN int32 maxargsafe; EXTERN int mnstring; -EXTERN int retok; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; @@ -211,7 +210,7 @@ void xcom(Node*); void indx(Node*); int bcomplex(Node*, Node*); Prog* gtext(Sym*, int32); -vlong argsize(void); +vlong argsize(int); /* * cgen.c @@ -240,7 +239,7 @@ Node* nodfconst(double); Node* nodgconst(vlong, Type*); int nodreg(Node*, Node*, int); int isreg(Node*, int); -void regret(Node*, Node*); +void regret(Node*, Node*, Type*, int); void regalloc(Node*, Node*, Node*); void regfree(Node*); void regialloc(Node*, Node*, Node*); diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c index 348d747b7..6f8d3ce14 100644 --- a/src/cmd/6c/reg.c +++ b/src/cmd/6c/reg.c @@ -585,14 +585,11 @@ loop2: } rgp->cost = change; nregion++; - if(nregion >= NRGN) { - warn(Z, "too many regions"); - goto brk; - } + if(nregion >= NRGN) + fatal(Z, "too many regions"); rgp++; } } -brk: qsort(region, nregion, sizeof(region[0]), rcmp); /* @@ -808,11 +805,8 @@ mkvar(Reg *r, Addr *a) goto out; v++; } - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c index ba1c1f652..fceb332b2 100644 --- a/src/cmd/6c/sgen.c +++ b/src/cmd/6c/sgen.c @@ -29,14 +29,14 @@ // THE SOFTWARE. #include "gc.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" Prog* gtext(Sym *s, int32 stkoff) { vlong v; - v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff); + v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff); if((textflag & NOSPLIT) && stkoff >= 128) yyerror("stack frame too large for NOSPLIT function"); @@ -124,10 +124,7 @@ xcom(Node *n) break; case ONAME: - if(flag_largemodel) - n->addable = 9; - else - n->addable = 10; + n->addable = 9; if(n->class == CPARAM || n->class == CAUTO) n->addable = 11; break; diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c index d7713648d..6e918eb10 100644 --- a/src/cmd/6c/swt.c +++ b/src/cmd/6c/swt.c @@ -250,10 +250,11 @@ align(int32 i, Type *t, int op, int32 *maxalign) { int32 o; Type *v; - int w; + int w, packw; o = i; w = 1; + packw = 0; switch(op) { default: diag(Z, "unknown align opcode %d", op); @@ -264,7 +265,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1) w = 1; if(packflg) - w = packflg; + packw = packflg; break; case Ael1: /* initial align of struct element */ @@ -277,7 +278,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1 || w > SZ_VLONG) fatal(Z, "align"); if(packflg) - w = packflg; + packw = packflg; break; case Ael2: /* width of a struct element */ @@ -331,6 +332,8 @@ align(int32 i, Type *t, int op, int32 *maxalign) o = align(o, t, Ael2, nil); break; } + if(packw != 0 && xround(o, w) != xround(o, packw)) + diag(Z, "#pragma pack changes offset of %T", t); o = xround(o, w); if(maxalign && *maxalign < w) *maxalign = w; diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c index 4d07436c3..3bdbf410e 100644 --- a/src/cmd/6c/txt.c +++ b/src/cmd/6c/txt.c @@ -351,15 +351,43 @@ nodreg(Node *n, Node *nn, int r) } void -regret(Node *n, Node *nn) +regret(Node *n, Node *nn, Type *t, int mode) { int r; + + if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) { + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET; + nodreg(n, nn, r); + reg[r]++; + return; + } + + if(mode == 1) { + // fetch returned value after call. + // already called gargs, so curarg is set. + curarg = (curarg+7) & ~7; + regaalloc(n, nn); + return; + } - r = REGRET; - if(typefd[nn->type->etype]) - r = FREGRET; - nodreg(n, nn, r); - reg[r]++; + if(mode == 2) { + // store value to be returned. + // must compute arg offset. + if(t->etype != TFUNC) + fatal(Z, "bad regret func %T", t); + *n = *nn; + n->op = ONAME; + n->class = CPARAM; + n->sym = slookup(".ret"); + n->complex = nodret->complex; + n->addable = 20; + n->xoffset = argsize(0); + return; + } + + fatal(Z, "bad regret"); } void diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 4dd505b08..d13c98dad 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -247,7 +247,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { @@ -752,12 +751,7 @@ agenr(Node *n, Node *a, Node *res) regalloc(&n3, types[tptr], res); p1 = gins(ALEAQ, N, &n3); datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - if(flag_largemodel) { - gins(AADDQ, &n2, &n3); - } else { - p1->from.scale = 1; - p1->from.index = n2.val.u.reg; - } + gins(AADDQ, &n2, &n3); goto indexdone; } @@ -1457,7 +1451,7 @@ sgen(Node *n, Node *ns, int64 w) p = gins(ADUFFCOPY, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); - // 14 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s + // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s p->to.offset = 14*(128-q); } else while(q > 0) { diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c index 1d32c5a61..5670e6fac 100644 --- a/src/cmd/6g/galign.c +++ b/src/cmd/6g/galign.c @@ -30,10 +30,10 @@ int cmpptr = ACMPQ; */ Typedef typedefs[] = { - "int", TINT, TINT64, - "uint", TUINT, TUINT64, - "uintptr", TUINTPTR, TUINT64, - 0 + {"int", TINT, TINT64}, + {"uint", TUINT, TUINT64}, + {"uintptr", TUINTPTR, TUINT64}, + {0} }; void diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index a5da17d61..fe69d5c96 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -51,7 +51,6 @@ void allocparams(void); void checklabels(void); void ginscall(Node*, int); int gen_as_init(Node*); -void clearslim(Node*); /* * cgen.c @@ -100,7 +99,6 @@ int sudoaddable(int, Node*, Addr*); void afunclit(Addr*, Node*); void nodfconst(Node*, Type*, Mpflt*); void gtrack(Sym*); -void gargsize(vlong); void fixlargeoffset(Node *n); /* diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 9665d831b..363620769 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -175,7 +175,6 @@ fixautoused(Prog *p) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node reg, con; Node r1; @@ -183,21 +182,6 @@ ginscall(Node *f, int proc) if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 2*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -275,9 +259,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* @@ -1121,26 +1102,54 @@ clearfat(Node *nl) c = w % 8; // bytes q = w / 8; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSQ. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSQ loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + agenr(nl, &n1, N); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVQ, &z, &n1); + n1.xoffset += 8; + } + if(c >= 4) { + nodconst(&z, types[TUINT32], 0); + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + c -= 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + savex(D_DI, &n1, &oldn1, N, types[tptr]); agen(nl, &n1); savex(D_AX, &ax, &oldax, N, types[tptr]); gconreg(AMOVL, 0, D_AX); - if(q > 128 || (q >= 4 && nacl)) { + if(q > 128 || nacl) { gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - } else if(q >= 4) { + } else { p = gins(ADUFFZERO, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - // 2 and 128 = magic constants: see ../../pkg/runtime/asm_amd64.s + // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s p->to.offset = 2*(128-q); - } else - while(q > 0) { - gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - q--; } z = ax; diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index e4d00bf41..5bd924660 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -31,11 +31,11 @@ #include #include #include "gg.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" // TODO(rsc): Can make this bigger if we move // the text segment up higher in 6l for all GOOS. -// At the same time, can raise StackBig in ../../pkg/runtime/stack.h. +// At the same time, can raise StackBig in ../../runtime/stack.h. vlong unmappedzero = 4096; void @@ -215,17 +215,7 @@ gtrack(Sym *s) } void -gargsize(vlong size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - -void -ggloblsym(Sym *s, int32 width, int dupok, int rodata) +ggloblsym(Sym *s, int32 width, int8 flags) { Prog *p; @@ -236,10 +226,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p->to.type = D_CONST; p->to.index = D_NONE; p->to.offset = width; - if(dupok) - p->from.scale |= DUPOK; - if(rodata) - p->from.scale |= RODATA; + p->from.scale = flags; } int @@ -584,6 +571,7 @@ ginscon(int as, vlong c, Node *n2) } #define CASE(a,b) (((a)<<16)|((b)<<0)) +/*c2go int CASE(int, int); */ /* * Is this node a memory operand? @@ -600,11 +588,8 @@ ismem(Node *n) case ONAME: case OPARAM: case OCLOSUREVAR: - return 1; case OADDR: - if(flag_largemodel) - return 1; - break; + return 1; } return 0; } @@ -1542,14 +1527,12 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADDL; break; case CASE(OADD, TINT64): case CASE(OADD, TUINT64): case CASE(OADD, TPTR64): - case CASE(OADDPTR, TPTR64): a = AADDQ; break; diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index bf356af0c..dbd039d89 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -49,6 +49,24 @@ typedef struct Reg Reg; typedef struct Rgn Rgn; +/*c2go +extern Node *Z; +enum +{ + D_HI = D_NONE, + D_LO = D_NONE, + CLOAD = 5, + CREF = 5, + CINF = 1000, + LOOP = 3, +}; + +uint32 BLOAD(Reg*); +uint32 BSTORE(Reg*); +uint32 LOAD(Reg*); +uint32 STORE(Reg*); +*/ + // A Reg is a wrapper around a single Prog (one instruction) that holds // register optimization information while the optimizer runs. // r->prog is the instruction. @@ -71,8 +89,10 @@ struct Reg int32 regu; // register used bitmap }; #define R ((Reg*)0) +/*c2go extern Reg *R; */ #define NRGN 600 +/*c2go enum { NRGN = 600 }; */ struct Rgn { Reg* enter; diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index f3b1e55de..1f757e197 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -35,6 +35,11 @@ #define NREGVAR 32 /* 16 general + 16 floating */ #define REGBITS ((uint32)0xffffffff) +/*c2go enum { + NREGVAR = 32, + REGBITS = 0xffffffff, +}; +*/ static Reg* firstr; static int first = 1; @@ -839,7 +844,7 @@ prop(Reg *r, Bits ref, Bits cal) if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) { for(; v1 != nil; v1 = v1->nextinnode) { j = v1 - var; - cal.b[j/32] |= 1<<(j&31); + cal.b[j/32] |= 1UL<<(j&31); } } } @@ -1186,6 +1191,7 @@ void addreg(Adr *a, int rn) { a->sym = nil; + a->node = nil; a->offset = 0; a->type = rn; diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 1e2a1488f..af72784e8 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -36,7 +36,7 @@ * amd64 */ -enum as +enum { AXXX, AAAA, diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 7828e2892..18b5aa311 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -290,7 +290,6 @@ elfreloc1(Reloc *r, vlong sectoff) break; case R_CALL: - case R_PCREL: if(r->siz == 4) { if(r->xsym->type == SDYNIMPORT) VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32); @@ -299,7 +298,14 @@ elfreloc1(Reloc *r, vlong sectoff) } else return -1; break; - + + case R_PCREL: + if(r->siz == 4) { + VPUT(R_X86_64_PC32 | (uint64)elfsym<<32); + } else + return -1; + break; + case R_TLS: if(r->siz == 4) { if(flag_shared) @@ -323,7 +329,7 @@ machoreloc1(Reloc *r, vlong sectoff) rs = r->xsym; - if(rs->type == SHOSTOBJ) { + if(rs->type == SHOSTOBJ || r->type == R_PCREL) { if(rs->dynid < 0) { diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); return -1; @@ -345,10 +351,13 @@ machoreloc1(Reloc *r, vlong sectoff) v |= MACHO_X86_64_RELOC_UNSIGNED<<28; break; case R_CALL: - case R_PCREL: v |= 1<<24; // pc-relative bit v |= MACHO_X86_64_RELOC_BRANCH<<28; break; + case R_PCREL: + // NOTE: Only works with 'external' relocation. Forced above. + v |= 1<<24; // pc-relative bit + v |= MACHO_X86_64_RELOC_SIGNED<<28; } switch(r->siz) { diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 7303910a6..ff2e69452 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -68,14 +68,9 @@ EXTERN int RegSize; #define P ((Prog*)0) #define S ((LSym*)0) -#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { - MINSIZ = 8, - STRINGSZ = 200, MINLC = 1, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ }; #pragma varargck type "I" uchar* @@ -89,9 +84,6 @@ EXTERN int32 spsize; EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN vlong textstksiz; -EXTERN vlong textarg; - int Iconv(Fmt *fp); void adddynlib(char *lib); void adddynrel(LSym *s, Reloc *r); @@ -103,8 +95,6 @@ int elfreloc1(Reloc *r, vlong sectoff); void elfsetupplt(void); void listinit(void); int machoreloc1(Reloc *r, vlong sectoff); -void main(int argc, char *argv[]); -void parsetextconst(vlong arg); vlong rnd(vlong v, vlong r); /* Native is little-endian */ diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam deleted file mode 100644 index 3001dbe93..000000000 --- a/src/cmd/6l/mkenam +++ /dev/null @@ -1,45 +0,0 @@ -# Inferno utils/6c/mkenam -# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam -# -# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -# Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -# Portions Copyright © 1997-1999 Vita Nuova Limited -# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -# Portions Copyright © 2004,2006 Bruce Ellis -# Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -# Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -# Portions Copyright © 2009 The Go Authors. All rights reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -awk ' -BEGIN { - print "char* anames[] =" - print "{" -} - -/^ A/ { - name=$1 - sub(/,/, "", name) - sub(/^A/, "", name) - print "\t\"" name "\"," -} - -END { print "};" } -' ../6l/6.out.h >enam.c diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y index d7ff623da..6bcf1313b 100644 --- a/src/cmd/8a/a.y +++ b/src/cmd/8a/a.y @@ -33,7 +33,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" %} %union { Sym *sym; diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c index 32c099b75..6ce6a18ab 100644 --- a/src/cmd/8a/lex.c +++ b/src/cmd/8a/lex.c @@ -90,6 +90,7 @@ main(int argc, char *argv[]) ctxt = linknew(&link386); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit8(); fmtinstall('L', Lconv); @@ -352,49 +353,49 @@ struct "IRETL", LTYPE0, AIRETL, "IRETW", LTYPE0, AIRETW, - "JOS", LTYPER, AJOS, + "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */ "JO", LTYPER, AJOS, /* alternate */ - "JOC", LTYPER, AJOC, + "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */ "JNO", LTYPER, AJOC, /* alternate */ - "JCS", LTYPER, AJCS, + "JCS", LTYPER, AJCS, /* carry set (CF = 1) */ "JB", LTYPER, AJCS, /* alternate */ "JC", LTYPER, AJCS, /* alternate */ "JNAE", LTYPER, AJCS, /* alternate */ "JLO", LTYPER, AJCS, /* alternate */ - "JCC", LTYPER, AJCC, + "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */ "JAE", LTYPER, AJCC, /* alternate */ "JNB", LTYPER, AJCC, /* alternate */ "JNC", LTYPER, AJCC, /* alternate */ "JHS", LTYPER, AJCC, /* alternate */ - "JEQ", LTYPER, AJEQ, + "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */ "JE", LTYPER, AJEQ, /* alternate */ "JZ", LTYPER, AJEQ, /* alternate */ - "JNE", LTYPER, AJNE, + "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */ "JNZ", LTYPER, AJNE, /* alternate */ - "JLS", LTYPER, AJLS, + "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ "JBE", LTYPER, AJLS, /* alternate */ "JNA", LTYPER, AJLS, /* alternate */ - "JHI", LTYPER, AJHI, + "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */ "JA", LTYPER, AJHI, /* alternate */ "JNBE", LTYPER, AJHI, /* alternate */ - "JMI", LTYPER, AJMI, + "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */ "JS", LTYPER, AJMI, /* alternate */ - "JPL", LTYPER, AJPL, + "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */ "JNS", LTYPER, AJPL, /* alternate */ - "JPS", LTYPER, AJPS, + "JPS", LTYPER, AJPS, /* parity set (PF = 1) */ "JP", LTYPER, AJPS, /* alternate */ "JPE", LTYPER, AJPS, /* alternate */ - "JPC", LTYPER, AJPC, + "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */ "JNP", LTYPER, AJPC, /* alternate */ "JPO", LTYPER, AJPC, /* alternate */ - "JLT", LTYPER, AJLT, + "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */ "JL", LTYPER, AJLT, /* alternate */ "JNGE", LTYPER, AJLT, /* alternate */ - "JGE", LTYPER, AJGE, + "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */ "JNL", LTYPER, AJGE, /* alternate */ - "JLE", LTYPER, AJLE, + "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */ "JNG", LTYPER, AJLE, /* alternate */ - "JGT", LTYPER, AJGT, + "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */ "JG", LTYPER, AJGT, /* alternate */ "JNLE", LTYPER, AJGT, /* alternate */ @@ -493,7 +494,7 @@ struct "SCASB", LTYPE0, ASCASB, "SCASL", LTYPE0, ASCASL, "SCASW", LTYPE0, ASCASW, - "SETCC", LTYPE1, ASETCC, + "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */ "SETCS", LTYPE1, ASETCS, "SETEQ", LTYPE1, ASETEQ, "SETGE", LTYPE1, ASETGE, diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c index f48c9fe1f..85279c21f 100644 --- a/src/cmd/8a/y.tab.c +++ b/src/cmd/8a/y.tab.c @@ -146,7 +146,7 @@ #include /* if we don't, bison will, and a.h re-#defines getc */ #include #include "a.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" /* Enabling traces. */ diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c index f54102245..87e8fdad8 100644 --- a/src/cmd/8c/cgen.c +++ b/src/cmd/8c/cgen.c @@ -29,7 +29,7 @@ // THE SOFTWARE. #include "gc.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" /* ,x/^(print|prtree)\(/i/\/\/ */ @@ -49,7 +49,7 @@ cgen(Node *n, Node *nn) } if(n == Z || n->type == T) return; - if(typesuv[n->type->etype]) { + if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) { sugen(n, nn, n->type->width); return; } @@ -86,7 +86,7 @@ cgen(Node *n, Node *nn) if(cond(o) && typesuv[l->type->etype]) break; - regret(&nod, r); + regret(&nod, r, 0, 0); cgen(r, &nod); regsalloc(&nod1, r); @@ -147,7 +147,7 @@ cgen(Node *n, Node *nn) if(!hardleft) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) - regret(&nod, r); + regret(&nod, r, 0, 0); else regalloc(&nod, r, nn); cgen(r, &nod); @@ -922,7 +922,7 @@ cgen(Node *n, Node *nn) if(l->op != OIND) diag(n, "bad function call"); - regret(&nod, l->left); + regret(&nod, l->left, 0, 0); cgen(l->left, &nod); regsalloc(&nod1, l->left); gmove(&nod, &nod1); @@ -938,7 +938,6 @@ cgen(Node *n, Node *nn) return; } gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; @@ -946,15 +945,14 @@ cgen(Node *n, Node *nn) regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0 && reg[REGARG]) reg[REGARG]--; - if(nn != Z) { - regret(&nod, n); + regret(&nod, n, l->type, 1); // update maxarg if nothing else + if(nn != Z) gmove(&nod, nn); + if(nod.op == OREGISTER) regfree(&nod); - } else - if(typefd[n->type->etype]) + if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype]) gins(AFMOVDP, &fregnode0, &fregnode0); break; @@ -1374,7 +1372,7 @@ boolgen(Node *n, int true, Node *nn) if(true) o = comrel[relindex(o)]; if(l->complex >= FNX && r->complex >= FNX) { - regret(&nod, r); + regret(&nod, r, 0, 0); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); @@ -1567,7 +1565,7 @@ sugen(Node *n, Node *nn, int32 w) if(nn != Z && side(nn)) { nod1 = *n; nod1.type = typ(TIND, n->type); - regret(&nod2, &nod1); + regret(&nod2, &nod1, 0, 0); lcgen(nn, &nod2); regsalloc(&nod0, &nod1); cgen(&nod2, &nod0); @@ -1649,6 +1647,20 @@ sugen(Node *n, Node *nn, int32 w) break; case OFUNC: + if(!hasdotdotdot(n->left->type)) { + cgen(n, Z); + if(nn != Z) { + curarg -= n->type->width; + regret(&nod1, n, n->left->type, 1); + if(nn->complex >= FNX) { + regsalloc(&nod2, n); + cgen(&nod1, &nod2); + nod1 = nod2; + } + cgen(&nod1, nn); + } + break; + } if(nn == Z) { sugen(n, nodrat, w); break; diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h index 87b8e22bc..aa3888d73 100644 --- a/src/cmd/8c/gc.h +++ b/src/cmd/8c/gc.h @@ -143,7 +143,6 @@ EXTERN int32 cursafe; EXTERN Prog* lastp; EXTERN int32 maxargsafe; EXTERN int mnstring; -EXTERN int retok; EXTERN Node* nodrat; EXTERN Node* nodret; EXTERN Node* nodsafe; @@ -211,7 +210,7 @@ void xcom(Node*); void indx(Node*); int bcomplex(Node*, Node*); Prog* gtext(Sym*, int32); -vlong argsize(void); +vlong argsize(int); /* * cgen.c @@ -245,7 +244,7 @@ Node* nodconst(int32); Node* nodfconst(double); int nodreg(Node*, Node*, int); int isreg(Node*, int); -void regret(Node*, Node*); +void regret(Node*, Node*, Type*, int); void regalloc(Node*, Node*, Node*); void regfree(Node*); void regialloc(Node*, Node*, Node*); diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c index e6ba8bcb3..ea862f388 100644 --- a/src/cmd/8c/reg.c +++ b/src/cmd/8c/reg.c @@ -518,7 +518,7 @@ loop2: rgp->cost = change; nregion++; if(nregion >= NRGN) { - warn(Z, "too many regions"); + fatal(Z, "too many regions"); goto brk; } rgp++; @@ -746,11 +746,8 @@ mkvar(Reg *r, Addr *a) goto out; v++; } - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c index 069bbc1fc..d647010ef 100644 --- a/src/cmd/8c/sgen.c +++ b/src/cmd/8c/sgen.c @@ -35,7 +35,7 @@ gtext(Sym *s, int32 stkoff) { int32 a; - a = argsize(); + a = argsize(1); if((textflag & NOSPLIT) != 0 && stkoff >= 128) yyerror("stack frame too large for NOSPLIT function"); diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c index ae36f84ea..d960519e3 100644 --- a/src/cmd/8c/swt.c +++ b/src/cmd/8c/swt.c @@ -255,10 +255,11 @@ align(int32 i, Type *t, int op, int32 *maxalign) { int32 o; Type *v; - int w; + int w, packw; o = i; w = 1; + packw = 0; switch(op) { default: diag(Z, "unknown align opcode %d", op); @@ -269,7 +270,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1) w = 1; if(packflg) - w = packflg; + packw = packflg; break; case Ael1: /* initial align of struct element */ @@ -285,7 +286,7 @@ align(int32 i, Type *t, int op, int32 *maxalign) if(w < 1 || w > SZ_LONG) fatal(Z, "align"); if(packflg) - w = packflg; + packw = packflg; break; case Ael2: /* width of a struct element */ @@ -320,6 +321,8 @@ align(int32 i, Type *t, int op, int32 *maxalign) o = align(o, t, Ael2, nil); break; } + if(packw != 0 && xround(o, w) != xround(o, packw)) + diag(Z, "#pragma pack changes offset of %T", t); o = xround(o, w); if(maxalign && *maxalign < w) *maxalign = w; diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c index 25082de05..7f87a0a0d 100644 --- a/src/cmd/8c/txt.c +++ b/src/cmd/8c/txt.c @@ -311,15 +311,43 @@ nodreg(Node *n, Node *nn, int r) } void -regret(Node *n, Node *nn) +regret(Node *n, Node *nn, Type *t, int mode) { int r; - r = REGRET; - if(typefd[nn->type->etype]) - r = FREGRET; - nodreg(n, nn, r); - reg[r]++; + if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) { + r = REGRET; + if(typefd[nn->type->etype]) + r = FREGRET; + nodreg(n, nn, r); + reg[r]++; + return; + } + + if(mode == 1) { + // fetch returned value after call. + // already called gargs, so curarg is set. + curarg = (curarg+3) & ~3; + regaalloc(n, nn); + return; + } + + if(mode == 2) { + // store value to be returned. + // must compute arg offset. + if(t->etype != TFUNC) + fatal(Z, "bad regret func %T", t); + *n = *nn; + n->op = ONAME; + n->class = CPARAM; + n->sym = slookup(".retx"); + n->complex = 0; + n->addable = 20; + n->xoffset = argsize(0); + return; + } + + fatal(Z, "bad regret"); } void diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index d626c2eb0..2735fb6a5 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -242,7 +242,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { @@ -347,8 +346,11 @@ cgen(Node *n, Node *res) if(istype(nl->type, TCHAN)) { // chan has cap in the second 32-bit word. // a zero pointer means zero length - regalloc(&n1, types[tptr], res); + tempname(&n1, types[tptr]); cgen(nl, &n1); + regalloc(&n2, types[tptr], N); + gmove(&n1, &n2); + n1 = n2; nodconst(&n2, types[tptr], 0); gins(optoas(OCMP, types[tptr]), &n1, &n2); @@ -1324,7 +1326,7 @@ sgen(Node *n, Node *res, int64 w) p = gins(ADUFFCOPY, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); - // 10 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + // 10 and 128 = magic constants: see ../../runtime/asm_386.s p->to.offset = 10*(128-q); } else while(q > 0) { @@ -1364,7 +1366,10 @@ int componentgen(Node *nr, Node *nl) { Node nodl, nodr; + Type *t; int freel, freer; + vlong fldcount; + vlong loffset, roffset; freel = 0; freer = 0; @@ -1374,8 +1379,33 @@ componentgen(Node *nr, Node *nl) goto no; case TARRAY: - if(!isslice(nl->type)) + t = nl->type; + + // Slices are ok. + if(isslice(t)) + break; + // Small arrays are ok. + if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) + break; + + goto no; + + case TSTRUCT: + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + fldcount = 0; + for(t=nl->type->type; t; t=t->down) { + if(isfat(t->type)) + goto no; + if(t->etype != TFIELD) + fatal("componentgen: not a TFIELD: %lT", t); + fldcount++; + } + if(fldcount == 0 || fldcount > 4) goto no; + + break; + case TSTRING: case TINTER: break; @@ -1396,7 +1426,7 @@ componentgen(Node *nr, Node *nl) freer = 1; } } - + // nl and nr are 'cadable' which basically means they are names (variables) now. // If they are the same variable, don't generate any code, because the // VARDEF we generate will mark the old value as dead incorrectly. @@ -1406,8 +1436,25 @@ componentgen(Node *nr, Node *nl) switch(nl->type->etype) { case TARRAY: + // componentgen for arrays. if(nl->op == ONAME) gvardef(nl); + t = nl->type; + if(!isslice(t)) { + nodl.type = t->type; + nodr.type = nodl.type; + for(fldcount=0; fldcount < t->bound; fldcount++) { + if(nr == N) + clearslim(&nodl); + else + gmove(&nodr, &nodl); + nodl.xoffset += t->type->width; + nodr.xoffset += t->type->width; + } + goto yes; + } + + // componentgen for slices. nodl.xoffset += Array_array; nodl.type = ptrto(nl->type->type); @@ -1419,7 +1466,7 @@ componentgen(Node *nr, Node *nl) gmove(&nodr, &nodl); nodl.xoffset += Array_nel-Array_array; - nodl.type = types[TUINT32]; + nodl.type = types[simtype[TUINT]]; if(nr != N) { nodr.xoffset += Array_nel-Array_array; @@ -1429,7 +1476,7 @@ componentgen(Node *nr, Node *nl) gmove(&nodr, &nodl); nodl.xoffset += Array_cap-Array_nel; - nodl.type = types[TUINT32]; + nodl.type = types[simtype[TUINT]]; if(nr != N) { nodr.xoffset += Array_cap-Array_nel; @@ -1454,7 +1501,7 @@ componentgen(Node *nr, Node *nl) gmove(&nodr, &nodl); nodl.xoffset += Array_nel-Array_array; - nodl.type = types[TUINT32]; + nodl.type = types[simtype[TUINT]]; if(nr != N) { nodr.xoffset += Array_nel-Array_array; @@ -1489,6 +1536,31 @@ componentgen(Node *nr, Node *nl) gmove(&nodr, &nodl); goto yes; + + case TSTRUCT: + if(nl->op == ONAME) + gvardef(nl); + loffset = nodl.xoffset; + roffset = nodr.xoffset; + // funarg structs may not begin at offset zero. + if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) + loffset -= nl->type->type->width; + if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) + roffset -= nr->type->type->width; + + for(t=nl->type->type; t; t=t->down) { + nodl.xoffset = loffset + t->width; + nodl.type = t->type; + + if(nr == N) + clearslim(&nodl); + else { + nodr.xoffset = roffset + t->width; + nodr.type = nodl.type; + gmove(&nodr, &nodl); + } + } + goto yes; } no: diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c index fbd2e9ad3..a0eb34937 100644 --- a/src/cmd/8g/galign.c +++ b/src/cmd/8g/galign.c @@ -23,10 +23,10 @@ vlong MAXWIDTH = (1LL<<32) - 1; */ Typedef typedefs[] = { - "int", TINT, TINT32, - "uint", TUINT, TUINT32, - "uintptr", TUINTPTR, TUINT32, - 0 + {"int", TINT, TINT32}, + {"uint", TUINT, TUINT32}, + {"uintptr", TUINTPTR, TUINT32}, + {0} }; void diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h index bdefa93b5..238f92765 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -114,7 +114,6 @@ void split64(Node*, Node*, Node*); void splitclean(void); void nswap(Node*, Node*); void gtrack(Sym*); -void gargsize(int32); /* * cplx.c */ diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 5e3140480..6333a60bb 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -157,7 +157,7 @@ void clearfat(Node *nl) { uint32 w, c, q; - Node n1; + Node n1, z; Prog *p; /* clear a fat object */ @@ -172,6 +172,32 @@ clearfat(Node *nl) c = w % 4; // bytes q = w / 4; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSL. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSL loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + regalloc(&n1, types[tptr], N); + agen(nl, &n1); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + nodreg(&n1, types[tptr], D_DI); agen(nl, &n1); gconreg(AMOVL, 0, D_AX); @@ -184,7 +210,7 @@ clearfat(Node *nl) p = gins(ADUFFZERO, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - // 1 and 128 = magic constants: see ../../pkg/runtime/asm_386.s + // 1 and 128 = magic constants: see ../../runtime/asm_386.s p->to.offset = 1*(128-q); } else while(q > 0) { @@ -210,28 +236,12 @@ clearfat(Node *nl) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node reg, r1, con; if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 2*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -293,9 +303,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 2f3cb28c8..3077e0ad9 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -31,14 +31,15 @@ #include #include #include "gg.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" // TODO(rsc): Can make this bigger if we move // the text segment up higher in 8l for all GOOS. -// At the same time, can raise StackBig in ../../pkg/runtime/stack.h. +// At the same time, can raise StackBig in ../../runtime/stack.h. uint32 unmappedzero = 4096; #define CASE(a,b) (((a)<<16)|((b)<<0)) +/*c2go int CASE(int, int);*/ void clearp(Prog *p) @@ -205,17 +206,7 @@ ggloblnod(Node *nam) } void -gargsize(int32 size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - -void -ggloblsym(Sym *s, int32 width, int dupok, int rodata) +ggloblsym(Sym *s, int32 width, int8 flags) { Prog *p; @@ -226,10 +217,7 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata) p->to.type = D_CONST; p->to.index = D_NONE; p->to.offset = width; - if(dupok) - p->from.scale |= DUPOK; - if(rodata) - p->from.scale |= RODATA; + p->from.scale = flags; } void @@ -432,7 +420,6 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADDL; break; @@ -697,6 +684,7 @@ optoas(int op, Type *t) } #define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c)) +/*c2go int FCASE(int, int, int); */ int foptoas(int op, Type *t, int flg) { @@ -950,7 +938,7 @@ regalloc(Node *n, Type *t, Node *o) fprint(2, "registers allocated at\n"); for(i=D_AX; i<=D_DI; i++) fprint(2, "\t%R\t%#lux\n", i, regpc[i]); - yyerror("out of fixed registers"); + fatal("out of fixed registers"); goto err; case TFLOAT32: diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h index 77a69e13a..09f58c40a 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -49,6 +49,24 @@ typedef struct Reg Reg; typedef struct Rgn Rgn; +/*c2go +extern Node *Z; +enum +{ + D_HI = D_NONE, + D_LO = D_NONE, + CLOAD = 5, + CREF = 5, + CINF = 1000, + LOOP = 3, +}; + +uint32 BLOAD(Reg*); +uint32 BSTORE(Reg*); +uint32 LOAD(Reg*); +uint32 STORE(Reg*); +*/ + // A Reg is a wrapper around a single Prog (one instruction) that holds // register optimization information while the optimizer runs. // r->prog is the instruction. @@ -84,8 +102,10 @@ struct Reg Prog* prog; // actual instruction }; #define R ((Reg*)0) +/*c2go extern Reg *R; */ #define NRGN 600 +/*c2go enum { NRGN = 600 }; */ struct Rgn { Reg* enter; diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index e2f3a003d..91a91d20d 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -33,7 +33,9 @@ #include "gg.h" #include "opt.h" -#define REGEXT 0 +enum { + REGEXT = 0, +}; static void conprop(Flow *r); static void elimshortmov(Graph*); diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index fd610f87a..302b273a1 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -35,6 +35,11 @@ #define NREGVAR 16 /* 8 integer + 8 floating */ #define REGBITS ((uint32)0xffff) +/*c2go enum { + NREGVAR = 16, + REGBITS = (1<sym = nil; + a->node = nil; a->offset = 0; a->type = rn; diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index 8e642d390..ed54f6744 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -32,7 +32,7 @@ #define NSNAME 8 #include "../ld/textflag.h" -enum as +enum { AXXX, AAAA, diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index c135dce70..98c042403 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -117,13 +117,21 @@ adddynrel(LSym *s, Reloc *r) case 256 + R_386_GOT32: if(targ->type != SDYNIMPORT) { // have symbol - // turn MOVL of GOT entry into LEAL of symbol itself - if(r->off < 2 || s->p[r->off-2] != 0x8b) { - diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + if(r->off >= 2 && s->p[r->off-2] == 0x8b) { + // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. + s->p[r->off-2] = 0x8d; + r->type = R_GOTOFF; return; } - s->p[r->off-2] = 0x8d; - r->type = R_GOTOFF; + if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) { + // turn PUSHL of GOT entry into PUSHL of symbol itself. + // use unnecessary SS prefix to keep instruction same length. + s->p[r->off-2] = 0x36; + s->p[r->off-1] = 0x68; + r->type = R_ADDR; + return; + } + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } addgotsym(ctxt, targ); diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index c9695ade0..70d3a4bb4 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -50,15 +50,10 @@ enum #define P ((Prog*)0) #define S ((LSym*)0) -#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) enum { - MINSIZ = 4, - STRINGSZ = 200, MINLC = 1, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ }; #pragma varargck type "I" uchar* @@ -72,7 +67,6 @@ EXTERN char* rpath; EXTERN int32 spsize; EXTERN LSym* symlist; EXTERN int32 symsize; -EXTERN int32 textsize; int Iconv(Fmt *fp); void adddynlib(char *lib); @@ -85,7 +79,6 @@ int elfreloc1(Reloc *r, vlong sectoff); void elfsetupplt(void); void listinit(void); int machoreloc1(Reloc *r, vlong sectoff); -void main(int argc, char *argv[]); int32 rnd(int32 v, int32 r); void s8put(char *n); char* xsymname(LSym *s); diff --git a/src/cmd/8l/mkenam b/src/cmd/8l/mkenam deleted file mode 100644 index 992aa3160..000000000 --- a/src/cmd/8l/mkenam +++ /dev/null @@ -1,45 +0,0 @@ -# Inferno utils/8c/mkenam -# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam -# -# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -# Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -# Portions Copyright © 1997-1999 Vita Nuova Limited -# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -# Portions Copyright © 2004,2006 Bruce Ellis -# Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -# Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -# Portions Copyright © 2009 The Go Authors. All rights reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -awk ' -BEGIN { - print "char* anames[] =" - print "{" -} - -/^ A/ { - name=$1 - sub(/,/, "", name) - sub(/^A/, "", name) - print "\t\"" name "\"," -} - -END { print "};" } -' ../8l/8.out.h >enam.c diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go index b278d08ce..10d1dc922 100644 --- a/src/cmd/addr2line/addr2line_test.go +++ b/src/cmd/addr2line/addr2line_test.go @@ -92,8 +92,9 @@ func testAddr2Line(t *testing.T, exepath, addr string) { // This is line 93. The test depends on that. func TestAddr2Line(t *testing.T) { - if runtime.GOOS == "nacl" { - t.Skip("skipping on nacl") + switch runtime.GOOS { + case "nacl", "android": + t.Skipf("skipping on %s", runtime.GOOS) } syms := loadSyms(t) diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go index b94ba12ef..267f4170a 100644 --- a/src/cmd/addr2line/main.go +++ b/src/cmd/addr2line/main.go @@ -19,17 +19,14 @@ package main import ( "bufio" - "debug/elf" - "debug/gosym" - "debug/macho" - "debug/pe" - "debug/plan9obj" "flag" "fmt" "log" "os" "strconv" "strings" + + "cmd/internal/objfile" ) func printUsage(w *os.File) { @@ -60,18 +57,12 @@ func main() { usage() } - f, err := os.Open(flag.Arg(0)) + f, err := objfile.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } - textStart, symtab, pclntab, err := loadTables(f) - if err != nil { - log.Fatalf("reading %s: %v", flag.Arg(0), err) - } - - pcln := gosym.NewLineTable(pclntab, textStart) - tab, err := gosym.NewTable(symtab, pcln) + tab, err := f.PCLineTable() if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } @@ -102,152 +93,3 @@ func main() { } stdout.Flush() } - -func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) { - if obj, err := elf.NewFile(f); err == nil { - if sect := obj.Section(".text"); sect != nil { - textStart = sect.Addr - } - if sect := obj.Section(".gosymtab"); sect != nil { - if symtab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - if sect := obj.Section(".gopclntab"); sect != nil { - if pclntab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - return textStart, symtab, pclntab, nil - } - - if obj, err := macho.NewFile(f); err == nil { - if sect := obj.Section("__text"); sect != nil { - textStart = sect.Addr - } - if sect := obj.Section("__gosymtab"); sect != nil { - if symtab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - if sect := obj.Section("__gopclntab"); sect != nil { - if pclntab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - return textStart, symtab, pclntab, nil - } - - if obj, err := pe.NewFile(f); err == nil { - var imageBase uint64 - switch oh := obj.OptionalHeader.(type) { - case *pe.OptionalHeader32: - imageBase = uint64(oh.ImageBase) - case *pe.OptionalHeader64: - imageBase = oh.ImageBase - default: - return 0, nil, nil, fmt.Errorf("pe file format not recognized") - } - if sect := obj.Section(".text"); sect != nil { - textStart = imageBase + uint64(sect.VirtualAddress) - } - if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil { - return 0, nil, nil, err - } - if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil { - return 0, nil, nil, err - } - return textStart, symtab, pclntab, nil - } - - if obj, err := plan9obj.NewFile(f); err == nil { - sym, err := findPlan9Symbol(obj, "text") - if err != nil { - return 0, nil, nil, err - } - textStart = sym.Value - if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil { - return 0, nil, nil, err - } - if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil { - return 0, nil, nil, err - } - return textStart, symtab, pclntab, nil - } - - return 0, nil, nil, fmt.Errorf("unrecognized binary format") -} - -func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { - for _, s := range f.Symbols { - if s.Name != name { - continue - } - if s.SectionNumber <= 0 { - return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) - } - if len(f.Sections) < int(s.SectionNumber) { - return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) - } - return s, nil - } - return nil, fmt.Errorf("no %s symbol found", name) -} - -func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { - ssym, err := findPESymbol(f, sname) - if err != nil { - return nil, err - } - esym, err := findPESymbol(f, ename) - if err != nil { - return nil, err - } - if ssym.SectionNumber != esym.SectionNumber { - return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) - } - sect := f.Sections[ssym.SectionNumber-1] - data, err := sect.Data() - if err != nil { - return nil, err - } - return data[ssym.Value:esym.Value], nil -} - -func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { - syms, err := f.Symbols() - if err != nil { - return nil, err - } - for _, s := range syms { - if s.Name != name { - continue - } - return &s, nil - } - return nil, fmt.Errorf("no %s symbol found", name) -} - -func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { - ssym, err := findPlan9Symbol(f, sname) - if err != nil { - return nil, err - } - esym, err := findPlan9Symbol(f, ename) - if err != nil { - return nil, err - } - text, err := findPlan9Symbol(f, "text") - if err != nil { - return nil, err - } - sect := f.Section("text") - if sect == nil { - return nil, err - } - data, err := sect.Data() - if err != nil { - return nil, err - } - return data[ssym.Value-text.Value : esym.Value-text.Value], nil -} diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 4bde794a1..4a63eac71 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -107,6 +107,8 @@ func setContexts() { } } +var internalPkg = regexp.MustCompile(`(^|/)internal($|/)`) + func main() { flag.Parse() @@ -132,12 +134,16 @@ func main() { if err != nil { log.Fatal(err) } - pkgNames = strings.Fields(string(stds)) + for _, pkg := range strings.Fields(string(stds)) { + if !internalPkg.MatchString(pkg) { + pkgNames = append(pkgNames, pkg) + } + } } var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true for _, context := range contexts { - w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src/pkg")) + w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) for _, name := range pkgNames { // - Package "unsafe" contains special signatures requiring @@ -277,7 +283,7 @@ func compareAPI(w io.Writer, features, required, optional, exception []string) ( delete(optionalSet, newFeature) } else { fmt.Fprintf(w, "+%s\n", newFeature) - if !*allowNew { + if !*allowNew || !strings.Contains(runtime.Version(), "devel") { ok = false // we're in lock-down mode for next release } } @@ -307,11 +313,15 @@ func fileFeatures(filename string) []string { if err != nil { log.Fatalf("Error reading file %s: %v", filename, err) } - text := strings.TrimSpace(string(bs)) - if text == "" { - return nil + lines := strings.Split(string(bs), "\n") + var nonblank []string + for _, line := range lines { + line = strings.TrimSpace(line) + if line != "" && !strings.HasPrefix(line, "#") { + nonblank = append(nonblank, line) + } } - return strings.Split(text, "\n") + return nonblank } var fset = token.NewFileSet() @@ -370,6 +380,106 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { log.Fatalf("incorrect generated file: %s", err) } } + if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { + // Just enough to keep the api checker happy. Keep sorted. + src := "package runtime; type (" + + " _defer struct{};" + + " _func struct{};" + + " _panic struct{};" + + " _select struct{}; " + + " _type struct{};" + + " alg struct{};" + + " chantype struct{};" + + " context struct{};" + // windows + " eface struct{};" + + " epollevent struct{};" + + " funcval struct{};" + + " g struct{};" + + " gobuf struct{};" + + " hchan struct{};" + + " iface struct{};" + + " interfacetype struct{};" + + " itab struct{};" + + " keventt struct{};" + + " m struct{};" + + " maptype struct{};" + + " mcache struct{};" + + " mspan struct{};" + + " mutex struct{};" + + " note struct{};" + + " p struct{};" + + " parfor struct{};" + + " slicetype struct{};" + + " stkframe struct{};" + + " sudog struct{};" + + " timespec struct{};" + + " waitq struct{};" + + " wincallbackcontext struct{};" + + "); " + + "const (" + + " cb_max = 2000;" + + " _CacheLineSize = 64;" + + " _Gidle = 1;" + + " _Grunnable = 2;" + + " _Grunning = 3;" + + " _Gsyscall = 4;" + + " _Gwaiting = 5;" + + " _Gdead = 6;" + + " _Genqueue = 7;" + + " _Gcopystack = 8;" + + " _NSIG = 32;" + + " _FlagNoScan = iota;" + + " _FlagNoZero;" + + " _TinySize;" + + " _TinySizeClass;" + + " _MaxSmallSize;" + + " _PageShift;" + + " _PageSize;" + + " _PageMask;" + + " _BitsPerPointer;" + + " _BitsMask;" + + " _PointersPerByte;" + + " _MaxGCMask;" + + " _BitsDead;" + + " _BitsPointer;" + + " _MSpanInUse;" + + " _ConcurrentSweep;" + + " _KindBool;" + + " _KindInt;" + + " _KindInt8;" + + " _KindInt16;" + + " _KindInt32;" + + " _KindInt64;" + + " _KindUint;" + + " _KindUint8;" + + " _KindUint16;" + + " _KindUint32;" + + " _KindUint64;" + + " _KindUintptr;" + + " _KindFloat32;" + + " _KindFloat64;" + + " _KindComplex64;" + + " _KindComplex128;" + + " _KindArray;" + + " _KindChan;" + + " _KindFunc;" + + " _KindInterface;" + + " _KindMap;" + + " _KindPtr;" + + " _KindSlice;" + + " _KindString;" + + " _KindStruct;" + + " _KindUnsafePointer;" + + " _KindDirectIface;" + + " _KindGCProg;" + + " _KindNoPointers;" + + " _KindMask;" + + ")" + f, err = parser.ParseFile(fset, filename, src, 0) + if err != nil { + log.Fatalf("incorrect generated file: %s", err) + } + } if f == nil { f, err = parser.ParseFile(fset, filename, nil, 0) @@ -391,6 +501,11 @@ func contains(list []string, s string) bool { return false } +// The package cache doesn't operate correctly in rare (so far artificial) +// circumstances (issue 8425). Disable before debugging non-obvious errors +// from the type-checker. +const usePkgCache = true + var ( pkgCache = map[string]*types.Package{} // map tagKey to package pkgTags = map[string][]string{} // map import dir to list of relevant tags @@ -452,11 +567,13 @@ func (w *Walker) Import(name string) (pkg *types.Package) { // If we've already done an import with the same set // of relevant tags, reuse the result. var key string - if tags, ok := pkgTags[dir]; ok { - key = tagKey(dir, context, tags) - if pkg := pkgCache[key]; pkg != nil { - w.imported[name] = pkg - return pkg + if usePkgCache { + if tags, ok := pkgTags[dir]; ok { + key = tagKey(dir, context, tags) + if pkg := pkgCache[key]; pkg != nil { + w.imported[name] = pkg + return pkg + } } } @@ -469,9 +586,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) { } // Save tags list first time we see a directory. - if _, ok := pkgTags[dir]; !ok { - pkgTags[dir] = info.AllTags - key = tagKey(dir, context, info.AllTags) + if usePkgCache { + if _, ok := pkgTags[dir]; !ok { + pkgTags[dir] = info.AllTags + key = tagKey(dir, context, info.AllTags) + } } filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...) @@ -488,6 +607,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) { if !contains(filenames, n) { filenames = append(filenames, n) } + + n = fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) + if !contains(filenames, n) { + filenames = append(filenames, n) + } } // Parse package files. @@ -519,7 +643,9 @@ func (w *Walker) Import(name string) (pkg *types.Package) { log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt) } - pkgCache[key] = pkg + if usePkgCache { + pkgCache[key] = pkg + } w.imported[name] = pkg return diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go index b909c32b3..f4fb7d319 100644 --- a/src/cmd/api/goapi_test.go +++ b/src/cmd/api/goapi_test.go @@ -38,7 +38,7 @@ func TestGolden(t *testing.T) { continue } - goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt") + goldenFile := filepath.Join("testdata", "src", fi.Name(), "golden.txt") w := NewWalker(nil, "testdata/src/pkg") w.export(w.Import(fi.Name())) @@ -142,6 +142,26 @@ func TestCompareAPI(t *testing.T) { } } +func TestSkipInternal(t *testing.T) { + tests := []struct { + pkg string + want bool + }{ + {"net/http", true}, + {"net/http/internal-foo", true}, + {"net/http/internal", false}, + {"net/http/internal/bar", false}, + {"internal/foo", false}, + {"internal", false}, + } + for _, tt := range tests { + got := !internalPkg.MatchString(tt.pkg) + if got != tt.want { + t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want) + } + } +} + func BenchmarkAll(b *testing.B) { stds, err := exec.Command("go", "list", "std").Output() if err != nil { @@ -156,7 +176,7 @@ func BenchmarkAll(b *testing.B) { for i := 0; i < b.N; i++ { for _, context := range contexts { - w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src/pkg")) + w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) for _, name := range pkgNames { if name != "unsafe" && !strings.HasPrefix(name, "cmd/") { w.export(w.Import(name)) diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index 896b2b4a1..ed5613edd 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -21,6 +21,7 @@ import ( "os/exec" "os/user" "path/filepath" + "runtime" "strings" ) @@ -53,7 +54,7 @@ func main() { } out, err = exec.Command("go", "tool", "api", - "-c", file("go1", "go1.1", "go1.2", "go1.3"), + "-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"), "-next", file("next"), "-except", file("except")).CombinedOutput() if err != nil { @@ -98,16 +99,14 @@ func prepGoPath() string { if err == nil { username = u.Username } else { - // Only need to handle Unix here, as Windows's os/user uses - // native syscall and should work fine without cgo. username = os.Getenv("USER") if username == "" { - log.Fatalf("Error getting current user: %v", err) + username = "nobody" } } // The GOPATH we'll return - gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username), goToolsVersion) + gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion) // cloneDir is where we run "hg clone". cloneDir := filepath.Join(gopath, "src", "code.google.com", "p") diff --git a/src/cmd/cc/bv.c b/src/cmd/cc/bv.c deleted file mode 100644 index 51b7f4076..000000000 --- a/src/cmd/cc/bv.c +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 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. - -#include -#include "cc.h" - -enum { - WORDSIZE = sizeof(uint32), - WORDBITS = 32, -}; - -uintptr -bvsize(uintptr n) -{ - return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE; -} - -Bvec* -bvalloc(int32 n) -{ - Bvec *bv; - uintptr nbytes; - - if(n < 0) - fatal(Z, "bvalloc: initial size is negative\n"); - nbytes = sizeof(Bvec) + bvsize(n); - bv = malloc(nbytes); - if(bv == nil) - fatal(Z, "bvalloc: malloc failed\n"); - memset(bv, 0, nbytes); - bv->n = n; - return bv; -} - -void -bvset(Bvec *bv, int32 i) -{ - uint32 mask; - - if(i < 0 || i >= bv->n) - fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1 << (i % WORDBITS); - bv->b[i / WORDBITS] |= mask; -} diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index c8aac1253..9530f5cf6 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -761,12 +761,6 @@ Bits blsh(uint); int beq(Bits, Bits); int bset(Bits, uint); -/* - * bv.c - */ -Bvec* bvalloc(int32 n); -void bvset(Bvec *bv, int32 i); - /* * dpchk.c */ @@ -794,7 +788,7 @@ void xcom(Node*); int32 exreg(Type*); int32 align(int32, Type*, int, int32*); int32 maxround(int32, int32); -int hasdotdotdot(void); +int hasdotdotdot(Type*); void linkarchinit(void); extern schar ewidth[]; diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y index 11ee444b7..8d7cb1472 100644 --- a/src/cmd/cc/cc.y +++ b/src/cmd/cc/cc.y @@ -1043,6 +1043,7 @@ complex: } | LSTRUCT sbody { + diag(Z, "struct must have tag"); taggen++; sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TSTRUCT, autobn); diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index a7a942686..117508fd6 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -30,6 +30,9 @@ #include #include "cc.h" +#include "../ld/textflag.h" + +static int haspointers(Type*); Node* dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) @@ -123,7 +126,8 @@ loop: if(dataflag) { s->dataflag = dataflag; dataflag = 0; - } + } else if(s->type != T && !haspointers(s->type)) + s->dataflag = NOPTR; firstbit = 0; n->sym = s; n->type = s->type; @@ -568,9 +572,8 @@ haspointers(Type *t) return 0; case TARRAY: return haspointers(t->link); - case TFUNC: case TIND: - return 1; + return t->link->etype != TFUNC; default: return 0; } @@ -697,7 +700,8 @@ argmark(Node *n, int pass) { Type *t; - autoffset = align(0, thisfn->link, Aarg0, nil); + if(hasdotdotdot(thisfn->link)) + autoffset = align(0, thisfn->link, Aarg0, nil); stkoff = 0; for(; n->left != Z; n = n->left) { if(n->op != OFUNC || n->left->op != ONAME) @@ -1401,6 +1405,10 @@ xdecl(int c, Type *t, Sym *s) } tmerge(t, s); s->type = t; + if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) { + s->type = copytyp(t); + s->type->tag = s; + } s->class = c; s->block = 0; s->offset = o; @@ -1481,12 +1489,9 @@ edecl(int c, Type *t, Sym *s) { Type *t1; - if(s == S) { - if(!typesu[t->etype]) - diag(Z, "unnamed structure element must be struct/union"); - if(c != CXXX) - diag(Z, "unnamed structure element cannot have class"); - } else + if(s == S) + diag(Z, "unnamed structure elements not supported"); + else if(c != CXXX) diag(Z, "structure element cannot have class: %s", s->name); t1 = t; diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c index 7457bd000..d9f67f0ae 100644 --- a/src/cmd/cc/godefs.c +++ b/src/cmd/cc/godefs.c @@ -154,7 +154,6 @@ static void printtypename(Type *t) { Sym *s; - Type *t1; int w; char *n; @@ -188,40 +187,27 @@ printtypename(Type *t) switch(t->etype) { case TINT: - Bprint(&outbuf, "int32"); - break; case TUINT: - Bprint(&outbuf, "uint32"); - break; case TCHAR: - Bprint(&outbuf, "int8"); - break; case TUCHAR: - Bprint(&outbuf, "uint8"); - break; case TSHORT: - Bprint(&outbuf, "int16"); - break; case TUSHORT: - Bprint(&outbuf, "uint16"); - break; case TLONG: - Bprint(&outbuf, "int32"); - break; case TULONG: - Bprint(&outbuf, "uint32"); - break; case TVLONG: - Bprint(&outbuf, "int64"); - break; case TUVLONG: - Bprint(&outbuf, "uint64"); - break; case TFLOAT: - Bprint(&outbuf, "float32"); - break; case TDOUBLE: - Bprint(&outbuf, "float64"); + // All names used in the runtime code should be typedefs. + if(t->tag != nil) { + if(strcmp(t->tag->name, "intgo") == 0) + Bprint(&outbuf, "int"); + else if(strcmp(t->tag->name, "uintgo") == 0) + Bprint(&outbuf, "uint"); + else + Bprint(&outbuf, "%s", t->tag->name); + } else + Bprint(&outbuf, "C.%T", t); break; case TUNION: case TSTRUCT: @@ -231,27 +217,18 @@ printtypename(Type *t) n = s->name; else if(t->tag) n = t->tag->name; - if(strcmp(n, "String") == 0){ + if(strcmp(n, "String") == 0) Bprint(&outbuf, "string"); - } else if(strcmp(n, "Slice") == 0){ + else if(strcmp(n, "Slice") == 0) Bprint(&outbuf, "[]byte"); - } else + else if(strcmp(n, "Eface") == 0) + Bprint(&outbuf, "interface{}"); + else Bprint(&outbuf, "%U", n); break; case TFUNC: - Bprint(&outbuf, "func("); - for(t1 = t->down; t1 != T; t1 = t1->down) { - if(t1->etype == TVOID) - break; - if(t1 != t->down) - Bprint(&outbuf, ", "); - printtypename(t1); - } - Bprint(&outbuf, ")"); - if(t->link && t->link->etype != TVOID) { - Bprint(&outbuf, " "); - printtypename(t->link); - } + // There's no equivalent to a C function in the Go world. + Bprint(&outbuf, "unsafe.Pointer"); break; case TDOT: Bprint(&outbuf, "...interface{}"); @@ -340,9 +317,9 @@ godefvar(Sym *s) switch(t->etype) { case TENUM: if(!typefd[t->etype]) - Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst); + Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst); else - Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst); + Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst); break; case TFUNC: @@ -376,8 +353,10 @@ godefvar(Sym *s) case CSTATIC: case CEXTERN: case CGLOBL: - if(strchr(s->name, '$') != nil) // TODO(lvd) - break; + if(strchr(s->name, '$') != nil) + break; + if(strncmp(s->name, "go.weak.", 8) == 0) + break; Bprint(&outbuf, "var %U\t", s->name); printtypename(t); Bprint(&outbuf, "\n"); diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c index 424843764..7c9f718c0 100644 --- a/src/cmd/cc/lex.c +++ b/src/cmd/cc/lex.c @@ -31,6 +31,7 @@ #include #include "cc.h" #include "y.tab.h" +#include "../ld/textflag.h" #ifndef CPP #define CPP "cpp" @@ -203,6 +204,7 @@ main(int argc, char *argv[]) flagparse(&argc, &argv, usage); ctxt->debugasm = debug['S']; + ctxt->debugvlog = debug['v']; if(argc < 1 && outfile == 0) usage(); @@ -1316,6 +1318,7 @@ cinit(void) t->width = 0; symstring = slookup(".string"); symstring->class = CSTATIC; + symstring->dataflag = NOPTR; symstring->type = t; t = typ(TARRAY, types[TCHAR]); diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 10bebc196..db9aae916 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -29,51 +29,27 @@ // THE SOFTWARE. #include "gc.h" -#include "../../pkg/runtime/funcdata.h" - -enum { BitsPerPointer = 2 }; - -static void dumpgcargs(Type *fn, Sym *sym); - -static Sym* -makefuncdatasym(char *namefmt, int64 funcdatakind) -{ - Node nod; - Sym *sym; - static int32 nsym; - static char namebuf[40]; - - snprint(namebuf, sizeof(namebuf), namefmt, nsym++); - sym = slookup(namebuf); - sym->class = CSTATIC; - memset(&nod, 0, sizeof nod); - nod.op = ONAME; - nod.sym = sym; - nod.class = CSTATIC; - gins(AFUNCDATA, nodconst(funcdatakind), &nod); - linksym(sym)->type = SRODATA; - return sym; -} +#include "../../runtime/funcdata.h" int -hasdotdotdot(void) +hasdotdotdot(Type *t) { - Type *t; - - for(t=thisfn->down; t!=T; t=t->down) + for(t=t->down; t!=T; t=t->down) if(t->etype == TDOT) return 1; return 0; } vlong -argsize(void) +argsize(int doret) { Type *t; int32 s; //print("t=%T\n", thisfn); - s = align(0, thisfn->link, Aarg0, nil); + s = 0; + if(hasdotdotdot(thisfn)) + s = align(s, thisfn->link, Aarg0, nil); for(t=thisfn->down; t!=T; t=t->down) { switch(t->etype) { case TVOID: @@ -93,6 +69,14 @@ argsize(void) s = (s+7) & ~7; else s = (s+3) & ~3; + if(doret && thisfn->link->etype != TVOID) { + s = align(s, thisfn->link, Aarg1, nil); + s = align(s, thisfn->link, Aarg2, nil); + if(thechar == '6') + s = (s+7) & ~7; + else + s = (s+3) & ~3; + } return s; } @@ -101,9 +85,6 @@ codgen(Node *n, Node *nn) { Prog *sp; Node *n1, nod, nod1; - Sym *gcargs; - Sym *gclocals; - int isvarargs; cursafe = 0; curarg = 0; @@ -123,18 +104,9 @@ codgen(Node *n, Node *nn) nearln = nn->lineno; p = gtext(n1->sym, stkoff); + p->from.sym->cfunc = 1; sp = p; - /* - * generate funcdata symbol for this function. - * data is filled in at the end of codgen(). - */ - isvarargs = hasdotdotdot(); - gcargs = nil; - if(!isvarargs) - gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); - gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); - /* * isolate first argument */ @@ -155,8 +127,6 @@ codgen(Node *n, Node *nn) } } - retok = 0; - canreach = 1; warnreach = 1; gen(n); @@ -171,22 +141,6 @@ codgen(Node *n, Node *nn) if(thechar=='6' || thechar=='7') /* [sic] */ maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; - - if(!isvarargs) - dumpgcargs(thisfn, gcargs); - - // TODO(rsc): "stkoff" is not right. It does not account for - // the possibility of data stored in .safe variables. - // Unfortunately those move up and down just like - // the argument frame (and in fact dovetail with it) - // so the number we need is not available or even - // well-defined. Probably we need to make the safe - // area its own section. - // That said, we've been using stkoff for months - // and nothing too terrible has happened. - gextern(gclocals, nodconst(-stkoff), 0, 4); // locals - gclocals->type = typ(0, T); - gclocals->type->width = 4; } void @@ -214,7 +168,7 @@ supgen(Node *n) void gen(Node *n) { - Node *l, nod; + Node *l, nod, nod1; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; @@ -275,14 +229,26 @@ loop: gbranch(ORETURN); break; } + if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) { + regret(&nod, n, thisfn, 2); + sugen(l, &nod, n->type->width); + noretval(3); + gbranch(ORETURN); + break; + } if(typecmplx[n->type->etype]) { sugen(l, nodret, n->type->width); noretval(3); gbranch(ORETURN); break; } - regret(&nod, n); + regret(&nod1, n, thisfn, 2); + nod = nod1; + if(nod.op != OREGISTER) + regalloc(&nod, n, Z); cgen(l, &nod); + if(nod1.op != OREGISTER) + gmove(&nod, &nod1); regfree(&nod); if(typefd[n->type->etype]) noretval(1); @@ -654,111 +620,3 @@ bcomplex(Node *n, Node *c) boolgen(n, 1, Z); return 0; } - -// Updates the bitvector with a set bit for each pointer containing -// value in the type description starting at offset. -static void -walktype1(Type *t, int32 offset, Bvec *bv, int param) -{ - Type *t1; - int32 o; - int32 widthptr; - - widthptr = ewidth[TIND]; - switch(t->etype) { - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TFLOAT: - case TDOUBLE: - // non-pointer types - for(o = 0; o < t->width; o++) - bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar - break; - - case TIND: - pointer: - // pointer types - if((offset + t->offset) % widthptr != 0) - yyerror("unaligned pointer"); - bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr - break; - - case TARRAY: - if(param) // unlike Go, C passes arrays by reference - goto pointer; - // array in struct or union is an actual array - for(o = 0; o < t->width; o += t->link->width) - walktype1(t->link, offset+o, bv, 0); - break; - - case TSTRUCT: - // build map recursively - for(t1 = t->link; t1 != T; t1 = t1->down) - walktype1(t1, offset, bv, 0); - break; - - case TUNION: - walktype1(t->link, offset, bv, 0); - break; - - default: - yyerror("can't handle arg type %s\n", tnames[t->etype]); - } -} - -// Compute a bit vector to describe the pointer containing locations -// in the argument list. Adds the data to gcsym and returns the offset -// of end of the bit vector. -static void -dumpgcargs(Type *fn, Sym *sym) -{ - Bvec *bv; - Type *t; - int32 i; - int32 argbytes; - int32 symoffset, argoffset; - - // Dump the length of the bitmap array. This value is always one for - // functions written in C. - symoffset = 0; - gextern(sym, nodconst(1), symoffset, 4); - symoffset += 4; - argbytes = (argsize() + ewidth[TIND] - 1); - bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); - argoffset = align(0, fn->link, Aarg0, nil); - if(argoffset > 0) { - // The C calling convention returns structs by copying them to a - // location pointed to by a hidden first argument. This first - // argument is a pointer. - if(argoffset != ewidth[TIND]) - yyerror("passbyptr arg not the right size"); - bvset(bv, 1); // 2 = live ptr - } - for(t = fn->down; t != T; t = t->down) { - if(t->etype == TVOID) - continue; - argoffset = align(argoffset, t, Aarg1, nil); - walktype1(t, argoffset, bv, 1); - argoffset = align(argoffset, t, Aarg2, nil); - } - // Dump the length of the bitmap. - gextern(sym, nodconst(bv->n), symoffset, 4); - symoffset += 4; - // Dump the words of the bitmap. - for(i = 0; i < bv->n; i += 32) { - gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); - symoffset += 4; - } - free(bv); - // Finalize the gc symbol. - sym->type = typ(0, T); - sym->type->width = symoffset; -} diff --git a/src/cmd/cc/y.tab.c b/src/cmd/cc/y.tab.c index 8588515ab..94932efe5 100644 --- a/src/cmd/cc/y.tab.c +++ b/src/cmd/cc/y.tab.c @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.7.12-4996. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,7 +29,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +47,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.7.12-4996" +#define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -52,53 +55,10 @@ /* Pure parsers. */ #define YYPURE 0 -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - - - -/* Copy the first part of user declarations. */ -/* Line 371 of yacc.c */ -#line 31 "cc.y" - -#include -#include /* if we don't, bison will, and cc.h re-#defines getc */ -#include "cc.h" +/* Using locations. */ +#define YYLSP_NEEDED 0 -/* Line 371 of yacc.c */ -#line 74 "y.tab.c" -# ifndef YY_NULL -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULL nullptr -# else -# define YY_NULL 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "y.tab.h". */ -#ifndef YY_YY_Y_TAB_H_INCLUDED -# define YY_YY_Y_TAB_H_INCLUDED -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif /* Tokens. */ #ifndef YYTOKENTYPE @@ -256,12 +216,37 @@ extern int yydebug; + +/* Copy the first part of user declarations. */ +#line 31 "cc.y" + +#include +#include /* if we don't, bison will, and cc.h re-#defines getc */ +#include "cc.h" + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ -/* Line 387 of yacc.c */ #line 36 "cc.y" - +{ Node* node; Sym* sym; Type* type; @@ -285,38 +270,22 @@ typedef union YYSTYPE int32 lval; double dval; vlong vval; - - -/* Line 387 of yacc.c */ -#line 292 "y.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 193 of yacc.c. */ +#line 276 "y.tab.c" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif -extern YYSTYPE yylval; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - -#endif /* !YY_YY_Y_TAB_H_INCLUDED */ /* Copy the second part of user declarations. */ -/* Line 390 of yacc.c */ -#line 320 "y.tab.c" + +/* Line 216 of yacc.c. */ +#line 289 "y.tab.c" #ifdef short # undef short @@ -369,45 +338,36 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if (! defined __GNUC__ || __GNUC__ < 2 \ - || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) -# define __attribute__(Spec) /* empty */ +# define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) +# define YYUSE(e) ((void) (e)) #else -# define YYUSE(E) /* empty */ +# define YYUSE(e) /* empty */ #endif - /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(N) (N) +# define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int yyi) +YYID (int i) #else static int -YYID (yyi) - int yyi; +YYID (i) + int i; #endif { - return yyi; + return i; } #endif @@ -428,12 +388,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # endif @@ -456,24 +415,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ +# if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -489,9 +448,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; + yytype_int16 yyss; + YYSTYPE yyvs; + }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -502,19 +461,35 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -# define YYCOPY_NEEDED 1 +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ +# define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ @@ -522,26 +497,6 @@ union yyalloc #endif -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ @@ -737,16 +692,16 @@ static const yytype_uint16 yyrline[] = 794, 798, 802, 803, 810, 817, 824, 831, 838, 845, 852, 859, 860, 863, 873, 891, 901, 919, 922, 925, 926, 933, 932, 955, 959, 962, 967, 972, 978, 986, - 992, 998, 1004, 1012, 1020, 1027, 1033, 1032, 1044, 1052, - 1058, 1057, 1069, 1077, 1086, 1090, 1085, 1107, 1106, 1115, - 1121, 1122, 1128, 1131, 1137, 1138, 1139, 1142, 1143, 1149, - 1150, 1153, 1157, 1161, 1162, 1165, 1166, 1167, 1168, 1169, - 1170, 1171, 1172, 1173, 1176, 1177, 1178, 1179, 1180, 1181, - 1182, 1185, 1186, 1187, 1190, 1205, 1217, 1218 + 992, 998, 1004, 1012, 1020, 1027, 1033, 1032, 1044, 1053, + 1059, 1058, 1070, 1078, 1087, 1091, 1086, 1108, 1107, 1116, + 1122, 1123, 1129, 1132, 1138, 1139, 1140, 1143, 1144, 1150, + 1151, 1154, 1158, 1162, 1163, 1166, 1167, 1168, 1169, 1170, + 1171, 1172, 1173, 1174, 1177, 1178, 1179, 1180, 1181, 1182, + 1183, 1186, 1187, 1188, 1191, 1206, 1218, 1219 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || 0 +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -764,16 +719,16 @@ static const char *const yytname[] = "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID", "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF", "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'", - "$accept", "prog", "xdecl", "$@1", "$@2", "xdlist", "$@3", "xdecor", - "xdecor2", "adecl", "adlist", "$@4", "pdecl", "pdlist", "edecl", "$@5", - "$@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2", + "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor", + "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5", + "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2", "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist", - "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", - "$@7", "$@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", - "uexpr", "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9", - "zctlist", "types", "tlist", "ctlist", "complex", "$@10", "$@11", "$@12", - "$@13", "$@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname", - "enum", "tname", "cname", "gname", "name", "tag", "ltag", YY_NULL + "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7", + "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr", + "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9", + "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12", + "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname", + "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0 }; #endif @@ -855,8 +810,8 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { @@ -981,7 +936,8 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -205 static const yytype_int16 yytable[] = { @@ -1106,12 +1062,6 @@ static const yytype_int16 yytable[] = 178, 179, 180, 181, 182, 183, 184, 185, 186 }; -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-331))) - -#define yytable_value_is_error(Yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { 1, 27, 14, 91, 131, 17, 30, 58, 20, 33, @@ -1295,50 +1245,78 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) -/* Error token number */ + #define YYTERROR 1 #define YYERRCODE 256 -/* This macro is provided for backward compatibility. */ +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + #ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ + #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else @@ -1388,8 +1366,6 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) YYSTYPE const * const yyvaluep; #endif { - FILE *yyo = yyoutput; - YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT @@ -1398,7 +1374,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) # else YYUSE (yyoutput); # endif - YYUSE (yytype); + switch (yytype) + { + default: + break; + } } @@ -1435,20 +1415,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } @@ -1482,11 +1459,11 @@ yy_reduce_print (yyvsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - YYFPRINTF (stderr, " $%d = ", yyi + 1); + fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -1523,6 +1500,7 @@ int yydebug; # define YYMAXDEPTH 10000 #endif + #if YYERROR_VERBOSE @@ -1625,145 +1603,115 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) { - YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULL; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - } + int yyn = yypact[yystate]; - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } + if (yysize_overflow) + return YYSIZE_MAXIMUM; - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } } #endif /* YYERROR_VERBOSE */ + /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1788,31 +1736,44 @@ yydestruct (yymsg, yytype, yyvaluep) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - YYUSE (yytype); -} + switch (yytype) + { + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ -/* The lookahead symbol. */ -int yychar; -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif +/* The look-ahead symbol. */ +int yychar; -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; + /*----------. | yyparse. | `----------*/ @@ -1839,37 +1800,14 @@ yyparse () #endif #endif { - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - + + int yystate; int yyn; int yyresult; - /* Lookahead token as an internal (translated) token number. */ + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; @@ -1877,22 +1815,54 @@ yyparse () YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yystacksize = YYINITDEPTH; - YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + goto yysetstate; /*------------------------------------------------------------. @@ -1919,6 +1889,7 @@ yyparse () YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; + /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might @@ -1926,6 +1897,7 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); yyss = yyss1; @@ -1948,8 +1920,9 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1960,6 +1933,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; + YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1969,9 +1943,6 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) - YYACCEPT; - goto yybackup; /*-----------. @@ -1980,16 +1951,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ + look-ahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ + /* Not known => get a look-ahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -2015,27 +1986,29 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; yyn = -yyn; goto yyreduce; } + if (yyn == YYFINAL) + YYACCEPT; + /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the lookahead token. */ + /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token. */ - yychar = YYEMPTY; + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -2072,7 +2045,6 @@ yyreduce: switch (yyn) { case 4: -/* Line 1787 of yacc.c */ #line 109 "cc.y" { dodecl(xdecl, lastclass, lasttype, Z); @@ -2080,7 +2052,6 @@ yyreduce: break; case 6: -/* Line 1787 of yacc.c */ #line 114 "cc.y" { lastdcl = T; @@ -2098,7 +2069,6 @@ yyreduce: break; case 7: -/* Line 1787 of yacc.c */ #line 128 "cc.y" { argmark((yyvsp[(2) - (4)].node), 1); @@ -2106,7 +2076,6 @@ yyreduce: break; case 8: -/* Line 1787 of yacc.c */ #line 132 "cc.y" { Node *n; @@ -2120,7 +2089,6 @@ yyreduce: break; case 9: -/* Line 1787 of yacc.c */ #line 144 "cc.y" { dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2128,7 +2096,6 @@ yyreduce: break; case 10: -/* Line 1787 of yacc.c */ #line 148 "cc.y" { (yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2136,7 +2103,6 @@ yyreduce: break; case 11: -/* Line 1787 of yacc.c */ #line 152 "cc.y" { doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node)); @@ -2144,7 +2110,6 @@ yyreduce: break; case 14: -/* Line 1787 of yacc.c */ #line 160 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z); @@ -2153,7 +2118,6 @@ yyreduce: break; case 16: -/* Line 1787 of yacc.c */ #line 168 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2161,7 +2125,6 @@ yyreduce: break; case 17: -/* Line 1787 of yacc.c */ #line 172 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2169,7 +2132,6 @@ yyreduce: break; case 18: -/* Line 1787 of yacc.c */ #line 176 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2177,7 +2139,6 @@ yyreduce: break; case 19: -/* Line 1787 of yacc.c */ #line 185 "cc.y" { (yyval.node) = dodecl(adecl, lastclass, lasttype, Z); @@ -2185,7 +2146,6 @@ yyreduce: break; case 20: -/* Line 1787 of yacc.c */ #line 189 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2193,7 +2153,6 @@ yyreduce: break; case 21: -/* Line 1787 of yacc.c */ #line 195 "cc.y" { dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2202,7 +2161,6 @@ yyreduce: break; case 22: -/* Line 1787 of yacc.c */ #line 200 "cc.y" { (yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2210,7 +2168,6 @@ yyreduce: break; case 23: -/* Line 1787 of yacc.c */ #line 204 "cc.y" { int32 w; @@ -2222,7 +2179,6 @@ yyreduce: break; case 24: -/* Line 1787 of yacc.c */ #line 212 "cc.y" { (yyval.node) = (yyvsp[(1) - (3)].node); @@ -2235,7 +2191,6 @@ yyreduce: break; case 27: -/* Line 1787 of yacc.c */ #line 229 "cc.y" { dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2243,7 +2198,6 @@ yyreduce: break; case 29: -/* Line 1787 of yacc.c */ #line 239 "cc.y" { lasttype = (yyvsp[(1) - (1)].type); @@ -2251,7 +2205,6 @@ yyreduce: break; case 31: -/* Line 1787 of yacc.c */ #line 244 "cc.y" { lasttype = (yyvsp[(2) - (2)].type); @@ -2259,7 +2212,6 @@ yyreduce: break; case 33: -/* Line 1787 of yacc.c */ #line 250 "cc.y" { lastfield = 0; @@ -2268,7 +2220,6 @@ yyreduce: break; case 35: -/* Line 1787 of yacc.c */ #line 258 "cc.y" { dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node)); @@ -2276,7 +2227,6 @@ yyreduce: break; case 37: -/* Line 1787 of yacc.c */ #line 265 "cc.y" { lastbit = 0; @@ -2285,7 +2235,6 @@ yyreduce: break; case 38: -/* Line 1787 of yacc.c */ #line 270 "cc.y" { (yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2293,7 +2242,6 @@ yyreduce: break; case 39: -/* Line 1787 of yacc.c */ #line 274 "cc.y" { (yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node)); @@ -2301,7 +2249,6 @@ yyreduce: break; case 40: -/* Line 1787 of yacc.c */ #line 282 "cc.y" { (yyval.node) = (Z); @@ -2309,7 +2256,6 @@ yyreduce: break; case 42: -/* Line 1787 of yacc.c */ #line 289 "cc.y" { (yyval.node) = new(OIND, (Z), Z); @@ -2318,7 +2264,6 @@ yyreduce: break; case 43: -/* Line 1787 of yacc.c */ #line 294 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z); @@ -2327,7 +2272,6 @@ yyreduce: break; case 46: -/* Line 1787 of yacc.c */ #line 303 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2335,7 +2279,6 @@ yyreduce: break; case 47: -/* Line 1787 of yacc.c */ #line 307 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2343,7 +2286,6 @@ yyreduce: break; case 48: -/* Line 1787 of yacc.c */ #line 313 "cc.y" { (yyval.node) = new(OFUNC, (Z), Z); @@ -2351,7 +2293,6 @@ yyreduce: break; case 49: -/* Line 1787 of yacc.c */ #line 317 "cc.y" { (yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node)); @@ -2359,7 +2300,6 @@ yyreduce: break; case 50: -/* Line 1787 of yacc.c */ #line 321 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2367,7 +2307,6 @@ yyreduce: break; case 52: -/* Line 1787 of yacc.c */ #line 328 "cc.y" { (yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z); @@ -2375,7 +2314,6 @@ yyreduce: break; case 53: -/* Line 1787 of yacc.c */ #line 334 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z); @@ -2383,7 +2321,6 @@ yyreduce: break; case 54: -/* Line 1787 of yacc.c */ #line 338 "cc.y" { (yyval.node) = new(OELEM, Z, Z); @@ -2392,7 +2329,6 @@ yyreduce: break; case 57: -/* Line 1787 of yacc.c */ #line 347 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node)); @@ -2400,7 +2336,6 @@ yyreduce: break; case 59: -/* Line 1787 of yacc.c */ #line 352 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2408,7 +2343,6 @@ yyreduce: break; case 62: -/* Line 1787 of yacc.c */ #line 360 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2416,7 +2350,6 @@ yyreduce: break; case 63: -/* Line 1787 of yacc.c */ #line 365 "cc.y" { (yyval.node) = Z; @@ -2424,7 +2357,6 @@ yyreduce: break; case 64: -/* Line 1787 of yacc.c */ #line 369 "cc.y" { (yyval.node) = invert((yyvsp[(1) - (1)].node)); @@ -2432,7 +2364,6 @@ yyreduce: break; case 66: -/* Line 1787 of yacc.c */ #line 377 "cc.y" { (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z); @@ -2441,7 +2372,6 @@ yyreduce: break; case 67: -/* Line 1787 of yacc.c */ #line 382 "cc.y" { (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z); @@ -2450,7 +2380,6 @@ yyreduce: break; case 68: -/* Line 1787 of yacc.c */ #line 387 "cc.y" { (yyval.node) = new(ODOTDOT, Z, Z); @@ -2458,7 +2387,6 @@ yyreduce: break; case 69: -/* Line 1787 of yacc.c */ #line 391 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2466,7 +2394,6 @@ yyreduce: break; case 70: -/* Line 1787 of yacc.c */ #line 397 "cc.y" { (yyval.node) = invert((yyvsp[(2) - (3)].node)); @@ -2478,7 +2405,6 @@ yyreduce: break; case 71: -/* Line 1787 of yacc.c */ #line 406 "cc.y" { (yyval.node) = Z; @@ -2486,7 +2412,6 @@ yyreduce: break; case 72: -/* Line 1787 of yacc.c */ #line 410 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2494,7 +2419,6 @@ yyreduce: break; case 73: -/* Line 1787 of yacc.c */ #line 414 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2502,7 +2426,6 @@ yyreduce: break; case 75: -/* Line 1787 of yacc.c */ #line 421 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2510,7 +2433,6 @@ yyreduce: break; case 76: -/* Line 1787 of yacc.c */ #line 427 "cc.y" { (yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z); @@ -2518,7 +2440,6 @@ yyreduce: break; case 77: -/* Line 1787 of yacc.c */ #line 431 "cc.y" { (yyval.node) = new(OCASE, Z, Z); @@ -2526,7 +2447,6 @@ yyreduce: break; case 78: -/* Line 1787 of yacc.c */ #line 435 "cc.y" { (yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z); @@ -2534,7 +2454,6 @@ yyreduce: break; case 79: -/* Line 1787 of yacc.c */ #line 441 "cc.y" { (yyval.node) = Z; @@ -2542,7 +2461,6 @@ yyreduce: break; case 81: -/* Line 1787 of yacc.c */ #line 446 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2550,7 +2468,6 @@ yyreduce: break; case 83: -/* Line 1787 of yacc.c */ #line 453 "cc.y" { (yyval.node) = (yyvsp[(2) - (2)].node); @@ -2558,7 +2475,6 @@ yyreduce: break; case 85: -/* Line 1787 of yacc.c */ #line 459 "cc.y" { markdcl(); @@ -2566,7 +2482,6 @@ yyreduce: break; case 86: -/* Line 1787 of yacc.c */ #line 463 "cc.y" { (yyval.node) = revertdcl(); @@ -2578,7 +2493,6 @@ yyreduce: break; case 87: -/* Line 1787 of yacc.c */ #line 471 "cc.y" { (yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z)); @@ -2588,7 +2502,6 @@ yyreduce: break; case 88: -/* Line 1787 of yacc.c */ #line 477 "cc.y" { (yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node))); @@ -2600,13 +2513,11 @@ yyreduce: break; case 89: -/* Line 1787 of yacc.c */ #line 484 "cc.y" { markdcl(); } break; case 90: -/* Line 1787 of yacc.c */ #line 485 "cc.y" { (yyval.node) = revertdcl(); @@ -2621,7 +2532,6 @@ yyreduce: break; case 91: -/* Line 1787 of yacc.c */ #line 496 "cc.y" { (yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); @@ -2629,7 +2539,6 @@ yyreduce: break; case 92: -/* Line 1787 of yacc.c */ #line 500 "cc.y" { (yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node)); @@ -2637,7 +2546,6 @@ yyreduce: break; case 93: -/* Line 1787 of yacc.c */ #line 504 "cc.y" { (yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z); @@ -2646,7 +2554,6 @@ yyreduce: break; case 94: -/* Line 1787 of yacc.c */ #line 509 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -2664,7 +2571,6 @@ yyreduce: break; case 95: -/* Line 1787 of yacc.c */ #line 523 "cc.y" { (yyval.node) = new(OBREAK, Z, Z); @@ -2672,7 +2578,6 @@ yyreduce: break; case 96: -/* Line 1787 of yacc.c */ #line 527 "cc.y" { (yyval.node) = new(OCONTINUE, Z, Z); @@ -2680,7 +2585,6 @@ yyreduce: break; case 97: -/* Line 1787 of yacc.c */ #line 531 "cc.y" { (yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z); @@ -2688,7 +2592,6 @@ yyreduce: break; case 98: -/* Line 1787 of yacc.c */ #line 535 "cc.y" { (yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z); @@ -2696,7 +2599,6 @@ yyreduce: break; case 99: -/* Line 1787 of yacc.c */ #line 539 "cc.y" { (yyval.node) = new(OPREFETCH, (yyvsp[(3) - (5)].node), Z); @@ -2704,7 +2606,6 @@ yyreduce: break; case 100: -/* Line 1787 of yacc.c */ #line 543 "cc.y" { (yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z); @@ -2712,7 +2613,6 @@ yyreduce: break; case 101: -/* Line 1787 of yacc.c */ #line 548 "cc.y" { (yyval.node) = Z; @@ -2720,7 +2620,6 @@ yyreduce: break; case 103: -/* Line 1787 of yacc.c */ #line 554 "cc.y" { (yyval.node) = Z; @@ -2728,7 +2627,6 @@ yyreduce: break; case 105: -/* Line 1787 of yacc.c */ #line 561 "cc.y" { (yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z); @@ -2737,7 +2635,6 @@ yyreduce: break; case 107: -/* Line 1787 of yacc.c */ #line 569 "cc.y" { (yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2745,7 +2642,6 @@ yyreduce: break; case 109: -/* Line 1787 of yacc.c */ #line 576 "cc.y" { (yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2753,7 +2649,6 @@ yyreduce: break; case 110: -/* Line 1787 of yacc.c */ #line 580 "cc.y" { (yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2761,7 +2656,6 @@ yyreduce: break; case 111: -/* Line 1787 of yacc.c */ #line 584 "cc.y" { (yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2769,7 +2663,6 @@ yyreduce: break; case 112: -/* Line 1787 of yacc.c */ #line 588 "cc.y" { (yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2777,7 +2670,6 @@ yyreduce: break; case 113: -/* Line 1787 of yacc.c */ #line 592 "cc.y" { (yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2785,7 +2677,6 @@ yyreduce: break; case 114: -/* Line 1787 of yacc.c */ #line 596 "cc.y" { (yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2793,7 +2684,6 @@ yyreduce: break; case 115: -/* Line 1787 of yacc.c */ #line 600 "cc.y" { (yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2801,7 +2691,6 @@ yyreduce: break; case 116: -/* Line 1787 of yacc.c */ #line 604 "cc.y" { (yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2809,7 +2698,6 @@ yyreduce: break; case 117: -/* Line 1787 of yacc.c */ #line 608 "cc.y" { (yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2817,7 +2705,6 @@ yyreduce: break; case 118: -/* Line 1787 of yacc.c */ #line 612 "cc.y" { (yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2825,7 +2712,6 @@ yyreduce: break; case 119: -/* Line 1787 of yacc.c */ #line 616 "cc.y" { (yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2833,7 +2719,6 @@ yyreduce: break; case 120: -/* Line 1787 of yacc.c */ #line 620 "cc.y" { (yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2841,7 +2726,6 @@ yyreduce: break; case 121: -/* Line 1787 of yacc.c */ #line 624 "cc.y" { (yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2849,7 +2733,6 @@ yyreduce: break; case 122: -/* Line 1787 of yacc.c */ #line 628 "cc.y" { (yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2857,7 +2740,6 @@ yyreduce: break; case 123: -/* Line 1787 of yacc.c */ #line 632 "cc.y" { (yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2865,7 +2747,6 @@ yyreduce: break; case 124: -/* Line 1787 of yacc.c */ #line 636 "cc.y" { (yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2873,7 +2754,6 @@ yyreduce: break; case 125: -/* Line 1787 of yacc.c */ #line 640 "cc.y" { (yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2881,7 +2761,6 @@ yyreduce: break; case 126: -/* Line 1787 of yacc.c */ #line 644 "cc.y" { (yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2889,7 +2768,6 @@ yyreduce: break; case 127: -/* Line 1787 of yacc.c */ #line 648 "cc.y" { (yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node))); @@ -2897,7 +2775,6 @@ yyreduce: break; case 128: -/* Line 1787 of yacc.c */ #line 652 "cc.y" { (yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2905,7 +2782,6 @@ yyreduce: break; case 129: -/* Line 1787 of yacc.c */ #line 656 "cc.y" { (yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2913,7 +2789,6 @@ yyreduce: break; case 130: -/* Line 1787 of yacc.c */ #line 660 "cc.y" { (yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2921,7 +2796,6 @@ yyreduce: break; case 131: -/* Line 1787 of yacc.c */ #line 664 "cc.y" { (yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2929,7 +2803,6 @@ yyreduce: break; case 132: -/* Line 1787 of yacc.c */ #line 668 "cc.y" { (yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2937,7 +2810,6 @@ yyreduce: break; case 133: -/* Line 1787 of yacc.c */ #line 672 "cc.y" { (yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2945,7 +2817,6 @@ yyreduce: break; case 134: -/* Line 1787 of yacc.c */ #line 676 "cc.y" { (yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2953,7 +2824,6 @@ yyreduce: break; case 135: -/* Line 1787 of yacc.c */ #line 680 "cc.y" { (yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2961,7 +2831,6 @@ yyreduce: break; case 136: -/* Line 1787 of yacc.c */ #line 684 "cc.y" { (yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2969,7 +2838,6 @@ yyreduce: break; case 137: -/* Line 1787 of yacc.c */ #line 688 "cc.y" { (yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2977,7 +2845,6 @@ yyreduce: break; case 138: -/* Line 1787 of yacc.c */ #line 692 "cc.y" { (yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2985,7 +2852,6 @@ yyreduce: break; case 140: -/* Line 1787 of yacc.c */ #line 699 "cc.y" { (yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z); @@ -2996,7 +2862,6 @@ yyreduce: break; case 141: -/* Line 1787 of yacc.c */ #line 706 "cc.y" { (yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z); @@ -3006,7 +2871,6 @@ yyreduce: break; case 143: -/* Line 1787 of yacc.c */ #line 715 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z); @@ -3014,7 +2878,6 @@ yyreduce: break; case 144: -/* Line 1787 of yacc.c */ #line 719 "cc.y" { (yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z); @@ -3022,7 +2885,6 @@ yyreduce: break; case 145: -/* Line 1787 of yacc.c */ #line 723 "cc.y" { (yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z); @@ -3030,7 +2892,6 @@ yyreduce: break; case 146: -/* Line 1787 of yacc.c */ #line 727 "cc.y" { (yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z); @@ -3038,7 +2899,6 @@ yyreduce: break; case 147: -/* Line 1787 of yacc.c */ #line 731 "cc.y" { (yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z); @@ -3046,7 +2906,6 @@ yyreduce: break; case 148: -/* Line 1787 of yacc.c */ #line 735 "cc.y" { (yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z); @@ -3054,7 +2913,6 @@ yyreduce: break; case 149: -/* Line 1787 of yacc.c */ #line 739 "cc.y" { (yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z); @@ -3062,7 +2920,6 @@ yyreduce: break; case 150: -/* Line 1787 of yacc.c */ #line 743 "cc.y" { (yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z); @@ -3070,7 +2927,6 @@ yyreduce: break; case 151: -/* Line 1787 of yacc.c */ #line 747 "cc.y" { (yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z); @@ -3078,7 +2934,6 @@ yyreduce: break; case 152: -/* Line 1787 of yacc.c */ #line 751 "cc.y" { (yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z); @@ -3086,7 +2941,6 @@ yyreduce: break; case 153: -/* Line 1787 of yacc.c */ #line 757 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -3094,7 +2948,6 @@ yyreduce: break; case 154: -/* Line 1787 of yacc.c */ #line 761 "cc.y" { (yyval.node) = new(OSIZE, Z, Z); @@ -3104,7 +2957,6 @@ yyreduce: break; case 155: -/* Line 1787 of yacc.c */ #line 767 "cc.y" { (yyval.node) = new(OSIGN, Z, Z); @@ -3114,7 +2966,6 @@ yyreduce: break; case 156: -/* Line 1787 of yacc.c */ #line 773 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z); @@ -3126,7 +2977,6 @@ yyreduce: break; case 157: -/* Line 1787 of yacc.c */ #line 781 "cc.y" { (yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z); @@ -3134,7 +2984,6 @@ yyreduce: break; case 158: -/* Line 1787 of yacc.c */ #line 785 "cc.y" { (yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z); @@ -3143,7 +2992,6 @@ yyreduce: break; case 159: -/* Line 1787 of yacc.c */ #line 790 "cc.y" { (yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z); @@ -3152,7 +3000,6 @@ yyreduce: break; case 160: -/* Line 1787 of yacc.c */ #line 795 "cc.y" { (yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z); @@ -3160,7 +3007,6 @@ yyreduce: break; case 161: -/* Line 1787 of yacc.c */ #line 799 "cc.y" { (yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z); @@ -3168,7 +3014,6 @@ yyreduce: break; case 163: -/* Line 1787 of yacc.c */ #line 804 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3179,7 +3024,6 @@ yyreduce: break; case 164: -/* Line 1787 of yacc.c */ #line 811 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3190,7 +3034,6 @@ yyreduce: break; case 165: -/* Line 1787 of yacc.c */ #line 818 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3201,7 +3044,6 @@ yyreduce: break; case 166: -/* Line 1787 of yacc.c */ #line 825 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3212,7 +3054,6 @@ yyreduce: break; case 167: -/* Line 1787 of yacc.c */ #line 832 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3223,7 +3064,6 @@ yyreduce: break; case 168: -/* Line 1787 of yacc.c */ #line 839 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3234,7 +3074,6 @@ yyreduce: break; case 169: -/* Line 1787 of yacc.c */ #line 846 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3245,7 +3084,6 @@ yyreduce: break; case 170: -/* Line 1787 of yacc.c */ #line 853 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3256,7 +3094,6 @@ yyreduce: break; case 173: -/* Line 1787 of yacc.c */ #line 864 "cc.y" { (yyval.node) = new(OSTRING, Z, Z); @@ -3270,7 +3107,6 @@ yyreduce: break; case 174: -/* Line 1787 of yacc.c */ #line 874 "cc.y" { char *s; @@ -3290,7 +3126,6 @@ yyreduce: break; case 175: -/* Line 1787 of yacc.c */ #line 892 "cc.y" { (yyval.node) = new(OLSTRING, Z, Z); @@ -3304,7 +3139,6 @@ yyreduce: break; case 176: -/* Line 1787 of yacc.c */ #line 902 "cc.y" { char *s; @@ -3324,7 +3158,6 @@ yyreduce: break; case 177: -/* Line 1787 of yacc.c */ #line 919 "cc.y" { (yyval.node) = Z; @@ -3332,7 +3165,6 @@ yyreduce: break; case 180: -/* Line 1787 of yacc.c */ #line 927 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -3340,7 +3172,6 @@ yyreduce: break; case 181: -/* Line 1787 of yacc.c */ #line 933 "cc.y" { (yyval.tyty).t1 = strf; @@ -3357,7 +3188,6 @@ yyreduce: break; case 182: -/* Line 1787 of yacc.c */ #line 946 "cc.y" { (yyval.type) = strf; @@ -3369,7 +3199,6 @@ yyreduce: break; case 183: -/* Line 1787 of yacc.c */ #line 955 "cc.y" { lastclass = CXXX; @@ -3378,7 +3207,6 @@ yyreduce: break; case 185: -/* Line 1787 of yacc.c */ #line 963 "cc.y" { (yyval.tycl).t = (yyvsp[(1) - (1)].type); @@ -3387,7 +3215,6 @@ yyreduce: break; case 186: -/* Line 1787 of yacc.c */ #line 968 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval)); @@ -3396,7 +3223,6 @@ yyreduce: break; case 187: -/* Line 1787 of yacc.c */ #line 973 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval)); @@ -3406,7 +3232,6 @@ yyreduce: break; case 188: -/* Line 1787 of yacc.c */ #line 979 "cc.y" { (yyval.tycl).t = (yyvsp[(1) - (2)].type); @@ -3418,7 +3243,6 @@ yyreduce: break; case 189: -/* Line 1787 of yacc.c */ #line 987 "cc.y" { (yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval))); @@ -3428,7 +3252,6 @@ yyreduce: break; case 190: -/* Line 1787 of yacc.c */ #line 993 "cc.y" { (yyval.tycl).t = (yyvsp[(2) - (3)].type); @@ -3438,7 +3261,6 @@ yyreduce: break; case 191: -/* Line 1787 of yacc.c */ #line 999 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval)); @@ -3448,7 +3270,6 @@ yyreduce: break; case 192: -/* Line 1787 of yacc.c */ #line 1005 "cc.y" { (yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval))); @@ -3458,7 +3279,6 @@ yyreduce: break; case 193: -/* Line 1787 of yacc.c */ #line 1013 "cc.y" { (yyval.type) = (yyvsp[(1) - (1)].tycl).t; @@ -3468,7 +3288,6 @@ yyreduce: break; case 194: -/* Line 1787 of yacc.c */ #line 1021 "cc.y" { lasttype = (yyvsp[(1) - (1)].tycl).t; @@ -3477,7 +3296,6 @@ yyreduce: break; case 195: -/* Line 1787 of yacc.c */ #line 1028 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0); @@ -3486,7 +3304,6 @@ yyreduce: break; case 196: -/* Line 1787 of yacc.c */ #line 1033 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn); @@ -3494,7 +3311,6 @@ yyreduce: break; case 197: -/* Line 1787 of yacc.c */ #line 1037 "cc.y" { (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag; @@ -3506,9 +3322,9 @@ yyreduce: break; case 198: -/* Line 1787 of yacc.c */ #line 1045 "cc.y" { + diag(Z, "struct must have tag"); taggen++; sprint(symb, "_%d_", taggen); (yyval.type) = dotag(lookup(), TSTRUCT, autobn); @@ -3518,8 +3334,7 @@ yyreduce: break; case 199: -/* Line 1787 of yacc.c */ -#line 1053 "cc.y" +#line 1054 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TUNION, 0); (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag; @@ -3527,16 +3342,14 @@ yyreduce: break; case 200: -/* Line 1787 of yacc.c */ -#line 1058 "cc.y" +#line 1059 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TUNION, autobn); } break; case 201: -/* Line 1787 of yacc.c */ -#line 1062 "cc.y" +#line 1063 "cc.y" { (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag; if((yyval.type)->link != T) @@ -3547,8 +3360,7 @@ yyreduce: break; case 202: -/* Line 1787 of yacc.c */ -#line 1070 "cc.y" +#line 1071 "cc.y" { taggen++; sprint(symb, "_%d_", taggen); @@ -3559,8 +3371,7 @@ yyreduce: break; case 203: -/* Line 1787 of yacc.c */ -#line 1078 "cc.y" +#line 1079 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TENUM, 0); (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag; @@ -3571,16 +3382,14 @@ yyreduce: break; case 204: -/* Line 1787 of yacc.c */ -#line 1086 "cc.y" +#line 1087 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TENUM, autobn); } break; case 205: -/* Line 1787 of yacc.c */ -#line 1090 "cc.y" +#line 1091 "cc.y" { en.tenum = T; en.cenum = T; @@ -3588,8 +3397,7 @@ yyreduce: break; case 206: -/* Line 1787 of yacc.c */ -#line 1095 "cc.y" +#line 1096 "cc.y" { (yyval.type) = (yyvsp[(2) - (7)].sym)->suetag; if((yyval.type)->link != T) @@ -3604,8 +3412,7 @@ yyreduce: break; case 207: -/* Line 1787 of yacc.c */ -#line 1107 "cc.y" +#line 1108 "cc.y" { en.tenum = T; en.cenum = T; @@ -3613,186 +3420,158 @@ yyreduce: break; case 208: -/* Line 1787 of yacc.c */ -#line 1112 "cc.y" +#line 1113 "cc.y" { (yyval.type) = en.tenum; } break; case 209: -/* Line 1787 of yacc.c */ -#line 1116 "cc.y" +#line 1117 "cc.y" { (yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type); } break; case 211: -/* Line 1787 of yacc.c */ -#line 1123 "cc.y" +#line 1124 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 212: -/* Line 1787 of yacc.c */ -#line 1128 "cc.y" +#line 1129 "cc.y" { (yyval.lval) = 0; } break; case 213: -/* Line 1787 of yacc.c */ -#line 1132 "cc.y" +#line 1133 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 218: -/* Line 1787 of yacc.c */ -#line 1144 "cc.y" +#line 1145 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 221: -/* Line 1787 of yacc.c */ -#line 1154 "cc.y" +#line 1155 "cc.y" { doenum((yyvsp[(1) - (1)].sym), Z); } break; case 222: -/* Line 1787 of yacc.c */ -#line 1158 "cc.y" +#line 1159 "cc.y" { doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node)); } break; case 225: -/* Line 1787 of yacc.c */ -#line 1165 "cc.y" +#line 1166 "cc.y" { (yyval.lval) = BCHAR; } break; case 226: -/* Line 1787 of yacc.c */ -#line 1166 "cc.y" +#line 1167 "cc.y" { (yyval.lval) = BSHORT; } break; case 227: -/* Line 1787 of yacc.c */ -#line 1167 "cc.y" +#line 1168 "cc.y" { (yyval.lval) = BINT; } break; case 228: -/* Line 1787 of yacc.c */ -#line 1168 "cc.y" +#line 1169 "cc.y" { (yyval.lval) = BLONG; } break; case 229: -/* Line 1787 of yacc.c */ -#line 1169 "cc.y" +#line 1170 "cc.y" { (yyval.lval) = BSIGNED; } break; case 230: -/* Line 1787 of yacc.c */ -#line 1170 "cc.y" +#line 1171 "cc.y" { (yyval.lval) = BUNSIGNED; } break; case 231: -/* Line 1787 of yacc.c */ -#line 1171 "cc.y" +#line 1172 "cc.y" { (yyval.lval) = BFLOAT; } break; case 232: -/* Line 1787 of yacc.c */ -#line 1172 "cc.y" +#line 1173 "cc.y" { (yyval.lval) = BDOUBLE; } break; case 233: -/* Line 1787 of yacc.c */ -#line 1173 "cc.y" +#line 1174 "cc.y" { (yyval.lval) = BVOID; } break; case 234: -/* Line 1787 of yacc.c */ -#line 1176 "cc.y" +#line 1177 "cc.y" { (yyval.lval) = BAUTO; } break; case 235: -/* Line 1787 of yacc.c */ -#line 1177 "cc.y" +#line 1178 "cc.y" { (yyval.lval) = BSTATIC; } break; case 236: -/* Line 1787 of yacc.c */ -#line 1178 "cc.y" +#line 1179 "cc.y" { (yyval.lval) = BEXTERN; } break; case 237: -/* Line 1787 of yacc.c */ -#line 1179 "cc.y" +#line 1180 "cc.y" { (yyval.lval) = BTYPEDEF; } break; case 238: -/* Line 1787 of yacc.c */ -#line 1180 "cc.y" +#line 1181 "cc.y" { (yyval.lval) = BTYPESTR; } break; case 239: -/* Line 1787 of yacc.c */ -#line 1181 "cc.y" +#line 1182 "cc.y" { (yyval.lval) = BREGISTER; } break; case 240: -/* Line 1787 of yacc.c */ -#line 1182 "cc.y" +#line 1183 "cc.y" { (yyval.lval) = 0; } break; case 241: -/* Line 1787 of yacc.c */ -#line 1185 "cc.y" +#line 1186 "cc.y" { (yyval.lval) = BCONSTNT; } break; case 242: -/* Line 1787 of yacc.c */ -#line 1186 "cc.y" +#line 1187 "cc.y" { (yyval.lval) = BVOLATILE; } break; case 243: -/* Line 1787 of yacc.c */ -#line 1187 "cc.y" +#line 1188 "cc.y" { (yyval.lval) = 0; } break; case 244: -/* Line 1787 of yacc.c */ -#line 1191 "cc.y" +#line 1192 "cc.y" { (yyval.node) = new(ONAME, Z, Z); if((yyvsp[(1) - (1)].sym)->class == CLOCAL) @@ -3809,8 +3588,7 @@ yyreduce: break; case 245: -/* Line 1787 of yacc.c */ -#line 1206 "cc.y" +#line 1207 "cc.y" { (yyval.node) = new(ONAME, Z, Z); (yyval.node)->sym = (yyvsp[(1) - (1)].sym); @@ -3824,21 +3602,10 @@ yyreduce: break; -/* Line 1787 of yacc.c */ -#line 3829 "y.tab.c" +/* Line 1267 of yacc.c. */ +#line 3607 "y.tab.c" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -3847,6 +3614,7 @@ yyreduce: *++yyvsp = yyval; + /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -3866,10 +3634,6 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -3877,36 +3641,37 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } } -# undef YYSYNTAX_ERROR #endif } @@ -3914,7 +3679,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse lookahead token after an + /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -3931,7 +3696,7 @@ yyerrlab: } } - /* Else will try to reuse lookahead token after shifting the error + /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; @@ -3965,7 +3730,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) + if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -3988,9 +3753,10 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + if (yyn == YYFINAL) + YYACCEPT; + *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -4014,7 +3780,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined yyoverflow || YYERROR_VERBOSE +#ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -4025,14 +3791,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -4056,6 +3817,6 @@ yyreturn: } -/* Line 2050 of yacc.c */ -#line 1219 "cc.y" +#line 1220 "cc.y" + diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h index b26d659ef..32daca9b6 100644 --- a/src/cmd/cc/y.tab.h +++ b/src/cmd/cc/y.tab.h @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.7.12-4996. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,20 +29,10 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ -#ifndef YY_YY_Y_TAB_H_INCLUDED -# define YY_YY_Y_TAB_H_INCLUDED -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -196,12 +189,11 @@ extern int yydebug; + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ -/* Line 2053 of yacc.c */ #line 36 "cc.y" - +{ Node* node; Sym* sym; Type* type; @@ -225,30 +217,14 @@ typedef union YYSTYPE int32 lval; double dval; vlong vval; - - -/* Line 2053 of yacc.c */ -#line 232 "y.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 1529 of yacc.c. */ +#line 223 "y.tab.h" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - -#endif /* !YY_YY_Y_TAB_H_INCLUDED */ diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 7757efa1b..10e2278a1 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -272,7 +272,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} case nil: - // These are ordered and grouped to match ../../pkg/go/ast/ast.go + // These are ordered and grouped to match ../../go/ast/ast.go case *ast.Field: if len(n.Names) == 0 && context == "field" { f.walk(&n.Type, "embed-type", visit) @@ -308,6 +308,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} if n.High != nil { f.walk(&n.High, "expr", visit) } + if n.Max != nil { + f.walk(&n.Max, "expr", visit) + } case *ast.TypeAssertExpr: f.walk(&n.X, "expr", visit) f.walk(&n.Type, "type", visit) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 69c7ce893..6179c7afd 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array actually requires a pointer to the first element of the array. C compilers are aware of this calling convention and adjust the call accordingly, but Go cannot. In Go, you must pass -the pointer to the first element explicitly: C.f(&x[0]). +the pointer to the first element explicitly: C.f(&C.x[0]). A few special functions convert between Go and C types by making copies of the data. In pseudo-Go definitions: diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index f55cfbac4..abdd369d7 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name { // Determine kinds for names we already know about, // like #defines or 'struct foo', before bothering with gcc. var names, needType []*Name - for _, n := range f.Name { + for _, key := range nameKeys(f.Name) { + n := f.Name[key] // If we've already found this name as a #define // and we can translate it as a constant value, do so. if n.Define != "" { @@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name { const ( notType = 1 << iota notConst + notDeclared ) for _, line := range strings.Split(stderr, "\n") { if !strings.Contains(line, ": error:") { @@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name { completed = true case "not-declared": - error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:])) + sniff[i] |= notDeclared case "not-type": sniff[i] |= notType case "not-const": @@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name { } if !completed { - fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) + fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr) } for i, n := range names { switch sniff[i] { - case 0: + default: error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go)) case notType: n.Kind = "const" @@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name { } } if nerrors > 0 { + // Check if compiling the preamble by itself causes any errors, + // because the messages we've printed out so far aren't helpful + // to users debugging preamble mistakes. See issue 8442. + preambleErrors := p.gccErrors([]byte(f.Preamble)) + if len(preambleErrors) > 0 { + error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors) + } + fatalf("unresolved names") } @@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) { f.Name[fpName] = name } r.Name = name - expr = ast.NewIdent(name.Mangle) + // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr + // function is defined in out.go and simply returns its argument. See + // issue 7757. + expr = &ast.CallExpr{ + Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, + Args: []ast.Expr{ast.NewIdent(name.Mangle)}, + } } else if r.Name.Kind == "type" { // Okay - might be new(T) expr = r.Name.Type.Go @@ -928,9 +944,8 @@ type typeConv struct { // Map from types to incomplete pointers to those types. ptrs map[dwarf.Type][]*Type - - // Fields to be processed by godefsField after completing pointers. - todoFlds [][]*ast.Field + // Keys of ptrs in insertion order (deterministic worklist) + ptrKeys []dwarf.Type // Predeclared types. bool ast.Expr @@ -940,9 +955,9 @@ type typeConv struct { float32, float64 ast.Expr complex64, complex128 ast.Expr void ast.Expr - unsafePointer ast.Expr string ast.Expr goVoid ast.Expr // _Ctype_void, denotes C's void + goVoidPtr ast.Expr // unsafe.Pointer or *byte ptrSize int64 intSize int64 @@ -972,10 +987,17 @@ func (c *typeConv) Init(ptrSize, intSize int64) { c.float64 = c.Ident("float64") c.complex64 = c.Ident("complex64") c.complex128 = c.Ident("complex128") - c.unsafePointer = c.Ident("unsafe.Pointer") c.void = c.Ident("void") c.string = c.Ident("string") c.goVoid = c.Ident("_Ctype_void") + + // Normally cgo translates void* to unsafe.Pointer, + // but for historical reasons -cdefs and -godefs use *byte instead. + if *cdefs || *godefs { + c.goVoidPtr = &ast.StarExpr{X: c.byte} + } else { + c.goVoidPtr = c.Ident("unsafe.Pointer") + } } // base strips away qualifiers and typedefs to get the underlying type @@ -1037,29 +1059,22 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) { } // FinishType completes any outstanding type mapping work. -// In particular, it resolves incomplete pointer types and also runs -// godefsFields on any new struct types. +// In particular, it resolves incomplete pointer types. func (c *typeConv) FinishType(pos token.Pos) { // Completing one pointer type might produce more to complete. // Keep looping until they're all done. - for len(c.ptrs) > 0 { - for dtype := range c.ptrs { - // Note Type might invalidate c.ptrs[dtype]. - t := c.Type(dtype, pos) - for _, ptr := range c.ptrs[dtype] { - ptr.Go.(*ast.StarExpr).X = t.Go - ptr.C.Set("%s*", t.C) - } - delete(c.ptrs, dtype) - } - } + for len(c.ptrKeys) > 0 { + dtype := c.ptrKeys[0] + c.ptrKeys = c.ptrKeys[1:] - // Now that pointer types are completed, we can invoke godefsFields - // to rewrite struct definitions. - for _, fld := range c.todoFlds { - godefsFields(fld) + // Note Type might invalidate c.ptrs[dtype]. + t := c.Type(dtype, pos) + for _, ptr := range c.ptrs[dtype] { + ptr.Go.(*ast.StarExpr).X = t.Go + ptr.C.Set("%s*", t.C) + } + c.ptrs[dtype] = nil // retain the map key } - c.todoFlds = nil } // Type returns a *Type with the same memory layout as @@ -1072,12 +1087,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { return t } - // clang won't generate DW_AT_byte_size for pointer types, - // so we have to fix it here. - if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { - dt.ByteSize = c.ptrSize - } - t := new(Type) t.Size = dtype.Size() // note: wrong for array of pointers, corrected below t.Align = -1 @@ -1101,12 +1110,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { t.Go = c.Opaque(t.Size) break } + count := dt.Count + if count == -1 { + // Indicates flexible array member, which Go doesn't support. + // Translate to zero-length array instead. + count = 0 + } sub := c.Type(dt.Type, pos) t.Align = sub.Align t.Go = &ast.ArrayType{ - Len: c.intExpr(dt.Count), + Len: c.intExpr(count), Elt: sub.Go, } + // Recalculate t.Size now that we know sub.Size. + t.Size = count * sub.Size t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) case *dwarf.BoolType: @@ -1207,11 +1224,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { } case *dwarf.PtrType: + // Clang doesn't emit DW_AT_byte_size for pointer types. + if t.Size != c.ptrSize && t.Size != -1 { + fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype) + } + t.Size = c.ptrSize t.Align = c.ptrSize - // Translate void* as unsafe.Pointer if _, ok := base(dt.Type).(*dwarf.VoidType); ok { - t.Go = c.unsafePointer + t.Go = c.goVoidPtr t.C.Set("void*") break } @@ -1219,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { // Placeholder initialization; completed in FinishType. t.Go = &ast.StarExpr{} t.C.Set("*") + if _, ok := c.ptrs[dt.Type]; !ok { + c.ptrKeys = append(c.ptrKeys, dt.Type) + } c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t) case *dwarf.QualType: @@ -1379,34 +1403,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { } } - if t.Size <= 0 { - // Clang does not record the size of a pointer in its DWARF entry, - // so if dtype is an array, the call to dtype.Size at the top of the function - // computed the size as the array length * 0 = 0. - // The type switch called Type (this function) recursively on the pointer - // entry, and the code near the top of the function updated the size to - // be correct, so calling dtype.Size again will produce the correct value. - t.Size = dtype.Size() - if t.Size < 0 { - // Unsized types are [0]byte, unless they're typedefs of other types - // or structs with tags. - // if so, use the name we've already defined. - t.Size = 0 - switch dt := dtype.(type) { - case *dwarf.TypedefType: - // ok - case *dwarf.StructType: - if dt.StructName != "" { - break - } - t.Go = c.Opaque(0) - default: - t.Go = c.Opaque(0) - } - if t.C.Empty() { - t.C.Set("void") + if t.Size < 0 { + // Unsized types are [0]byte, unless they're typedefs of other types + // or structs with tags. + // if so, use the name we've already defined. + t.Size = 0 + switch dt := dtype.(type) { + case *dwarf.TypedefType: + // ok + case *dwarf.StructType: + if dt.StructName != "" { + break } - return t + t.Go = c.Opaque(0) + default: + t.Go = c.Opaque(0) + } + if t.C.Empty() { + t.C.Set("void") } } @@ -1538,6 +1552,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { // Struct conversion: return Go and (6g) C syntax for type. func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { + // Minimum alignment for a struct is 1 byte. + align = 1 + var buf bytes.Buffer buf.WriteString("struct {") fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field @@ -1579,7 +1596,27 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct fld = c.pad(fld, f.ByteOffset-off) off = f.ByteOffset } - t := c.Type(f.Type, pos) + + name := f.Name + ft := f.Type + + // In godefs or cdefs mode, if this field is a C11 + // anonymous union then treat the first field in the + // union as the field in the struct. This handles + // cases like the glibc file; see + // issue 6677. + if *godefs || *cdefs { + if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] { + name = st.Field[0].Name + ident[name] = name + ft = st.Field[0].Type + } + } + + // TODO: Handle fields that are anonymous structs by + // promoting the fields of the inner struct. + + t := c.Type(ft, pos) tgo := t.Go size := t.Size talign := t.Align @@ -1598,17 +1635,18 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct talign = size } - if talign > 0 && f.ByteOffset%talign != 0 { + if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs { // Drop misaligned fields, the same way we drop integer bit fields. // The goal is to make available what can be made available. // Otherwise one bad and unneeded field in an otherwise okay struct // makes the whole program not compile. Much of the time these // structs are in system headers that cannot be corrected. + // Exception: In -cdefs mode, we use #pragma pack, so misaligned + // fields should still work. continue } n := len(fld) fld = fld[0 : n+1] - name := f.Name if name == "" { name = fmt.Sprintf("anon%d", anon) anon++ @@ -1635,7 +1673,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct csyntax = buf.String() if *godefs || *cdefs { - c.todoFlds = append(c.todoFlds, fld) + godefsFields(fld) } expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} return @@ -1673,19 +1711,6 @@ func godefsFields(fld []*ast.Field) { n.Name = upper(n.Name) } } - p := &f.Type - t := *p - if star, ok := t.(*ast.StarExpr); ok { - star = &ast.StarExpr{X: star.X} - *p = star - p = &star.X - t = *p - } - if id, ok := t.(*ast.Ident); ok { - if id.Name == "unsafe.Pointer" { - *p = ast.NewIdent("*byte") - } - } } } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 76c7247af..d92bed9bf 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -44,6 +44,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "int main() { return 0; }\n") if *importRuntimeCgo { fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") + fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n") } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, // which provides crosscall2. We just need a prototype. @@ -58,16 +59,14 @@ func (p *Package) writeDefs() { fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") - if *importSyscall { - fmt.Fprintf(fgo2, "import \"syscall\"\n\n") - } if !*gccgo && *importRuntimeCgo { fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") } - fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") if *importSyscall { - fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n") + fmt.Fprintf(fgo2, "import \"syscall\"\n\n") + fmt.Fprintf(fgo2, "var _ syscall.Errno\n") } + fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") typedefNames := make([]string, 0, len(typedef)) for name := range typedef { @@ -87,9 +86,10 @@ func (p *Package) writeDefs() { } if *gccgo { - fmt.Fprintf(fc, p.cPrologGccgo()) + fmt.Fprint(fc, p.cPrologGccgo()) } else { - fmt.Fprintf(fc, cProlog) + fmt.Fprint(fc, cProlog) + fmt.Fprint(fgo2, goProlog) } gccgoSymbolPrefix := p.gccgoSymbolPrefix() @@ -130,6 +130,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C) } else { + fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n") fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C) } fmt.Fprintf(fc, "\n") @@ -296,10 +297,6 @@ func (p *Package) structType(n *Name) (string, int64) { fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) off += pad } - if n.AddError { - fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n") - off += 2 * p.PtrSize - } if off == 0 { fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct } @@ -334,19 +331,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { } // Builtins defined in the C prolog. - inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc" + inProlog := builtinDefs[name] != "" + cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) + paramnames := []string(nil) + for i, param := range d.Type.Params.List { + paramName := fmt.Sprintf("p%d", i) + param.Names = []*ast.Ident{ast.NewIdent(paramName)} + paramnames = append(paramnames, paramName) + } if *gccgo { // Gccgo style hooks. fmt.Fprint(fgo2, "\n") - cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) - paramnames := []string(nil) - for i, param := range d.Type.Params.List { - paramName := fmt.Sprintf("p%d", i) - param.Names = []*ast.Ident{ast.NewIdent(paramName)} - paramnames = append(paramnames, paramName) - } - conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") if !inProlog { @@ -383,7 +379,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { fmt.Fprint(fgo2, "}\n") // declare the C function. - fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) + fmt.Fprintf(fgo2, "//extern %s\n", cname) d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List @@ -394,61 +390,50 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { return } - conf.Fprint(fgo2, fset, d) - fmt.Fprint(fgo2, "\n") if inProlog { + fmt.Fprint(fgo2, builtinDefs[name]) return } - var argSize int64 - _, argSize = p.structType(n) - // C wrapper calls into gcc, passing a pointer to the argument frame. - fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle) - fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) - fmt.Fprintf(fc, "\n") - fmt.Fprintf(fc, "void\n") - if argSize == 0 { - argSize++ + fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname) + fmt.Fprintf(fc, "void %s(void*);\n", cname) + fmt.Fprintf(fc, "#pragma dataflag NOPTR\n") + fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname) + + nret := 0 + if !void { + d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")} + nret = 1 } - // TODO(rsc): The struct here should declare pointers only where - // there are pointers in the actual argument frame. - // This is a workaround for golang.org/issue/6397. - fmt.Fprintf(fc, "·%s(struct{", n.Mangle) - if n := argSize / p.PtrSize; n > 0 { - fmt.Fprintf(fc, "void *y[%d];", n) + if n.AddError { + d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")} } - if n := argSize % p.PtrSize; n > 0 { - fmt.Fprintf(fc, "uint8 x[%d];", n) + + fmt.Fprint(fgo2, "\n") + fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname) + conf.Fprint(fgo2, fset, d) + fmt.Fprint(fgo2, " {\n") + + // NOTE: Using uintptr to hide from escape analysis. + arg := "0" + if len(paramnames) > 0 { + arg = "uintptr(unsafe.Pointer(&p0))" + } else if !void { + arg = "uintptr(unsafe.Pointer(&r1))" } - fmt.Fprintf(fc, "}p)\n") - fmt.Fprintf(fc, "{\n") - fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) + + prefix := "" if n.AddError { - // gcc leaves errno in first word of interface at end of p. - // check whether it is zero; if so, turn interface into nil. - // if not, turn interface into errno. - // Go init function initializes ·_Cerrno with an os.Errno - // for us to copy. - fmt.Fprintln(fc, ` { - int32 e; - void **v; - v = (void**)(&p+1) - 2; /* v = final two void* of p */ - e = *(int32*)v; - v[0] = (void*)0xdeadbeef; - v[1] = (void*)0xdeadbeef; - if(e == 0) { - /* nil interface */ - v[0] = 0; - v[1] = 0; - } else { - ·_Cerrno(v, e); /* fill in v as error for errno e */ - } - }`) + prefix = "errno := " } - fmt.Fprintf(fc, "}\n") - fmt.Fprintf(fc, "\n") + fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg) + if n.AddError { + fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") + } + fmt.Fprintf(fgo2, "\treturn\n") + fmt.Fprintf(fgo2, "}\n") } // writeOutput creates stubs for a specific source file to be compiled by 6g @@ -521,7 +506,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Gcc wrapper unpacks the C argument struct // and calls the actual C function. - fmt.Fprintf(fgcc, "void\n") + if n.AddError { + fmt.Fprintf(fgcc, "int\n") + } else { + fmt.Fprintf(fgcc, "void\n") + } fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) fmt.Fprintf(fgcc, "{\n") if n.AddError { @@ -531,9 +520,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Use packed attribute to force no padding in this struct in case // gcc has different packing requirements. fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) + if n.FuncType.Result != nil { + // Save the stack top for use below. + fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n") + } fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { - fmt.Fprintf(fgcc, "a->r = ") + fmt.Fprintf(fgcc, "__typeof__(a->r) r = ") if c := t.C.String(); c[len(c)-1] == '*' { fmt.Fprint(fgcc, "(__typeof__(a->r)) ") } @@ -556,8 +549,15 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "a->p%d", i) } fmt.Fprintf(fgcc, ");\n") + if n.FuncType.Result != nil { + // The cgo call may have caused a stack copy (via a callback). + // Adjust the return value pointer appropriately. + fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n") + // Save the return value. + fmt.Fprintf(fgcc, "\ta->r = r;\n") + } if n.AddError { - fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n") + fmt.Fprintf(fgcc, "\treturn errno;\n") } fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "\n") @@ -1016,7 +1016,7 @@ func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) { fn(i, r.Type) i++ } else { - for _ = range r.Names { + for range r.Names { fn(i, r.Type) i++ } @@ -1143,21 +1143,17 @@ __cgo_size_assert(__cgo_long_long, 8) __cgo_size_assert(float, 4) __cgo_size_assert(double, 8) +extern char* _cgo_topofstack(void); + #include #include ` const builtinProlog = ` -#include /* for size_t below */ +#include /* for ptrdiff_t and size_t below */ /* Define intgo when compiling with GCC. */ -#ifdef __PTRDIFF_TYPE__ -typedef __PTRDIFF_TYPE__ intgo; -#elif defined(_LP64) -typedef long long intgo; -#else -typedef int intgo; -#endif +typedef ptrdiff_t intgo; typedef struct { char *p; intgo n; } _GoString_; typedef struct { char *p; intgo n; intgo c; } _GoBytes_; @@ -1171,47 +1167,86 @@ void *_CMalloc(size_t); const cProlog = ` #include "runtime.h" #include "cgocall.h" +#include "textflag.h" + +#pragma dataflag NOPTR +static void *cgocall_errno = runtime·cgocall_errno; +#pragma dataflag NOPTR +void *·_cgo_runtime_cgocall_errno = &cgocall_errno; + +#pragma dataflag NOPTR +static void *runtime_gostring = runtime·gostring; +#pragma dataflag NOPTR +void *·_cgo_runtime_gostring = &runtime_gostring; + +#pragma dataflag NOPTR +static void *runtime_gostringn = runtime·gostringn; +#pragma dataflag NOPTR +void *·_cgo_runtime_gostringn = &runtime_gostringn; + +#pragma dataflag NOPTR +static void *runtime_gobytes = runtime·gobytes; +#pragma dataflag NOPTR +void *·_cgo_runtime_gobytes = &runtime_gobytes; + +#pragma dataflag NOPTR +static void *runtime_cmalloc = runtime·cmalloc; +#pragma dataflag NOPTR +void *·_cgo_runtime_cmalloc = &runtime_cmalloc; void ·_Cerrno(void*, int32); +` -void -·_Cfunc_GoString(int8 *p, String s) -{ - s = runtime·gostring((byte*)p); - FLUSH(&s); +const goProlog = ` +var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32 +var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer +` + +const goStringDef = ` +var _cgo_runtime_gostring func(*_Ctype_char) string +func _Cfunc_GoString(p *_Ctype_char) string { + return _cgo_runtime_gostring(p) } +` -void -·_Cfunc_GoStringN(int8 *p, int32 l, String s) -{ - s = runtime·gostringn((byte*)p, l); - FLUSH(&s); +const goStringNDef = ` +var _cgo_runtime_gostringn func(*_Ctype_char, int) string +func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string { + return _cgo_runtime_gostringn(p, int(l)) } +` -void -·_Cfunc_GoBytes(int8 *p, int32 l, Slice s) -{ - s = runtime·gobytes((byte*)p, l); - FLUSH(&s); +const goBytesDef = ` +var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte +func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte { + return _cgo_runtime_gobytes(p, int(l)) } +` -void -·_Cfunc_CString(String s, int8 *p) -{ - p = runtime·cmalloc(s.len+1); - runtime·memmove((byte*)p, s.str, s.len); - p[s.len] = 0; - FLUSH(&p); +const cStringDef = ` +func _Cfunc_CString(s string) *_Ctype_char { + p := _cgo_runtime_cmalloc(uintptr(len(s)+1)) + pp := (*[1<<30]byte)(p) + copy(pp[:], s) + pp[len(s)] = 0 + return (*_Ctype_char)(p) } +` -void -·_Cfunc__CMalloc(uintptr n, int8 *p) -{ - p = runtime·cmalloc(n); - FLUSH(&p); +const cMallocDef = ` +func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer { + return _cgo_runtime_cmalloc(uintptr(n)) } ` +var builtinDefs = map[string]string{ + "GoString": goStringDef, + "GoStringN": goStringNDef, + "GoBytes": goBytesDef, + "CString": cStringDef, + "_CMalloc": cMallocDef, +} + func (p *Package) cPrologGccgo() string { return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1) } diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h index 6222e5060..288063b94 100644 --- a/src/cmd/dist/a.h +++ b/src/cmd/dist/a.h @@ -108,9 +108,6 @@ void mkzexperiment(char*, char*); // buildgo.c void mkzdefaultcc(char*, char*); -// goc2c.c -void goc2c(char*, char*); - // main.c extern int vflag; extern int sflag; @@ -129,6 +126,7 @@ bool isfile(char *p); char* lastelem(char*); Time mtime(char*); void readfile(Buf*, char*); +void copyfile(char*, char*, int); void run(Buf *b, char *dir, int mode, char *cmd, ...); void runv(Buf *b, char *dir, int mode, Vec *argv); void bgrunv(char *dir, int mode, Vec *argv); diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c index 52a621c5d..1ce7b7710 100644 --- a/src/cmd/dist/arm.c +++ b/src/cmd/dist/arm.c @@ -21,7 +21,8 @@ xgetgoarm(void) // FreeBSD has broken VFP support return "5"; #endif - if(xtryexecfunc(useVFPv3)) + // NaCl always has VFP support. + if(streq(goos, "nacl") || xtryexecfunc(useVFPv3)) return "7"; else if(xtryexecfunc(useVFPv1)) return "6"; diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c index 45fb1954d..2ddc6be75 100644 --- a/src/cmd/dist/buf.c +++ b/src/cmd/dist/buf.c @@ -202,7 +202,7 @@ vadd(Vec *v, char *p) } // vaddn adds a string consisting of the n bytes at p to the vector. -void +static void vaddn(Vec *v, char *p, int n) { char *q; diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index 6884e0aae..d638ae4eb 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -35,7 +35,6 @@ bool rebuildall; bool defaultclang; static bool shouldbuild(char*, char*); -static void copy(char*, char*, int); static void dopack(char*, char*, char**, int); static char *findgoversion(void); @@ -56,6 +55,7 @@ static char *okgoos[] = { "darwin", "dragonfly", "linux", + "android", "solaris", "freebsd", "nacl", @@ -366,8 +366,8 @@ static char *oldtool[] = { // not be in release branches. static char *unreleased[] = { "src/cmd/link", - "src/pkg/debug/goobj", - "src/pkg/old", + "src/debug/goobj", + "src/old", }; // setup sets up the tree for the initial build. @@ -590,7 +590,7 @@ static struct { "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a", "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a", }}, - {"pkg/runtime", { + {"runtime", { "zaexperiment.h", // must sort above zasm "zasm_$GOOS_$GOARCH.h", "zsys_$GOOS_$GOARCH.s", @@ -607,7 +607,6 @@ char *depsuffix[] = { ".h", ".s", ".go", - ".goc", }; // gentab records how to generate some trivial files. @@ -639,7 +638,7 @@ install(char *dir) { char *name, *p, *elem, *prefix, *exe; bool islib, ispkg, isgo, stale, ispackcmd; - Buf b, b1, path; + Buf b, b1, path, final_path, final_name; Vec compile, files, link, go, missing, clean, lib, extra; Time ttarg, t; int i, j, k, n, doclean, targ; @@ -654,6 +653,8 @@ install(char *dir) binit(&b); binit(&b1); binit(&path); + binit(&final_path); + binit(&final_name); vinit(&compile); vinit(&files); vinit(&link); @@ -666,15 +667,9 @@ install(char *dir) // path = full path to dir. bpathf(&path, "%s/src/%s", goroot, dir); + bpathf(&final_path, "%s/src/%s", goroot_final, dir); name = lastelem(dir); - // For misc/prof, copy into the tool directory and we're done. - if(hasprefix(dir, "misc/")) { - copy(bpathf(&b, "%s/%s", tooldir, name), - bpathf(&b1, "%s/misc/%s", goroot, name), 1); - goto out; - } - // set up gcc command line on first run. if(gccargs.len == 0) { bprintf(&b, "%s %s", defaultcc, defaultcflags); @@ -704,7 +699,7 @@ install(char *dir) } islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc"); - ispkg = hasprefix(dir, "pkg"); + ispkg = !islib && !hasprefix(dir, "cmd/"); isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo"); exe = ""; @@ -730,11 +725,11 @@ install(char *dir) // Go library (package). ispackcmd = 1; vadd(&link, "pack"); // program name - unused here, but all the other cases record one - p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4); + p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir); *xstrrchr(p, '/') = '\0'; xmkdirall(p); targ = link.len; - vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4)); + vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)); } else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) { // Go command. vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar)); @@ -881,18 +876,22 @@ install(char *dir) goto out; // For package runtime, copy some files into the work space. - if(streq(dir, "pkg/runtime")) { - copy(bpathf(&b, "%s/arch_GOARCH.h", workdir), + if(streq(dir, "runtime")) { + copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir), bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0); - copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir), + copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir), bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0); p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch); if(isfile(p)) - copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0); - copy(bpathf(&b, "%s/os_GOOS.h", workdir), + copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0); + copyfile(bpathf(&b, "%s/os_GOOS.h", workdir), bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0); - copy(bpathf(&b, "%s/signals_GOOS.h", workdir), + copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir), bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0); + copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch), + bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0); + copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch), + bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0); } // Generate any missing files; regenerate existing ones. @@ -907,7 +906,7 @@ install(char *dir) errprintf("generate %s\n", p); gentab[j].gen(bstr(&path), p); // Do not add generated file to clean list. - // In pkg/runtime, we want to be able to + // In runtime, we want to be able to // build the package with the go tool, // and it assumes these generated files already // exist (it does not know how to build them). @@ -925,27 +924,11 @@ install(char *dir) // One more copy for package runtime. // The last batch was required for the generators. // This one is generated. - if(streq(dir, "pkg/runtime")) { - copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), + if(streq(dir, "runtime")) { + copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0); } - // Generate .c files from .goc files. - if(streq(dir, "pkg/runtime")) { - for(i=0; i 1) @@ -1086,7 +1069,7 @@ install(char *dir) else vadd(&compile, "main"); - if(streq(dir, "pkg/runtime")) + if(streq(dir, "runtime")) vadd(&compile, "-+"); vcopy(&compile, go.p, go.len); @@ -1115,11 +1098,11 @@ install(char *dir) nobuild: // In package runtime, we install runtime.h and cgocall.h too, // for use by cgo compilation. - if(streq(dir, "pkg/runtime")) { - copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch), - bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0); - copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch), - bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0); + if(streq(dir, "runtime")) { + copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch), + bpathf(&b1, "%s/src/runtime/cgocall.h", goroot), 0); + copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch), + bpathf(&b1, "%s/src/runtime/runtime.h", goroot), 0); } @@ -1149,7 +1132,7 @@ matchfield(char *f) p = xstrrchr(f, ','); if(p == nil) - return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1"); + return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux")); *p = 0; res = matchfield(f) && matchfield(p+1); *p = ','; @@ -1241,8 +1224,8 @@ out: } // copy copies the file src to dst, via memory (so only good for small files). -static void -copy(char *dst, char *src, int exec) +void +copyfile(char *dst, char *src, int exec) { Buf b; @@ -1303,8 +1286,6 @@ static char *buildorder[] = { "libbio", "liblink", - "misc/pprof", - "cmd/cc", // must be before c "cmd/gc", // must be before g "cmd/%sl", // must be before a, c, g @@ -1316,47 +1297,47 @@ static char *buildorder[] = { // back when there were build scripts. Will have to // be maintained by hand, but shouldn't change very // often. - "pkg/runtime", - "pkg/errors", - "pkg/sync/atomic", - "pkg/sync", - "pkg/io", - "pkg/unicode", - "pkg/unicode/utf8", - "pkg/unicode/utf16", - "pkg/bytes", - "pkg/math", - "pkg/strings", - "pkg/strconv", - "pkg/bufio", - "pkg/sort", - "pkg/container/heap", - "pkg/encoding/base64", - "pkg/syscall", - "pkg/time", - "pkg/os", - "pkg/reflect", - "pkg/fmt", - "pkg/encoding", - "pkg/encoding/json", - "pkg/flag", - "pkg/path/filepath", - "pkg/path", - "pkg/io/ioutil", - "pkg/log", - "pkg/regexp/syntax", - "pkg/regexp", - "pkg/go/token", - "pkg/go/scanner", - "pkg/go/ast", - "pkg/go/parser", - "pkg/os/exec", - "pkg/os/signal", - "pkg/net/url", - "pkg/text/template/parse", - "pkg/text/template", - "pkg/go/doc", - "pkg/go/build", + "runtime", + "errors", + "sync/atomic", + "sync", + "io", + "unicode", + "unicode/utf8", + "unicode/utf16", + "bytes", + "math", + "strings", + "strconv", + "bufio", + "sort", + "container/heap", + "encoding/base64", + "syscall", + "time", + "os", + "reflect", + "fmt", + "encoding", + "encoding/json", + "flag", + "path/filepath", + "path", + "io/ioutil", + "log", + "regexp/syntax", + "regexp", + "go/token", + "go/scanner", + "go/ast", + "go/parser", + "os/exec", + "os/signal", + "net/url", + "text/template/parse", + "text/template", + "go/doc", + "go/build", "cmd/go", }; @@ -1364,6 +1345,7 @@ static char *buildorder[] = { // It is bigger than the buildorder because we clean all the // compilers but build only the $GOARCH ones. static char *cleantab[] = { + // Commands and C libraries. "cmd/5a", "cmd/5c", "cmd/5g", @@ -1382,46 +1364,48 @@ static char *cleantab[] = { "lib9", "libbio", "liblink", - "pkg/bufio", - "pkg/bytes", - "pkg/container/heap", - "pkg/encoding", - "pkg/encoding/base64", - "pkg/encoding/json", - "pkg/errors", - "pkg/flag", - "pkg/fmt", - "pkg/go/ast", - "pkg/go/build", - "pkg/go/doc", - "pkg/go/parser", - "pkg/go/scanner", - "pkg/go/token", - "pkg/io", - "pkg/io/ioutil", - "pkg/log", - "pkg/math", - "pkg/net/url", - "pkg/os", - "pkg/os/exec", - "pkg/path", - "pkg/path/filepath", - "pkg/reflect", - "pkg/regexp", - "pkg/regexp/syntax", - "pkg/runtime", - "pkg/sort", - "pkg/strconv", - "pkg/strings", - "pkg/sync", - "pkg/sync/atomic", - "pkg/syscall", - "pkg/text/template", - "pkg/text/template/parse", - "pkg/time", - "pkg/unicode", - "pkg/unicode/utf16", - "pkg/unicode/utf8", + + // Go packages. + "bufio", + "bytes", + "container/heap", + "encoding", + "encoding/base64", + "encoding/json", + "errors", + "flag", + "fmt", + "go/ast", + "go/build", + "go/doc", + "go/parser", + "go/scanner", + "go/token", + "io", + "io/ioutil", + "log", + "math", + "net/url", + "os", + "os/exec", + "path", + "path/filepath", + "reflect", + "regexp", + "regexp/syntax", + "runtime", + "sort", + "strconv", + "strings", + "sync", + "sync/atomic", + "syscall", + "text/template", + "text/template/parse", + "time", + "unicode", + "unicode/utf16", + "unicode/utf8", }; static void @@ -1450,9 +1434,9 @@ clean(void) xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4)); } - // remove src/pkg/runtime/z* unconditionally + // remove src/runtime/z* unconditionally vreset(&dir); - bpathf(&path, "%s/src/pkg/runtime", goroot); + bpathf(&path, "%s/src/runtime", goroot); xreaddir(&dir, bstr(&path)); for(j=0; j 0) usage(); + if(isdir(bpathf(&b, "%s/src/pkg", goroot))) { + fatal("\n\n" + "The Go package sources have moved to $GOROOT/src.\n" + "*** %s still exists. ***\n" + "It probably contains stale files that may confuse the build.\n" + "Please (check what's there and) remove it and try again.\n" + "See http://golang.org/s/go14nopkg\n", bpathf(&b, "%s/src/pkg", goroot)); + } + if(rebuildall) clean(); goversion = findgoversion(); @@ -1619,9 +1612,9 @@ cmdbootstrap(int argc, char **argv) xsetenv("GOARCH", goarch); xsetenv("GOOS", goos); - // Build pkg/runtime for actual goos/goarch too. + // Build runtime for actual goos/goarch too. if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) - install("pkg/runtime"); + install("runtime"); bfree(&b); } diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c index 1f0625daa..66adf6857 100644 --- a/src/cmd/dist/buildgc.c +++ b/src/cmd/dist/buildgc.c @@ -65,24 +65,35 @@ gcopnames(char *dir, char *file) // mkanames reads [568].out.h and writes anames[568].c // The format is much the same as the Go opcodes above. +// it also writes out cnames array for C_* constants. void mkanames(char *dir, char *file) { - int i, ch; - Buf in, b, out; + int i, j, ch; + Buf in, b, out, out2; Vec lines; char *p; binit(&b); binit(&in); binit(&out); + binit(&out2); vinit(&lines); ch = file[xstrlen(file)-3]; bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch); readfile(&in, bstr(&b)); splitlines(&lines, bstr(&in)); - bprintf(&out, "char* anames%c[] = {\n", ch); + + // Include link.h so that the extern declaration there is + // checked against the non-extern declaration we are generating. + bwritestr(&out, bprintf(&b, "#include \n")); + bwritestr(&out, bprintf(&b, "#include \n")); + bwritestr(&out, bprintf(&b, "#include \n")); + bwritestr(&out, bprintf(&b, "#include \n")); + bwritestr(&out, bprintf(&b, "\n")); + + bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch)); for(i=0; i0) + bwriteb(&out, &out2); + writefile(&out, file, 0); bfree(&b); bfree(&in); bfree(&out); + bfree(&out2); vfree(&lines); } diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c index ba5993b2f..bb774e05f 100644 --- a/src/cmd/dist/buildruntime.c +++ b/src/cmd/dist/buildruntime.c @@ -5,7 +5,7 @@ #include "a.h" /* - * Helpers for building pkg/runtime. + * Helpers for building runtime. */ // mkzversion writes zversion.go: @@ -30,7 +30,8 @@ mkzversion(char *dir, char *file) "package runtime\n" "\n" "const defaultGoroot = `%s`\n" - "const theVersion = `%s`\n", goroot_final, goversion)); + "const theVersion = `%s`\n" + "var buildVersion = theVersion\n", goroot_final, goversion)); writefile(&out, file, 0); @@ -108,10 +109,14 @@ mkzgoos(char *dir, char *file) binit(&b); binit(&out); + + bwritestr(&out, "// auto generated by go tool dist\n\n"); + + if(streq(goos, "linux")) { + bwritestr(&out, "// +build !android\n\n"); + } bwritestr(&out, bprintf(&b, - "// auto generated by go tool dist\n" - "\n" "package runtime\n" "\n" "const theGoos = `%s`\n", goos)); @@ -130,17 +135,14 @@ static struct { {"386", "", "#define get_tls(r) MOVL TLS, r\n" "#define g(r) 0(r)(TLS*1)\n" - "#define m(r) 4(r)(TLS*1)\n" }, {"amd64p32", "", "#define get_tls(r) MOVL TLS, r\n" "#define g(r) 0(r)(TLS*1)\n" - "#define m(r) 4(r)(TLS*1)\n" }, {"amd64", "", "#define get_tls(r) MOVQ TLS, r\n" "#define g(r) 0(r)(TLS*1)\n" - "#define m(r) 8(r)(TLS*1)\n" }, {"arm", "", @@ -160,11 +162,12 @@ mkzasm(char *dir, char *file) { int i, n; char *aggr, *p; - Buf in, b, out, exp; + Buf in, b, b1, out, exp; Vec argv, lines, fields; binit(&in); binit(&b); + binit(&b1); binit(&out); binit(&exp); vinit(&argv); @@ -172,6 +175,10 @@ mkzasm(char *dir, char *file) vinit(&fields); bwritestr(&out, "// auto generated by go tool dist\n\n"); + if(streq(goos, "linux")) { + bwritestr(&out, "// +build !android\n\n"); + } + for(i=0; inext; - xfree(p->name); - xfree(p->type); - xfree(p); - p = next; - } -} - -/* Read a character, tracking lineno. */ -static int -getchar_update_lineno(void) -{ - int c; - - c = xgetchar(); - if (c == '\n') - ++lineno; - return c; -} - -/* Read a character, giving an error on EOF, tracking lineno. */ -static int -getchar_no_eof(void) -{ - int c; - - c = getchar_update_lineno(); - if (c == EOF) - bad_eof(); - return c; -} - -/* Read a character, skipping comments. */ -static int -getchar_skipping_comments(void) -{ - int c; - - while (1) { - c = getchar_update_lineno(); - if (c != '/') - return c; - - c = xgetchar(); - if (c == '/') { - do { - c = getchar_update_lineno(); - } while (c != EOF && c != '\n'); - return c; - } else if (c == '*') { - while (1) { - c = getchar_update_lineno(); - if (c == EOF) - return EOF; - if (c == '*') { - do { - c = getchar_update_lineno(); - } while (c == '*'); - if (c == '/') - break; - } - } - } else { - xungetc(); - return '/'; - } - } -} - -/* - * Read and return a token. Tokens are string or character literals - * or else delimited by whitespace or by [(),{}]. - * The latter are all returned as single characters. - */ -static char * -read_token(void) -{ - int c, q; - char *buf; - unsigned int alc, off; - char* delims = "(),{}"; - - while (1) { - c = getchar_skipping_comments(); - if (c == EOF) - return nil; - if (!xisspace(c)) - break; - } - alc = 16; - buf = xmalloc(alc + 1); - off = 0; - if(c == '"' || c == '\'') { - q = c; - buf[off] = c; - ++off; - while (1) { - if (off+2 >= alc) { // room for c and maybe next char - alc *= 2; - buf = xrealloc(buf, alc + 1); - } - c = getchar_no_eof(); - buf[off] = c; - ++off; - if(c == q) - break; - if(c == '\\') { - buf[off] = getchar_no_eof(); - ++off; - } - } - } else if (xstrrchr(delims, c) != nil) { - buf[off] = c; - ++off; - } else { - while (1) { - if (off >= alc) { - alc *= 2; - buf = xrealloc(buf, alc + 1); - } - buf[off] = c; - ++off; - c = getchar_skipping_comments(); - if (c == EOF) - break; - if (xisspace(c) || xstrrchr(delims, c) != nil) { - if (c == '\n') - lineno--; - xungetc(); - break; - } - } - } - buf[off] = '\0'; - return buf; -} - -/* Read a token, giving an error on EOF. */ -static char * -read_token_no_eof(void) -{ - char *token = read_token(); - if (token == nil) - bad_eof(); - return token; -} - -/* Read the package clause, and return the package name. */ -static char * -read_package(void) -{ - char *token; - - token = read_token_no_eof(); - if (token == nil) - fatal("%s:%d: no token\n", file, lineno); - if (!streq(token, "package")) { - fatal("%s:%d: expected \"package\", got \"%s\"\n", - file, lineno, token); - } - return read_token_no_eof(); -} - -/* Read and copy preprocessor lines. */ -static void -read_preprocessor_lines(void) -{ - int first; - - first = 1; - while (1) { - int c; - - do { - c = getchar_skipping_comments(); - } while (xisspace(c)); - if (c != '#') { - xungetc(); - break; - } - if(first) { - first = 0; - xputchar('\n'); - } - xputchar(c); - do { - c = getchar_update_lineno(); - xputchar(c); - } while (c != '\n'); - } -} - -/* - * Read a type in Go syntax and return a type in C syntax. We only - * permit basic types and pointers. - */ -static char * -read_type(void) -{ - char *p, *op, *q; - int pointer_count; - unsigned int len; - - p = read_token_no_eof(); - if (*p != '*' && !streq(p, "int") && !streq(p, "uint")) - return p; - op = p; - pointer_count = 0; - while (*p == '*') { - ++pointer_count; - ++p; - } - len = xstrlen(p); - q = xmalloc(len + 2 + pointer_count + 1); - xmemmove(q, p, len); - - // Turn int/uint into intgo/uintgo. - if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) { - q[len++] = 'g'; - q[len++] = 'o'; - } - - while (pointer_count-- > 0) - q[len++] = '*'; - - q[len] = '\0'; - xfree(op); - return q; -} - -/* Return the size of the given type. */ -static int -type_size(char *p, int *rnd) -{ - int i; - - if(p[xstrlen(p)-1] == '*') { - *rnd = type_table[Uintptr].rnd; - return type_table[Uintptr].size; - } - - if(streq(p, "Iface")) - p = "Eface"; - - for(i=0; type_table[i].name; i++) - if(streq(type_table[i].name, p)) { - *rnd = type_table[i].rnd; - return type_table[i].size; - } - fatal("%s:%d: unknown type %s\n", file, lineno, p); - return 0; -} - -/* - * Read a list of parameters. Each parameter is a name and a type. - * The list ends with a ')'. We have already read the '('. - */ -static struct params * -read_params(int *poffset) -{ - char *token; - struct params *ret, **pp, *p; - int offset, size, rnd; - - ret = nil; - pp = &ret; - token = read_token_no_eof(); - offset = 0; - if (!streq(token, ")")) { - while (1) { - p = xmalloc(sizeof(struct params)); - p->name = token; - p->next = nil; - *pp = p; - pp = &p->next; - - if(streq(token, "...")) { - p->type = xstrdup(""); - } else { - p->type = read_type(); - rnd = 0; - size = type_size(p->type, &rnd); - if(rnd > structround) - rnd = structround; - if(offset%rnd) - offset += rnd - offset%rnd; - offset += size; - } - - token = read_token_no_eof(); - if (!streq(token, ",")) - break; - token = read_token_no_eof(); - } - } - if (!streq(token, ")")) { - fatal("%s:%d: expected '('\n", - file, lineno); - } - if (poffset != nil) - *poffset = offset; - return ret; -} - -/* - * Read a function header. This reads up to and including the initial - * '{' character. Returns 1 if it read a header, 0 at EOF. - */ -static int -read_func_header(char **name, struct params **params, int *paramwid, struct params **rets) -{ - int lastline; - char *token; - - lastline = -1; - while (1) { - read_preprocessor_lines(); - token = read_token(); - if (token == nil) - return 0; - if (streq(token, "func")) { - if(lastline != -1) - bwritef(output, "\n"); - break; - } - if (lastline != lineno) { - if (lastline == lineno-1) - bwritef(output, "\n"); - else - bwritef(output, "\n#line %d \"%s\"\n", lineno, file); - lastline = lineno; - } - bwritef(output, "%s ", token); - } - - *name = read_token_no_eof(); - - token = read_token(); - if (token == nil || !streq(token, "(")) { - fatal("%s:%d: expected \"(\"\n", - file, lineno); - } - *params = read_params(paramwid); - - token = read_token(); - if (token == nil || !streq(token, "(")) - *rets = nil; - else { - *rets = read_params(nil); - token = read_token(); - } - if (token == nil || !streq(token, "{")) { - fatal("%s:%d: expected \"{\"\n", - file, lineno); - } - return 1; -} - -/* Write out parameters. */ -static void -write_params(struct params *params, int *first) -{ - struct params *p; - - for (p = params; p != nil; p = p->next) { - if (*first) - *first = 0; - else - bwritef(output, ", "); - bwritef(output, "%s %s", p->type, p->name); - } -} - -/* Write a 6g function header. */ -static void -write_6g_func_header(char *package, char *name, struct params *params, - int paramwid, struct params *rets) -{ - int first, n; - struct params *p; - - bwritef(output, "void\n"); - if(!contains(name, "·")) - bwritef(output, "%s·", package); - bwritef(output, "%s(", name); - - first = 1; - write_params(params, &first); - - /* insert padding to align output struct */ - if(rets != nil && paramwid%structround != 0) { - n = structround - paramwid%structround; - if(n & 1) - bwritef(output, ", uint8"); - if(n & 2) - bwritef(output, ", uint16"); - if(n & 4) - bwritef(output, ", uint32"); - } - - write_params(rets, &first); - bwritef(output, ")\n{\n"); - - for (p = rets; p != nil; p = p->next) { - if(streq(p->name, "...")) - continue; - if(streq(p->type, "Slice")) - bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name); - else if(streq(p->type, "String")) - bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name); - else if(streq(p->type, "Eface")) - bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name); - else if(streq(p->type, "Iface")) - bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name); - else if(streq(p->type, "Complex128")) - bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name); - else - bwritef(output, "\t%s = 0;\n", p->name); - bwritef(output, "\tFLUSH(&%s);\n", p->name); - } -} - -/* Write a 6g function trailer. */ -static void -write_6g_func_trailer(struct params *rets) -{ - struct params *p; - - for (p = rets; p != nil; p = p->next) - if(!streq(p->name, "...")) - bwritef(output, "\tFLUSH(&%s);\n", p->name); - bwritef(output, "}\n"); -} - -/* Define the gcc function return type if necessary. */ -static void -define_gcc_return_type(char *package, char *name, struct params *rets) -{ - struct params *p; - - if (rets == nil || rets->next == nil) - return; - bwritef(output, "struct %s_%s_ret {\n", package, name); - for (p = rets; p != nil; p = p->next) - bwritef(output, " %s %s;\n", p->type, p->name); - bwritef(output, "};\n"); -} - -/* Write out the gcc function return type. */ -static void -write_gcc_return_type(char *package, char *name, struct params *rets) -{ - if (rets == nil) - bwritef(output, "void"); - else if (rets->next == nil) - bwritef(output, "%s", rets->type); - else - bwritef(output, "struct %s_%s_ret", package, name); -} - -/* Write out a gcc function header. */ -static void -write_gcc_func_header(char *package, char *name, struct params *params, - struct params *rets) -{ - int first; - struct params *p; - - define_gcc_return_type(package, name, rets); - write_gcc_return_type(package, name, rets); - bwritef(output, " %s_%s(", package, name); - first = 1; - write_params(params, &first); - bwritef(output, ") asm (\"%s.%s\");\n", package, name); - write_gcc_return_type(package, name, rets); - bwritef(output, " %s_%s(", package, name); - first = 1; - write_params(params, &first); - bwritef(output, ")\n{\n"); - for (p = rets; p != nil; p = p->next) - bwritef(output, " %s %s;\n", p->type, p->name); -} - -/* Write out a gcc function trailer. */ -static void -write_gcc_func_trailer(char *package, char *name, struct params *rets) -{ - if (rets == nil) { - // nothing to do - } - else if (rets->next == nil) - bwritef(output, "return %s;\n", rets->name); - else { - struct params *p; - - bwritef(output, " {\n struct %s_%s_ret __ret;\n", package, name); - for (p = rets; p != nil; p = p->next) - bwritef(output, " __ret.%s = %s;\n", p->name, p->name); - bwritef(output, " return __ret;\n }\n"); - } - bwritef(output, "}\n"); -} - -/* Write out a function header. */ -static void -write_func_header(char *package, char *name, - struct params *params, int paramwid, - struct params *rets) -{ - if (gcc) - write_gcc_func_header(package, name, params, rets); - else - write_6g_func_header(package, name, params, paramwid, rets); - bwritef(output, "#line %d \"%s\"\n", lineno, file); -} - -/* Write out a function trailer. */ -static void -write_func_trailer(char *package, char *name, - struct params *rets) -{ - if (gcc) - write_gcc_func_trailer(package, name, rets); - else - write_6g_func_trailer(rets); -} - -/* - * Read and write the body of the function, ending in an unnested } - * (which is read but not written). - */ -static void -copy_body(void) -{ - int nesting = 0; - while (1) { - int c; - - c = getchar_no_eof(); - if (c == '}' && nesting == 0) - return; - xputchar(c); - switch (c) { - default: - break; - case '{': - ++nesting; - break; - case '}': - --nesting; - break; - case '/': - c = getchar_update_lineno(); - xputchar(c); - if (c == '/') { - do { - c = getchar_no_eof(); - xputchar(c); - } while (c != '\n'); - } else if (c == '*') { - while (1) { - c = getchar_no_eof(); - xputchar(c); - if (c == '*') { - do { - c = getchar_no_eof(); - xputchar(c); - } while (c == '*'); - if (c == '/') - break; - } - } - } - break; - case '"': - case '\'': - { - int delim = c; - do { - c = getchar_no_eof(); - xputchar(c); - if (c == '\\') { - c = getchar_no_eof(); - xputchar(c); - c = '\0'; - } - } while (c != delim); - } - break; - } - } -} - -/* Process the entire file. */ -static void -process_file(void) -{ - char *package, *name, *p, *n; - struct params *params, *rets; - int paramwid; - - package = read_package(); - read_preprocessor_lines(); - while (read_func_header(&name, ¶ms, ¶mwid, &rets)) { - // name may have a package override already - n = xstrstr(name, "·"); - if(n != nil) { - p = xmalloc(n - name + 1); - xmemmove(p, name, n - name); - p[n - name] = 0; - n += xstrlen("·"); - } else { - p = package; - n = name; - } - write_func_header(p, n, params, paramwid, rets); - copy_body(); - write_func_trailer(p, n, rets); - xfree(name); - if(p != package) xfree(p); - free_params(params); - free_params(rets); - } - xfree(package); -} - -void -goc2c(char *goc, char *c) -{ - int i; - Buf in, out; - - binit(&in); - binit(&out); - - file = goc; - readfile(&in, goc); - - // TODO: set gcc=1 when using gcc - - if(!gcc) { - if(streq(goarch, "amd64")) { - type_table[Uintptr].size = 8; - if(use64bitint) { - type_table[Int].size = 8; - } else { - type_table[Int].size = 4; - } - structround = 8; - } else if(streq(goarch, "amd64p32")) { - type_table[Uintptr].size = 4; - type_table[Int].size = 4; - structround = 8; - } else { - // NOTE: These are set in the initializer, - // but they might have been changed by a - // previous invocation of goc2c, so we have - // to restore them. - type_table[Uintptr].size = 4; - type_table[Int].size = 4; - structround = 4; - } - - type_table[Uint].size = type_table[Int].size; - type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size; - type_table[Eface].size = 2*type_table[Uintptr].size; - type_table[String].size = 2*type_table[Uintptr].size; - - for(i=0; i= ns && strcmp(p+np-ns, suffix) == 0; + return np >= ns && streq(p+np-ns, suffix); } // hasprefix reports whether p begins with prefix. diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c index 8b943a2d9..4a78684b4 100644 --- a/src/cmd/dist/unix.c +++ b/src/cmd/dist/unix.c @@ -431,7 +431,7 @@ xremoveall(char *p) } bfree(&b); - vfree(&dir); + vfree(&dir); } // xreaddir replaces dst with a list of the names of the files in dir. @@ -441,13 +441,13 @@ xreaddir(Vec *dst, char *dir) { DIR *d; struct dirent *dp; - + vreset(dst); d = opendir(dir); if(d == nil) fatal("opendir %s: %s", dir, strerror(errno)); while((dp = readdir(d)) != nil) { - if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + if(streq(dp->d_name, ".") || streq(dp->d_name, "..")) continue; vadd(dst, dp->d_name); } @@ -461,7 +461,7 @@ xworkdir(void) { Buf b; char *p; - + binit(&b); xgetenv(&b, "TMPDIR"); @@ -546,10 +546,10 @@ bool hassuffix(char *p, char *suffix) { int np, ns; - + np = strlen(p); ns = strlen(suffix); - return np >= ns && strcmp(p+np-ns, suffix) == 0; + return np >= ns && streq(p+np-ns, suffix); } // hasprefix reports whether p begins with prefix. @@ -712,7 +712,7 @@ main(int argc, char **argv) fatal("unknown architecture: %s", u.machine); } - if(strcmp(gohostarch, "arm") == 0) + if(streq(gohostarch, "arm")) maxnbg = 1; // The OS X 10.6 linker does not support external linking mode. @@ -724,7 +724,7 @@ main(int argc, char **argv) // // Roughly, OS X 10.N shows up as uname release (N+4), // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12. - if(strcmp(gohostos, "darwin") == 0) { + if(streq(gohostos, "darwin")) { if(uname(&u) < 0) fatal("uname: %s", strerror(errno)); osx = atoi(u.release) - 4; diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c index 2839c4bc5..ff1a27351 100644 --- a/src/cmd/dist/windows.c +++ b/src/cmd/dist/windows.c @@ -770,10 +770,10 @@ bool hassuffix(char *p, char *suffix) { int np, ns; - + np = strlen(p); ns = strlen(suffix); - return np >= ns && strcmp(p+np-ns, suffix) == 0; + return np >= ns && streq(p+np-ns, suffix); } bool @@ -929,7 +929,7 @@ xsamefile(char *f1, char *f2) return 1; torune(&ru, f1); - // refer to ../../pkg/os/stat_windows.go:/sameFile + // refer to ../../os/stat_windows.go:/sameFile fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); xfree(ru); if(fd1 == INVALID_HANDLE_VALUE) diff --git a/src/cmd/fix/doc.go b/src/cmd/fix/doc.go index 5de3e08c5..057016957 100644 --- a/src/cmd/fix/doc.go +++ b/src/cmd/fix/doc.go @@ -27,7 +27,7 @@ rewrites are idempotent, so that it is safe to apply fix to updated or partially updated code even without using the -r flag. Fix prints the full list of fixes it can apply in its help output; -to see them, run go tool fix -?. +to see them, run go tool fix -help. Fix does not make backup copies of the files that it edits. Instead, use a version control system's ``diff'' functionality to inspect diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go index a100be794..a07bbac79 100644 --- a/src/cmd/fix/fix.go +++ b/src/cmd/fix/fix.go @@ -101,7 +101,7 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) { case *[]ast.Stmt: walkBeforeAfter(*n, before, after) - // These are ordered and grouped to match ../../pkg/go/ast/ast.go + // These are ordered and grouped to match ../../go/ast/ast.go case *ast.Field: walkBeforeAfter(&n.Names, before, after) walkBeforeAfter(&n.Type, before, after) diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index b809640e4..6e5d149c7 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -119,8 +119,10 @@ dowidth(Type *t) if(t->width == -2) { lno = lineno; lineno = t->lineno; - if(!t->broke) + if(!t->broke) { + t->broke = 1; yyerror("invalid recursive type %T", t); + } t->width = 0; lineno = lno; return; diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors index 1f97fc8ce..fa74c67c3 100755 --- a/src/cmd/gc/bisonerrors +++ b/src/cmd/gc/bisonerrors @@ -22,6 +22,7 @@ BEGIN{ bison = 1 grammar = 0 states = 0 + open = 0 } # In Grammar section of y.output, @@ -130,11 +131,26 @@ $1 == "%" { continue # No shift or reduce applied - found the error. - printf("\t%s, %s,\n", state, tok); + printf("\t{%s, %s,\n", state, tok); + open = 1; break } next } # Print other lines verbatim. +open && /,$/ { + s = $0; + sub(",", "},", s) + print s + open = 0 + next +} + +open && /"$/ { + print $0 "}" + open = 0 + next +} + {print} diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 5ca5aeb77..fbca4ee5f 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -2,18 +2,19 @@ char *runtimeimport = "package runtime\n" "import runtime \"runtime\"\n" - "func @\"\".new (@\"\".typ·2 *byte) (? *any)\n" + "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" "func @\"\".panicindex ()\n" "func @\"\".panicslice ()\n" "func @\"\".panicdivide ()\n" "func @\"\".throwreturn ()\n" "func @\"\".throwinit ()\n" "func @\"\".panicwrap (? string, ? string, ? string)\n" - "func @\"\".panic (? interface {})\n" - "func @\"\".recover (? *int32) (? interface {})\n" + "func @\"\".gopanic (? interface {})\n" + "func @\"\".gorecover (? *int32) (? interface {})\n" "func @\"\".printbool (? bool)\n" "func @\"\".printfloat (? float64)\n" "func @\"\".printint (? int64)\n" + "func @\"\".printhex (? uint64)\n" "func @\"\".printuint (? uint64)\n" "func @\"\".printcomplex (? complex128)\n" "func @\"\".printstring (? string)\n" @@ -23,7 +24,6 @@ char *runtimeimport = "func @\"\".printslice (? any)\n" "func @\"\".printnl ()\n" "func @\"\".printsp ()\n" - "func @\"\".goprintf ()\n" "func @\"\".concatstring2 (? string, ? string) (? string)\n" "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n" "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n" @@ -39,7 +39,7 @@ char *runtimeimport = "func @\"\".stringtoslicerune (? string) (? []rune)\n" "func @\"\".stringiter (? string, ? int) (? int)\n" "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" - "func @\"\".copy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" + "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" "func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" @@ -64,7 +64,6 @@ char *runtimeimport = "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" - "func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n" "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n" "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" @@ -83,10 +82,18 @@ char *runtimeimport = "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" "func @\"\".closechan (@\"\".hchan·1 any)\n" + "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" + "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" + "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" + "func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" - "func @\"\".newselect (@\"\".size·2 int32) (@\"\".sel·1 *byte)\n" + "func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n" "func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" "func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" "func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n" @@ -96,12 +103,12 @@ char *runtimeimport = "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n" "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n" - "func @\"\".memequal (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal8 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal16 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal32 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal64 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal128 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" + "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" + "func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" + "func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" + "func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" + "func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" + "func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" "func @\"\".int64div (? int64, ? int64) (? int64)\n" "func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n" "func @\"\".int64mod (? int64, ? int64) (? int64)\n" diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c index 0e8f8d473..cfd1cd281 100644 --- a/src/cmd/gc/bv.c +++ b/src/cmd/gc/bv.c @@ -108,6 +108,9 @@ bvnext(Bvec *bv, int32 i) { uint32 w; + if(i >= bv->n) + return -1; + // Jump i ahead to next word with bits. if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) { i &= ~WORDMASK; @@ -117,7 +120,7 @@ bvnext(Bvec *bv, int32 i) } if(i >= bv->n) return -1; - + // Find 1 bit. w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK); while((w&1) == 0) { diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index 143c1730d..e418b9c56 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -6,6 +6,7 @@ #include #include "go.h" #define TUP(x,y) (((x)<<16)|(y)) +/*c2go int TUP(int, int); */ static Val tocplx(Val); static Val toflt(Val); @@ -1565,7 +1566,6 @@ isgoconst(Node *n) case ORSH: case OSUB: case OXOR: - case OCONV: case OIOTA: case OCOMPLEX: case OREAL: @@ -1573,7 +1573,12 @@ isgoconst(Node *n) if(isgoconst(n->left) && (n->right == N || isgoconst(n->right))) return 1; break; - + + case OCONV: + if(okforconst[n->type->etype] && isgoconst(n->left)) + return 1; + break; + case OLEN: case OCAP: l = n->left; diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 73c2581be..dfcf47520 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -488,6 +488,10 @@ colasdefn(NodeList *left, Node *defn) NodeList *l; Node *n; + for(l=left; l; l=l->next) + if(l->n->sym != S) + l->n->sym->flags |= SymUniq; + nnew = 0; nerr = 0; for(l=left; l; l=l->next) { @@ -499,6 +503,13 @@ colasdefn(NodeList *left, Node *defn) nerr++; continue; } + if((n->sym->flags & SymUniq) == 0) { + yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym); + n->diag++; + nerr++; + continue; + } + n->sym->flags &= ~SymUniq; if(n->sym->block == block) continue; @@ -547,6 +558,9 @@ ifacedcl(Node *n) if(n->op != ODCLFIELD || n->right == N) fatal("ifacedcl"); + if(isblank(n->left)) + yyerror("methods must have a unique non-blank name"); + dclcontext = PPARAM; markdcl(); funcdepth++; diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index 78624d7cb..324f24fcf 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -495,7 +495,7 @@ esc(EscState *e, Node *n, Node *up) case ORANGE: // Everything but fixed array is a dereference. - if(isfixedarray(n->type) && n->list->next) + if(isfixedarray(n->type) && n->list && n->list->next) escassign(e, n->list->next->n, n->right); break; @@ -1110,6 +1110,7 @@ escflood(EscState *e, Node *dst) // pass all the tests we have written so far, which we assume matches // the level of complexity we want the escape analysis code to handle. #define MinLevel (-2) +/*c2go enum { MinLevel = -2 };*/ static void escwalk(EscState *e, int level, Node *dst, Node *src) diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index b5f8a834f..89d2a1404 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -649,7 +649,7 @@ typefmt(Fmt *fp, Type *t) if(t->funarg) { fmtstrcpy(fp, "("); - if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape" tags + if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape"/"nosplit" tags for(t1=t->type; t1!=T; t1=t1->down) if(t1->down) fmtprint(fp, "%hT, ", t1); @@ -810,6 +810,13 @@ stmtfmt(Fmt *f, Node *n) break; case OASOP: + if(n->implicit) { + if(n->etype == OADD) + fmtprint(f, "%N++", n->left); + else + fmtprint(f, "%N--", n->left); + break; + } fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right); break; @@ -880,7 +887,11 @@ stmtfmt(Fmt *f, Node *n) fmtstrcpy(f, "for loop"); break; } - + + if(n->list == nil) { + fmtprint(f, "for range %N { %H }", n->right, n->nbody); + break; + } fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody); break; @@ -974,7 +985,6 @@ static int opprec[] = { [OTFUNC] = 8, [OTINTER] = 8, [OTMAP] = 8, - [OTPAREN] = 8, [OTSTRUCT] = 8, [OINDEXMAP] = 8, @@ -1105,16 +1115,11 @@ exprfmt(Fmt *f, Node *n, int prec) case ONAME: // Special case: name used as local variable in export. - switch(n->class&~PHEAP){ - case PAUTO: - case PPARAM: - case PPARAMOUT: - // _ becomes ~b%d internally; print as _ for export - if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') - return fmtprint(f, "_"); - if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) - return fmtprint(f, "%S·%d", n->sym, n->vargen); - } + // _ becomes ~b%d internally; print as _ for export + if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') + return fmtprint(f, "_"); + if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) + return fmtprint(f, "%S·%d", n->sym, n->vargen); // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, // but for export, this should be rendered as (*pkg.T).meth. @@ -1140,9 +1145,6 @@ exprfmt(Fmt *f, Node *n, int prec) return fmtprint(f, "[]%N", n->left); return fmtprint(f, "[]%N", n->right); // happens before typecheck - case OTPAREN: - return fmtprint(f, "(%N)", n->left); - case OTMAP: return fmtprint(f, "map[%N]%N", n->left, n->right); @@ -1153,7 +1155,7 @@ exprfmt(Fmt *f, Node *n, int prec) case Csend: return fmtprint(f, "chan<- %N", n->left); default: - if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv) + if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) return fmtprint(f, "chan (%N)", n->left); else return fmtprint(f, "chan %N", n->left); diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index cf630f348..c7c9fcdaf 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -54,9 +54,6 @@ addrescapes(Node *n) if(n->class == PAUTO && n->esc == EscNever) break; - if(debug['N'] && n->esc != EscUnknown) - fatal("without escape analysis, only PAUTO's should have esc: %N", n); - switch(n->class) { case PPARAMREF: addrescapes(n->defn); @@ -91,8 +88,7 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->orig->sym = n->heapaddr->sym; - if(!debug['N']) - n->esc = EscHeap; + n->esc = EscHeap; if(debug['m']) print("%L: moved to heap: %N\n", n->lineno, n); curfn = oldfn; @@ -584,6 +580,8 @@ cgen_dcl(Node *n) } if(!(n->class & PHEAP)) return; + if(compiling_runtime) + yyerror("%N escapes to heap, not allowed in runtime.", n); if(n->alloc == nil) n->alloc = callnew(n->type); cgen_as(n->heapaddr, n->alloc); @@ -733,14 +731,10 @@ cgen_as(Node *nl, Node *nr) return; } - if(nr == N || isnil(nr)) { - // externals and heaps should already be clear - if(nr == N) { - if(nl->class == PEXTERN) - return; - if(nl->class & PHEAP) - return; - } + if(nr == N || iszero(nr)) { + // heaps should already be clear + if(nr == N && (nl->class & PHEAP)) + return; tl = nl->type; if(tl == T) @@ -804,7 +798,8 @@ cgen_eface(Node *n, Node *res) void cgen_slice(Node *n, Node *res) { - Node src, dst, *cap, *len, *offs, *add, *base; + Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con; + Prog *p1, *p2; cap = n->list->n; len = n->list->next->n; @@ -821,6 +816,11 @@ cgen_slice(Node *n, Node *res) // garbage collector can see. base = temp(types[TUINTPTR]); + tmplen = temp(types[TINT]); + if(n->op != OSLICESTR) + tmpcap = temp(types[TINT]); + else + tmpcap = tmplen; if(isnil(n->left)) { tempname(&src, n->left->type); @@ -835,43 +835,62 @@ cgen_slice(Node *n, Node *res) fatal("slicearr is supposed to work on pointer: %+N\n", n); cgen(&src, base); cgen_checknil(base); - if(offs != N) { - add = nod(OADD, base, offs); - typecheck(&add, Erv); - cgen(add, base); - } - } else if(offs == N) { - src.type = types[tptr]; - cgen(&src, base); } else { src.type = types[tptr]; - add = nod(OADDPTR, &src, offs); - typecheck(&add, Erv); - cgen(add, base); + cgen(&src, base); } // committed to the update gvardef(res); + // compute len and cap. + // len = n-i, cap = m-i, and offs = i*width. + // computing offs last lets the multiply overwrite i. + cgen(len, tmplen); + if(n->op != OSLICESTR) + cgen(cap, tmpcap); + + // if new cap != 0 { base += add } + // This avoids advancing base past the end of the underlying array/string, + // so that it cannot point at the next object in memory. + // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. + // In essence we are replacing x[i:j:k] where i == j == k + // or x[i:j] where i == j == cap(x) with x[0:0:0]. + if(offs != N) { + p1 = gjmp(P); + p2 = gjmp(P); + patch(p1, pc); + + nodconst(&con, tmpcap->type, 0); + cmp = nod(OEQ, tmpcap, &con); + typecheck(&cmp, Erv); + bgen(cmp, 1, -1, p2); + + add = nod(OADD, base, offs); + typecheck(&add, Erv); + cgen(add, base); + + patch(p2, pc); + } + // dst.array = src.array [ + lo *width ] dst = *res; dst.xoffset += Array_array; dst.type = types[tptr]; - cgen(base, &dst); // dst.len = hi [ - lo ] dst = *res; dst.xoffset += Array_nel; dst.type = types[simtype[TUINT]]; - cgen(len, &dst); + cgen(tmplen, &dst); if(n->op != OSLICESTR) { // dst.cap = cap [ - lo ] dst = *res; dst.xoffset += Array_cap; dst.type = types[simtype[TUINT]]; - cgen(cap, &dst); + cgen(tmpcap, &dst); } } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index ee879f67f..965a0550d 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -269,6 +269,7 @@ struct Node uchar colas; // OAS resulting from := uchar diag; // already printed error about this uchar noescape; // func arguments do not escape + uchar nosplit; // func should not execute on separate stack uchar builtin; // built-in name, like len or close uchar walkdef; uchar typecheck; @@ -282,6 +283,7 @@ struct Node uchar addrtaken; // address taken, even if not moved to heap uchar dupok; // duplicate definitions ok (for func) uchar wrapper; // is method wrapper (for func) + uchar reslice; // this is a reslice x = x[0:y] or x = append(x, ...) schar likely; // likeliness of if statement uchar hasbreak; // has break statement uchar needzero; // if it contains pointers, needs to be zeroed on function entry @@ -380,7 +382,6 @@ enum SymExported = 1<<2, // already written out by export SymUniq = 1<<3, SymSiggen = 1<<4, - SymGcgen = 1<<5, }; struct Sym @@ -447,7 +448,6 @@ enum OSUB, // x - y OOR, // x | y OXOR, // x ^ y - OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen OADDSTR, // s + "foo" OADDR, // &x OANDAND, // b0 && b1 @@ -573,7 +573,6 @@ enum OTINTER, // interface{} OTFUNC, // func() OTARRAY, // []int, [8]int, [N]int or [...]int - OTPAREN, // (T) // misc ODDD, // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}. @@ -975,11 +974,13 @@ EXTERN int funcdepth; EXTERN int typecheckok; EXTERN int compiling_runtime; EXTERN int compiling_wrappers; +EXTERN int use_writebarrier; EXTERN int pure_go; EXTERN char* flag_installsuffix; EXTERN int flag_race; EXTERN int flag_largemodel; EXTERN int noescape; +EXTERN int nosplit; EXTERN int debuglive; EXTERN Link* ctxt; @@ -1169,6 +1170,7 @@ void cgen_callmeth(Node *n, int proc); void cgen_eface(Node* n, Node* res); void cgen_slice(Node* n, Node* res); void clearlabels(void); +void clearslim(Node*); void checklabels(void); int dotoffset(Node *n, int64 *oary, Node **nn); void gen(Node *n); @@ -1284,6 +1286,7 @@ LSym* linksym(Sym*); * order.c */ void order(Node *fn); +void orderstmtinplace(Node **stmt); /* * range.c @@ -1302,7 +1305,6 @@ Sym* typenamesym(Type *t); Sym* tracksym(Type *t); Sym* typesymprefix(char *prefix, Type *t); int haspointers(Type *t); -void usefield(Node*); Type* hiter(Type* t); /* @@ -1364,6 +1366,7 @@ int is64(Type *t); int isbadimport(Strlit *s); int isblank(Node *n); int isblanksym(Sym *s); +int isdirectiface(Type*); int isfixedarray(Type *t); int isideal(Type *t); int isinter(Type *t); @@ -1372,6 +1375,7 @@ int isnilinter(Type *t); int isptrto(Type *t, int et); int isslice(Type *t); int istype(Type *t, int et); +int iszero(Node *n); void linehist(char *file, int32 off, int relative); NodeList* list(NodeList *l, Node *n); NodeList* list1(Node *n); @@ -1464,7 +1468,9 @@ void walkstmt(Node **np); void walkstmtlist(NodeList *l); Node* conv(Node*, Type*); int candiscard(Node*); +int needwritebarrier(Node*, Node*); Node* outervalue(Node*); +void usefield(Node*); /* * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c @@ -1505,7 +1511,7 @@ void gdata(Node*, Node*, int); void gdatacomplex(Node*, Mpcplx*); void gdatastring(Node*, Strlit*); void ggloblnod(Node *nam); -void ggloblsym(Sym *s, int32 width, int dupok, int rodata); +void ggloblsym(Sym *s, int32 width, int8 flags); void gvardef(Node*); void gvarkill(Node*); Prog* gjmp(Prog*); @@ -1514,6 +1520,7 @@ void movelarge(NodeList*); int isfat(Type*); void linkarchinit(void); void liveness(Node*, Prog*, Sym*, Sym*); +void twobitwalktype1(Type*, vlong*, Bvec*); void markautoused(Prog*); Plist* newplist(void); Node* nodarg(Type*, int); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 2f354f723..68fccc1ad 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -460,11 +460,13 @@ simple_stmt: | expr LINC { $$ = nod(OASOP, $1, nodintconst(1)); + $$->implicit = 1; $$->etype = OADD; } | expr LDEC { $$ = nod(OASOP, $1, nodintconst(1)); + $$->implicit = 1; $$->etype = OSUB; } @@ -613,6 +615,11 @@ range_stmt: $$->colas = 1; colasdefn($1, $$); } +| LRANGE expr + { + $$ = nod(ORANGE, N, $2); + $$->etype = 0; // := flag + } for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt @@ -1180,7 +1187,7 @@ ntype: | dotname | '(' ntype ')' { - $$ = nod(OTPAREN, $2, N); + $$ = $2; } non_expr_type: @@ -1199,7 +1206,7 @@ non_recvchantype: | dotname | '(' ntype ')' { - $$ = nod(OTPAREN, $2, N); + $$ = $2; } convtype: @@ -1311,6 +1318,7 @@ xfndcl: $$->nbody = $3; $$->endlineno = lineno; $$->noescape = noescape; + $$->nosplit = nosplit; funcbody($$); } @@ -1365,8 +1373,6 @@ fndcl: yyerror("bad receiver in method"); break; } - if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) - yyerror("cannot parenthesize receiver type"); t = nod(OTFUNC, rcvr, N); t->list = $6; @@ -1495,6 +1501,7 @@ xdcl_list: testdclstack(); nointerface = 0; noescape = 0; + nosplit = 0; } vardcl_list: diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index a50101c42..523ba37aa 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -45,7 +45,7 @@ static struct { }; // Debug arguments. -// These can be specified with the -d flag, as in "-d checknil" +// 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. static struct { @@ -139,6 +139,8 @@ yy_isalnum(int c) #define isalnum use_yy_isalnum_instead_of_isalnum #define DBG if(!debug['x']){}else print +/*c2go void DBG(char*, ...); */ + enum { EOF = -1, @@ -310,6 +312,8 @@ main(int argc, char *argv[]) flagcount("u", "reject unsafe code", &safemode); flagcount("v", "increase debug verbosity", &debug['v']); flagcount("w", "debug type checking", &debug['w']); + use_writebarrier = 1; + flagcount("wb", "enable write barrier", &use_writebarrier); flagcount("x", "debug lexer", &debug['x']); flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']); if(thechar == '6') @@ -317,6 +321,7 @@ main(int argc, char *argv[]) flagparse(&argc, &argv, usage); ctxt->debugasm = debug['S']; + ctxt->debugvlog = debug['v']; if(argc < 1) usage(); @@ -339,8 +344,8 @@ main(int argc, char *argv[]) break; } } - if(j == nelem(debugtab)) - fatal("unknown debug information -d '%s'\n", f[i]); + if(debugtab[j].name == nil) + sysfatal("unknown debug information -d '%s'\n", f[i]); } } @@ -476,8 +481,12 @@ main(int argc, char *argv[]) } // Phase 5: Escape analysis. - if(!debug['N']) - escapes(xtop); + // 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. + escapes(xtop); // Escape analysis moved escaped values off stack. // Move large values off stack too. @@ -516,24 +525,18 @@ saveerrors(void) nerrors = 0; } -/* - * macro to portably read/write archive header. - * 'cmd' is read/write/Bread/Bwrite, etc. - */ -#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ - || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ - || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ - || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ - || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ - || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ - || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) - static int arsize(Biobuf *b, char *name) { struct ar_hdr a; - if (HEADER_IO(Bread, b, a)) + if(Bread(b, a.name, sizeof(a.name)) != sizeof(a.name) || + Bread(b, a.date, sizeof(a.date)) != sizeof(a.date) || + Bread(b, a.uid, sizeof(a.uid)) != sizeof(a.uid) || + Bread(b, a.gid, sizeof(a.gid)) != sizeof(a.gid) || + Bread(b, a.mode, sizeof(a.mode)) != sizeof(a.mode) || + Bread(b, a.size, sizeof(a.size)) != sizeof(a.size) || + Bread(b, a.fmag, sizeof(a.fmag)) != sizeof(a.fmag)) return -1; if(strncmp(a.name, name, strlen(name)) != 0) @@ -1592,6 +1595,10 @@ go: noescape = 1; goto out; } + if(strcmp(lexbuf, "go:nosplit") == 0) { + nosplit = 1; + goto out; + } out: return c; @@ -1854,74 +1861,74 @@ static struct /* name lexical etype op */ /* basic types */ - "int8", LNAME, TINT8, OXXX, - "int16", LNAME, TINT16, OXXX, - "int32", LNAME, TINT32, OXXX, - "int64", LNAME, TINT64, OXXX, - - "uint8", LNAME, TUINT8, OXXX, - "uint16", LNAME, TUINT16, OXXX, - "uint32", LNAME, TUINT32, OXXX, - "uint64", LNAME, TUINT64, OXXX, - - "float32", LNAME, TFLOAT32, OXXX, - "float64", LNAME, TFLOAT64, OXXX, - - "complex64", LNAME, TCOMPLEX64, OXXX, - "complex128", LNAME, TCOMPLEX128, OXXX, - - "bool", LNAME, TBOOL, OXXX, - "string", LNAME, TSTRING, OXXX, - - "any", LNAME, TANY, OXXX, - - "break", LBREAK, Txxx, OXXX, - "case", LCASE, Txxx, OXXX, - "chan", LCHAN, Txxx, OXXX, - "const", LCONST, Txxx, OXXX, - "continue", LCONTINUE, Txxx, OXXX, - "default", LDEFAULT, Txxx, OXXX, - "else", LELSE, Txxx, OXXX, - "defer", LDEFER, Txxx, OXXX, - "fallthrough", LFALL, Txxx, OXXX, - "for", LFOR, Txxx, OXXX, - "func", LFUNC, Txxx, OXXX, - "go", LGO, Txxx, OXXX, - "goto", LGOTO, Txxx, OXXX, - "if", LIF, Txxx, OXXX, - "import", LIMPORT, Txxx, OXXX, - "interface", LINTERFACE, Txxx, OXXX, - "map", LMAP, Txxx, OXXX, - "package", LPACKAGE, Txxx, OXXX, - "range", LRANGE, Txxx, OXXX, - "return", LRETURN, Txxx, OXXX, - "select", LSELECT, Txxx, OXXX, - "struct", LSTRUCT, Txxx, OXXX, - "switch", LSWITCH, Txxx, OXXX, - "type", LTYPE, Txxx, OXXX, - "var", LVAR, Txxx, OXXX, - - "append", LNAME, Txxx, OAPPEND, - "cap", LNAME, Txxx, OCAP, - "close", LNAME, Txxx, OCLOSE, - "complex", LNAME, Txxx, OCOMPLEX, - "copy", LNAME, Txxx, OCOPY, - "delete", LNAME, Txxx, ODELETE, - "imag", LNAME, Txxx, OIMAG, - "len", LNAME, Txxx, OLEN, - "make", LNAME, Txxx, OMAKE, - "new", LNAME, Txxx, ONEW, - "panic", LNAME, Txxx, OPANIC, - "print", LNAME, Txxx, OPRINT, - "println", LNAME, Txxx, OPRINTN, - "real", LNAME, Txxx, OREAL, - "recover", LNAME, Txxx, ORECOVER, - - "notwithstanding", LIGNORE, Txxx, OXXX, - "thetruthofthematter", LIGNORE, Txxx, OXXX, - "despiteallobjections", LIGNORE, Txxx, OXXX, - "whereas", LIGNORE, Txxx, OXXX, - "insofaras", LIGNORE, Txxx, OXXX, + {"int8", LNAME, TINT8, OXXX}, + {"int16", LNAME, TINT16, OXXX}, + {"int32", LNAME, TINT32, OXXX}, + {"int64", LNAME, TINT64, OXXX}, + + {"uint8", LNAME, TUINT8, OXXX}, + {"uint16", LNAME, TUINT16, OXXX}, + {"uint32", LNAME, TUINT32, OXXX}, + {"uint64", LNAME, TUINT64, OXXX}, + + {"float32", LNAME, TFLOAT32, OXXX}, + {"float64", LNAME, TFLOAT64, OXXX}, + + {"complex64", LNAME, TCOMPLEX64, OXXX}, + {"complex128", LNAME, TCOMPLEX128, OXXX}, + + {"bool", LNAME, TBOOL, OXXX}, + {"string", LNAME, TSTRING, OXXX}, + + {"any", LNAME, TANY, OXXX}, + + {"break", LBREAK, Txxx, OXXX}, + {"case", LCASE, Txxx, OXXX}, + {"chan", LCHAN, Txxx, OXXX}, + {"const", LCONST, Txxx, OXXX}, + {"continue", LCONTINUE, Txxx, OXXX}, + {"default", LDEFAULT, Txxx, OXXX}, + {"else", LELSE, Txxx, OXXX}, + {"defer", LDEFER, Txxx, OXXX}, + {"fallthrough", LFALL, Txxx, OXXX}, + {"for", LFOR, Txxx, OXXX}, + {"func", LFUNC, Txxx, OXXX}, + {"go", LGO, Txxx, OXXX}, + {"goto", LGOTO, Txxx, OXXX}, + {"if", LIF, Txxx, OXXX}, + {"import", LIMPORT, Txxx, OXXX}, + {"interface", LINTERFACE, Txxx, OXXX}, + {"map", LMAP, Txxx, OXXX}, + {"package", LPACKAGE, Txxx, OXXX}, + {"range", LRANGE, Txxx, OXXX}, + {"return", LRETURN, Txxx, OXXX}, + {"select", LSELECT, Txxx, OXXX}, + {"struct", LSTRUCT, Txxx, OXXX}, + {"switch", LSWITCH, Txxx, OXXX}, + {"type", LTYPE, Txxx, OXXX}, + {"var", LVAR, Txxx, OXXX}, + + {"append", LNAME, Txxx, OAPPEND}, + {"cap", LNAME, Txxx, OCAP}, + {"close", LNAME, Txxx, OCLOSE}, + {"complex", LNAME, Txxx, OCOMPLEX}, + {"copy", LNAME, Txxx, OCOPY}, + {"delete", LNAME, Txxx, ODELETE}, + {"imag", LNAME, Txxx, OIMAG}, + {"len", LNAME, Txxx, OLEN}, + {"make", LNAME, Txxx, OMAKE}, + {"new", LNAME, Txxx, ONEW}, + {"panic", LNAME, Txxx, OPANIC}, + {"print", LNAME, Txxx, OPRINT}, + {"println", LNAME, Txxx, OPRINTN}, + {"real", LNAME, Txxx, OREAL}, + {"recover", LNAME, Txxx, ORECOVER}, + + {"notwithstanding", LIGNORE, Txxx, OXXX}, + {"thetruthofthematter", LIGNORE, Txxx, OXXX}, + {"despiteallobjections", LIGNORE, Txxx, OXXX}, + {"whereas", LIGNORE, Txxx, OXXX}, + {"insofaras", LIGNORE, Txxx, OXXX}, }; static void @@ -2171,50 +2178,50 @@ struct char* name; } lexn[] = { - LANDAND, "ANDAND", - LANDNOT, "ANDNOT", - LASOP, "ASOP", - LBREAK, "BREAK", - LCASE, "CASE", - LCHAN, "CHAN", - LCOLAS, "COLAS", - LCOMM, "<-", - LCONST, "CONST", - LCONTINUE, "CONTINUE", - LDDD, "...", - LDEC, "DEC", - LDEFAULT, "DEFAULT", - LDEFER, "DEFER", - LELSE, "ELSE", - LEQ, "EQ", - LFALL, "FALL", - LFOR, "FOR", - LFUNC, "FUNC", - LGE, "GE", - LGO, "GO", - LGOTO, "GOTO", - LGT, "GT", - LIF, "IF", - LIMPORT, "IMPORT", - LINC, "INC", - LINTERFACE, "INTERFACE", - LLE, "LE", - LLITERAL, "LITERAL", - LLSH, "LSH", - LLT, "LT", - LMAP, "MAP", - LNAME, "NAME", - LNE, "NE", - LOROR, "OROR", - LPACKAGE, "PACKAGE", - LRANGE, "RANGE", - LRETURN, "RETURN", - LRSH, "RSH", - LSELECT, "SELECT", - LSTRUCT, "STRUCT", - LSWITCH, "SWITCH", - LTYPE, "TYPE", - LVAR, "VAR", + {LANDAND, "ANDAND"}, + {LANDNOT, "ANDNOT"}, + {LASOP, "ASOP"}, + {LBREAK, "BREAK"}, + {LCASE, "CASE"}, + {LCHAN, "CHAN"}, + {LCOLAS, "COLAS"}, + {LCOMM, "<-"}, + {LCONST, "CONST"}, + {LCONTINUE, "CONTINUE"}, + {LDDD, "..."}, + {LDEC, "DEC"}, + {LDEFAULT, "DEFAULT"}, + {LDEFER, "DEFER"}, + {LELSE, "ELSE"}, + {LEQ, "EQ"}, + {LFALL, "FALL"}, + {LFOR, "FOR"}, + {LFUNC, "FUNC"}, + {LGE, "GE"}, + {LGO, "GO"}, + {LGOTO, "GOTO"}, + {LGT, "GT"}, + {LIF, "IF"}, + {LIMPORT, "IMPORT"}, + {LINC, "INC"}, + {LINTERFACE, "INTERFACE"}, + {LLE, "LE"}, + {LLITERAL, "LITERAL"}, + {LLSH, "LSH"}, + {LLT, "LT"}, + {LMAP, "MAP"}, + {LNAME, "NAME"}, + {LNE, "NE"}, + {LOROR, "OROR"}, + {LPACKAGE, "PACKAGE"}, + {LRANGE, "RANGE"}, + {LRETURN, "RETURN"}, + {LRSH, "RSH"}, + {LSELECT, "SELECT"}, + {LSTRUCT, "STRUCT"}, + {LSWITCH, "SWITCH"}, + {LTYPE, "TYPE"}, + {LVAR, "VAR"}, }; char* @@ -2236,56 +2243,56 @@ struct char *want; } yytfix[] = { - "$end", "EOF", - "LLITERAL", "literal", - "LASOP", "op=", - "LBREAK", "break", - "LCASE", "case", - "LCHAN", "chan", - "LCOLAS", ":=", - "LCONST", "const", - "LCONTINUE", "continue", - "LDDD", "...", - "LDEFAULT", "default", - "LDEFER", "defer", - "LELSE", "else", - "LFALL", "fallthrough", - "LFOR", "for", - "LFUNC", "func", - "LGO", "go", - "LGOTO", "goto", - "LIF", "if", - "LIMPORT", "import", - "LINTERFACE", "interface", - "LMAP", "map", - "LNAME", "name", - "LPACKAGE", "package", - "LRANGE", "range", - "LRETURN", "return", - "LSELECT", "select", - "LSTRUCT", "struct", - "LSWITCH", "switch", - "LTYPE", "type", - "LVAR", "var", - "LANDAND", "&&", - "LANDNOT", "&^", - "LBODY", "{", - "LCOMM", "<-", - "LDEC", "--", - "LINC", "++", - "LEQ", "==", - "LGE", ">=", - "LGT", ">", - "LLE", "<=", - "LLT", "<", - "LLSH", "<<", - "LRSH", ">>", - "LOROR", "||", - "LNE", "!=", + {"$end", "EOF"}, + {"LLITERAL", "literal"}, + {"LASOP", "op="}, + {"LBREAK", "break"}, + {"LCASE", "case"}, + {"LCHAN", "chan"}, + {"LCOLAS", ":="}, + {"LCONST", "const"}, + {"LCONTINUE", "continue"}, + {"LDDD", "..."}, + {"LDEFAULT", "default"}, + {"LDEFER", "defer"}, + {"LELSE", "else"}, + {"LFALL", "fallthrough"}, + {"LFOR", "for"}, + {"LFUNC", "func"}, + {"LGO", "go"}, + {"LGOTO", "goto"}, + {"LIF", "if"}, + {"LIMPORT", "import"}, + {"LINTERFACE", "interface"}, + {"LMAP", "map"}, + {"LNAME", "name"}, + {"LPACKAGE", "package"}, + {"LRANGE", "range"}, + {"LRETURN", "return"}, + {"LSELECT", "select"}, + {"LSTRUCT", "struct"}, + {"LSWITCH", "switch"}, + {"LTYPE", "type"}, + {"LVAR", "var"}, + {"LANDAND", "&&"}, + {"LANDNOT", "&^"}, + {"LBODY", "{"}, + {"LCOMM", "<-"}, + {"LDEC", "--"}, + {"LINC", "++"}, + {"LEQ", "=="}, + {"LGE", ">="}, + {"LGT", ">"}, + {"LLE", "<="}, + {"LLT", "<"}, + {"LLSH", "<<"}, + {"LRSH", ">>"}, + {"LOROR", "||"}, + {"LNE", "!="}, // spell out to avoid confusion with punctuation in error messages - "';'", "semicolon or newline", - "','", "comma", + {"';'", "semicolon or newline"}, + {"','", "comma"}, }; static void diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c index 0051ac964..46cb6b712 100644 --- a/src/cmd/gc/md5.c +++ b/src/cmd/gc/md5.c @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // 64-bit MD5 (does full MD5 but returns 64 bits only). -// Translation of ../../pkg/crypto/md5/md5*.go. +// Translation of ../../crypto/md5/md5*.go. #include #include @@ -20,7 +20,15 @@ enum { #define _Init1 0xEFCDAB89 #define _Init2 0x98BADCFE #define _Init3 0x10325476 - +/*c2go +enum { + _Init0 = 0x67452301, + _Init1 = 0xEFCDAB89, + _Init2 = 0x98BADCFE, + _Init3 = 0x10325476 +}; +*/ + void md5reset(MD5 *d) { diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index 1519caec7..d33a81e09 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -591,7 +591,7 @@ Fconv(Fmt *fp) d = mpgetflt(fvp); if(d >= 0 && (fp->flags & FmtSign)) fmtprint(fp, "+"); - return fmtprint(fp, "%g", d, exp, fvp); + return fmtprint(fp, "%g", d); } // very out of range. compute decimal approximation by hand. diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index 5cf98c62c..fd9f591ce 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -656,7 +656,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) } static int -iszero(Mpint *a) +mpiszero(Mpint *a) { long *a1; int i; @@ -687,7 +687,7 @@ mpdivfract(Mpint *a, Mpint *b) for(j=0; j prec+1) s = prec+1; - if((v & ((1<>= s; e = minexp; } diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 4eeb03aa8..b752a13ce 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -5,6 +5,7 @@ #include #include #include "go.h" +#include "../ld/textflag.h" /* * architecture-independent object file output @@ -84,7 +85,7 @@ dumpobj(void) externdcl = tmp; zero = pkglookup("zerovalue", runtimepkg); - ggloblsym(zero, zerosize, 1, 1); + ggloblsym(zero, zerosize, DUPOK|RODATA); dumpdata(); writeobj(ctxt, bout); @@ -128,7 +129,7 @@ dumpglobls(void) for(l=funcsyms; l; l=l->next) { n = l->n; dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0); - ggloblsym(n->sym, widthptr, 1, 1); + ggloblsym(n->sym, widthptr, DUPOK|RODATA); } // Do not reprocess funcsyms on next dumpglobls call. @@ -249,7 +250,7 @@ stringsym(char *s, int len) } off = duint8(sym, off, 0); // terminating NUL for runtime off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment - ggloblsym(sym, off, 1, 1); + ggloblsym(sym, off, DUPOK|RODATA); return sym; } @@ -272,7 +273,7 @@ slicebytes(Node *nam, char *s, int len) m = len-n; off = dsname(sym, off, s+n, m); } - ggloblsym(sym, off, 0, 0); + ggloblsym(sym, off, NOPTR); if(nam->op != ONAME) fatal("slicebytes %N", nam); diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 30dbc7dac..76820fde7 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -317,7 +317,7 @@ orderexprinplace(Node **np, Order *outer) // Orderstmtinplace orders the side effects of the single statement *np // and replaces it with the resulting statement list. -static void +void orderstmtinplace(Node **np) { Node *n; @@ -438,6 +438,9 @@ ordercall(Node *n, Order *order) // cases they are also typically registerizable, so not much harm done. // And this only applies to the multiple-assignment form. // We could do a more precise analysis if needed, like in walk.c. +// +// Ordermapassign also inserts these temporaries if needed for +// calling writebarrierfat with a pointer to n->right. static void ordermapassign(Node *n, Order *order) { @@ -451,7 +454,8 @@ ordermapassign(Node *n, Order *order) case OAS: order->out = list(order->out, n); - if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) { + // We call writebarrierfat only for values > 4 pointers long. See walk.c. + if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) { m = n->left; n->left = ordertemp(m->type, order, 0); a = nod(OAS, m, n->left); @@ -593,7 +597,10 @@ orderstmt(Node *n, Order *order) orderexpr(&n->rlist->n->left, order); // arg to recv ch = n->rlist->n->left->type; tmp1 = ordertemp(ch->type, order, haspointers(ch->type)); - tmp2 = ordertemp(types[TBOOL], order, 0); + if(!isblank(n->list->next->n)) + tmp2 = ordertemp(n->list->next->n->type, order, 0); + else + tmp2 = ordertemp(types[TBOOL], order, 0); order->out = list(order->out, n); r = nod(OAS, n->list->n, tmp1); typecheck(&r, Etop); @@ -768,6 +775,12 @@ orderstmt(Node *n, Order *order) // Special: clean case temporaries in each block entry. // Select must enter one of its blocks, so there is no // need for a cleaning at the end. + // Doubly special: evaluation order for select is stricter + // than ordinary expressions. Even something like p.c + // has to be hoisted into a temporary, so that it cannot be + // reordered after the channel evaluation for a different + // case (if p were nil, then the timing of the fault would + // give this away). t = marktemp(order); for(l=n->list; l; l=l->next) { if(l->n->op != OXCASE) @@ -810,6 +823,8 @@ orderstmt(Node *n, Order *order) // r->left == N means 'case <-c'. // c is always evaluated; x and ok are only evaluated when assigned. orderexpr(&r->right->left, order); + if(r->right->left->op != ONAME) + r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0); // Introduce temporary for receive and move actual copy into case body. // avoids problems with target being addressed, as usual. @@ -1017,11 +1032,21 @@ orderexpr(Node **np, Order *order) orderexprinplace(&n->right, order); break; + case OAPPEND: case OCALLFUNC: - case OCALLMETH: case OCALLINTER: - case OAPPEND: + case OCALLMETH: + case OCAP: case OCOMPLEX: + case OCOPY: + case OIMAG: + case OLEN: + case OMAKECHAN: + case OMAKEMAP: + case OMAKESLICE: + case ONEW: + case OREAL: + case ORECOVER: ordercall(n, order); n = ordercopyexpr(n, n->type, order, 0); break; @@ -1055,6 +1080,19 @@ orderexpr(Node **np, Order *order) orderexpr(&n->left, order); n = ordercopyexpr(n, n->type, order, 1); break; + + case OEQ: + case ONE: + orderexpr(&n->left, order); + orderexpr(&n->right, order); + t = n->left->type; + if(t->etype == TSTRUCT || isfixedarray(t)) { + // for complex comparisons, we need both args to be + // addressable so we can pass them to the runtime. + orderaddrtemp(&n->left, order); + orderaddrtemp(&n->right, order); + } + break; } lineno = lno; diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 40620c3da..39028e3f8 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -11,9 +11,10 @@ #include "md5.h" #include "gg.h" #include "opt.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" static void allocauto(Prog* p); +static void emitptrargsmap(void); static Sym* makefuncdatasym(char *namefmt, int64 funcdatakind) @@ -173,9 +174,17 @@ compile(Node *fn) lno = setlineno(fn); + curfn = fn; + dowidth(curfn->type); + if(fn->nbody == nil) { - if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) + if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) { yyerror("missing function body", fn); + goto ret; + } + if(debug['A']) + goto ret; + emitptrargsmap(); goto ret; } @@ -184,9 +193,6 @@ compile(Node *fn) // set up domain for labels clearlabels(); - curfn = fn; - dowidth(curfn->type); - if(curfn->type->outnamed) { // add clearing of the output parameters t = structfirst(&save, getoutarg(curfn->type)); @@ -229,9 +235,11 @@ compile(Node *fn) ptxt->TEXTFLAG |= WRAPPER; if(fn->needctxt) ptxt->TEXTFLAG |= NEEDCTXT; + if(fn->nosplit) + ptxt->TEXTFLAG |= NOSPLIT; // Clumsy but important. - // See test/recover.go for test cases and src/pkg/reflect/value.go + // See test/recover.go for test cases and src/reflect/value.go // for the actual functions being considered. if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) { if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0) @@ -327,6 +335,43 @@ ret: lineno = lno; } +static void +emitptrargsmap(void) +{ + int nptr, nbitmap, j, off; + vlong xoffset; + Bvec *bv; + Sym *sym; + + sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name)); + + nptr = curfn->type->argwid / widthptr; + bv = bvalloc(nptr*2); + nbitmap = 1; + if(curfn->type->outtuple > 0) + nbitmap = 2; + off = duint32(sym, 0, nbitmap); + off = duint32(sym, off, bv->n); + if(curfn->type->thistuple > 0) { + xoffset = 0; + twobitwalktype1(getthisx(curfn->type), &xoffset, bv); + } + if(curfn->type->intuple > 0) { + xoffset = 0; + twobitwalktype1(getinargx(curfn->type), &xoffset, bv); + } + for(j = 0; j < bv->n; j += 32) + off = duint32(sym, off, bv->b[j/32]); + if(curfn->type->outtuple > 0) { + xoffset = 0; + twobitwalktype1(getoutargx(curfn->type), &xoffset, bv); + for(j = 0; j < bv->n; j += 32) + off = duint32(sym, off, bv->b[j/32]); + } + ggloblsym(sym, off, RODATA); + free(bv); +} + // Sort the list of stack variables. Autos after anything else, // within autos, unused after used, within used, things with // pointers first, zeroed things first, and then decreasing size. diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c index 7a40ab559..0feb2c710 100644 --- a/src/cmd/gc/plive.c +++ b/src/cmd/gc/plive.c @@ -17,9 +17,9 @@ #include #include "gg.h" #include "opt.h" -#include "../../pkg/runtime/funcdata.h" - -enum { BitsPerPointer = 2 }; +#include "../ld/textflag.h" +#include "../../runtime/funcdata.h" +#include "../../runtime/mgc0.h" enum { UNVISITED = 0, @@ -674,8 +674,8 @@ static void progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit) { ProgInfo info; - Adr *from; - Adr *to; + Addr *from; + Addr *to; Node *node; int32 i; int32 pos; @@ -1063,7 +1063,7 @@ checkptxt(Node *fn, Prog *firstp) // and then simply copied into bv at the correct offset on future calls with // the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1 // accounts for 40% of the 6g execution time. -static void +void twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) { vlong fieldoffset; @@ -1113,8 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *str; intgo len; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot *xoffset += t->width; break; @@ -1145,9 +1144,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *array; uintgo len; uintgo cap; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid TARRAY alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot *xoffset += t->width; } else for(i = 0; i < t->bound; i++) @@ -1683,6 +1680,13 @@ livenessepilogue(Liveness *lv) // FNV-1 hash function constants. #define H0 2166136261UL #define Hp 16777619UL +/*c2go +enum +{ + H0 = 2166136261, + Hp = 16777619, +}; +*/ static uint32 hashbitmap(uint32 h, Bvec *bv) @@ -1932,11 +1936,15 @@ twobitwritesymbol(Array *arr, Sym *sym) break; for(j = 0; j < bv->n; j += 32) { word = bv->b[j/32]; - off = duint32(sym, off, word); + // Runtime reads the bitmaps as byte arrays. Oblige. + off = duint8(sym, off, word); + off = duint8(sym, off, word>>8); + off = duint8(sym, off, word>>16); + off = duint8(sym, off, word>>24); } } duint32(sym, 0, i); // number of bitmaps - ggloblsym(sym, off, 0, 1); + ggloblsym(sym, off, RODATA); } static void diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c index ea88b94db..993bb2482 100644 --- a/src/cmd/gc/popt.c +++ b/src/cmd/gc/popt.c @@ -49,7 +49,7 @@ noreturn(Prog *p) symlist[0] = pkglookup("panicindex", runtimepkg); symlist[1] = pkglookup("panicslice", runtimepkg); symlist[2] = pkglookup("throwinit", runtimepkg); - symlist[3] = pkglookup("panic", runtimepkg); + symlist[3] = pkglookup("gopanic", runtimepkg); symlist[4] = pkglookup("panicwrap", runtimepkg); symlist[5] = pkglookup("throwreturn", runtimepkg); symlist[6] = pkglookup("selectgo", runtimepkg); @@ -98,6 +98,10 @@ chasejmp(Prog *p, int *jmploop) */ #define alive ((void*)0) #define dead ((void*)1) +/*c2go +extern void *alive; +extern void *dead; +*/ /* mark all code reachable from firstp as alive */ static void diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c index 285bd78a2..c9e27fe56 100644 --- a/src/cmd/gc/racewalk.c +++ b/src/cmd/gc/racewalk.c @@ -208,6 +208,26 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) goto ret; case OCALLFUNC: + // Instrument dst argument of runtime.writebarrier* calls + // as we do not instrument runtime code. + if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) { + // Find the dst argument. + // The list can be reordered, so it's not necessary just the first or the second element. + for(l = n->list; l; l = l->next) { + if(strcmp(n->left->sym->name, "writebarrierfat") == 0) { + if(l->n->left->xoffset == widthptr) + break; + } else { + if(l->n->left->xoffset == 0) + break; + } + } + if(l == nil) + fatal("racewalk: writebarrier no arg"); + if(l->n->right->op != OADDR) + fatal("racewalk: writebarrier bad arg"); + callinstr(&l->n->right->left, init, 1, 0); + } racewalknode(&n->left, init, 0, 0); goto ret; @@ -419,8 +439,10 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) ret: if(n->op != OBLOCK) // OBLOCK is handled above in a special way. racewalklist(n->list, init); - racewalknode(&n->ntest, &n->ntest->ninit, 0, 0); - racewalknode(&n->nincr, &n->nincr->ninit, 0, 0); + if(n->ntest != N) + racewalknode(&n->ntest, &n->ntest->ninit, 0, 0); + if(n->nincr != N) + racewalknode(&n->nincr, &n->nincr->ninit, 0, 0); racewalklist(n->nbody, nil); racewalklist(n->nelse, nil); racewalklist(n->rlist, nil); diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index 45aa521b3..4ed452832 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -67,9 +67,11 @@ typecheckrange(Node *n) yyerror("too many variables in range"); } - v1 = n->list->n; + v1 = N; + if(n->list) + v1 = n->list->n; v2 = N; - if(n->list->next) + if(n->list && n->list->next) v2 = n->list->next->n; // this is not only a optimization but also a requirement in the spec. @@ -77,14 +79,17 @@ typecheckrange(Node *n) // clause is equivalent to the same clause with only the first variable // present." if(isblank(v2)) { - n->list = list1(v1); + if(v1 != N) + n->list = list1(v1); v2 = N; } - if(v1->defn == n) - v1->type = t1; - else if(v1->type != T && assignop(t1, v1->type, &why) == 0) - yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); + if(v1) { + if(v1->defn == n) + v1->type = t1; + else if(v1->type != T && assignop(t1, v1->type, &why) == 0) + yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); + } if(v2) { if(v2->defn == n) v2->type = t2; @@ -123,9 +128,11 @@ walkrange(Node *n) a = n->right; lno = setlineno(a); - v1 = n->list->n; + v1 = N; + if(n->list) + v1 = n->list->n; v2 = N; - if(n->list->next && !isblank(n->list->next->n)) + if(n->list && n->list->next && !isblank(n->list->next->n)) v2 = n->list->next->n; // n->list has no meaning anymore, clear it // to avoid erroneous processing by racewalk. @@ -154,7 +161,9 @@ walkrange(Node *n) n->ntest = nod(OLT, hv1, hn); n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); - if(v2 == N) + if(v1 == N) + body = nil; + else if(v2 == N) body = list1(nod(OAS, v1, hv1)); else { a = nod(OAS2, N, N); @@ -205,16 +214,18 @@ walkrange(Node *n) key = nod(ODOT, hit, keyname); key = nod(OIND, key, N); - if(v2 == N) { - a = nod(OAS, v1, key); + if(v1 == N) + body = nil; + else if(v2 == N) { + body = list1(nod(OAS, v1, key)); } else { val = nod(ODOT, hit, valname); val = nod(OIND, val, N); a = nod(OAS2, N, N); a->list = list(list1(v1), v2); a->rlist = list(list1(key), val); + body = list1(a); } - body = list1(a); break; case TCHAN: @@ -223,6 +234,7 @@ walkrange(Node *n) n->ntest = N; hv1 = temp(t->type); + hv1->typecheck = 1; if(haspointers(t->type)) init = list(init, nod(OAS, hv1, N)); hb = temp(types[TBOOL]); @@ -233,7 +245,10 @@ walkrange(Node *n) a->list = list(list1(hv1), hb); a->rlist = list1(nod(ORECV, ha, N)); n->ntest->ninit = list1(a); - body = list1(nod(OAS, v1, hv1)); + if(v1 == N) + body = nil; + else + body = list1(nod(OAS, v1, hv1)); break; case TSTRING: @@ -257,7 +272,10 @@ walkrange(Node *n) n->ntest = nod(ONE, hv1, nodintconst(0)); n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); - body = list1(nod(OAS, v1, ohv1)); + + body = nil; + if(v1 != N) + body = list1(nod(OAS, v1, ohv1)); if(v2 != N) body = list(body, nod(OAS, v2, hv2)); break; diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index dbb447e4e..b2ff2fbc5 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -5,7 +5,9 @@ #include #include #include "go.h" -#include "../../pkg/runtime/mgc0.h" +#include "../ld/textflag.h" +#include "../../runtime/mgc0.h" +#include "../../runtime/typekind.h" /* * runtime interface and reflection data structures @@ -15,7 +17,9 @@ static NodeList* signatlist; static Sym* dtypesym(Type*); static Sym* weaktypesym(Type*); static Sym* dalgsym(Type*); -static Sym* dgcsym(Type*); +static int usegcprog(Type*); +static void gengcprog(Type*, Sym**, Sym**); +static void gengcmask(Type*, uint8[16]); static int sigcmp(Sig *a, Sig *b) @@ -105,7 +109,7 @@ lsort(Sig *l, int(*f)(Sig*, Sig*)) // the given map type. This type is not visible to users - // we include only enough information to generate a correct GC // program for it. -// Make sure this stays in sync with ../../pkg/runtime/hashmap.c! +// Make sure this stays in sync with ../../runtime/hashmap.c! enum { BUCKETSIZE = 8, MAXKEYSIZE = 128, @@ -188,7 +192,7 @@ mapbucket(Type *t) // the given map type. This type is not visible to users - // we include only enough information to generate a correct GC // program for it. -// Make sure this stays in sync with ../../pkg/runtime/hashmap.c! +// Make sure this stays in sync with ../../runtime/hashmap.go! static Type* hmap(Type *t) { @@ -207,10 +211,6 @@ hmap(Type *t) offset += 4; // flags offset += 4; // hash0 offset += 1; // B - offset += 1; // keysize - offset += 1; // valuesize - offset = (offset + 1) / 2 * 2; - offset += 2; // bucketsize offset = (offset + widthptr - 1) / widthptr * widthptr; bucketsfield = typ(TFIELD); @@ -261,7 +261,7 @@ hiter(Type *t) // bptr *Bucket // other [4]uintptr // } - // must match ../../pkg/runtime/hashmap.c:hash_iter. + // must match ../../runtime/hashmap.c:hash_iter. field[0] = typ(TFIELD); field[0]->type = ptrto(t->down); field[0]->sym = mal(sizeof(Sym)); @@ -378,7 +378,7 @@ methods(Type *t) // type stored in interface word it = t; - if(it->width > widthptr) + if(!isdirectiface(it)) it = ptrto(t); // make list of methods for t, @@ -524,7 +524,7 @@ dimportpath(Pkg *p) p->pathsym = n->sym; gdatastring(n, p->path); - ggloblsym(n->sym, types[TSTRING]->width, 1, 1); + ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA); } static int @@ -550,7 +550,7 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg) /* * uncommonType - * ../../pkg/runtime/type.go:/uncommonType + * ../../runtime/type.go:/uncommonType */ static int dextratype(Sym *sym, int off, Type *t, int ptroff) @@ -564,6 +564,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) return off; // fill in *extraType pointer in header + off = rnd(off, widthptr); dsymptr(sym, ptroff, sym, off); n = 0; @@ -593,7 +594,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) // methods for(a=m; a; a=a->link) { // method - // ../../pkg/runtime/type.go:/method + // ../../runtime/type.go:/method ot = dgostringptr(s, ot, a->name); ot = dgopkgpath(s, ot, a->pkg); ot = dsymptr(s, ot, dtypesym(a->mtype), 0); @@ -611,37 +612,6 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) return ot; } -enum { - KindBool = 1, - KindInt, - KindInt8, - KindInt16, - KindInt32, - KindInt64, - KindUint, - KindUint8, - KindUint16, - KindUint32, - KindUint64, - KindUintptr, - KindFloat32, - KindFloat64, - KindComplex64, - KindComplex128, - KindArray, - KindChan, - KindFunc, - KindInterface, - KindMap, - KindPtr, - KindSlice, - KindString, - KindStruct, - KindUnsafePointer, - - KindNoPointers = 1<<7, -}; - static int kinds[] = { @@ -740,28 +710,30 @@ haspointers(Type *t) /* * commonType - * ../../pkg/runtime/type.go:/commonType + * ../../runtime/type.go:/commonType */ static int dcommontype(Sym *s, int ot, Type *t) { - int i, alg, sizeofAlg; - Sym *sptr, *algsym, *zero; + int i, alg, sizeofAlg, gcprog; + Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits; + uint8 gcmask[16]; static Sym *algarray; + uint64 x1, x2; char *p; if(ot != 0) fatal("dcommontype %d", ot); - sizeofAlg = 4*widthptr; + sizeofAlg = 2*widthptr; if(algarray == nil) algarray = pkglookup("algarray", runtimepkg); + dowidth(t); alg = algtype(t); algsym = S; if(alg < 0) algsym = dalgsym(t); - dowidth(t); if(t->sym != nil && !isptr[t->etype]) sptr = dtypesym(ptrto(t)); else @@ -808,17 +780,52 @@ dcommontype(Sym *s, int ot, Type *t) ot = duint8(s, ot, t->align); // align ot = duint8(s, ot, t->align); // fieldAlign + gcprog = usegcprog(t); i = kinds[t->etype]; if(t->etype == TARRAY && t->bound < 0) i = KindSlice; if(!haspointers(t)) i |= KindNoPointers; + if(isdirectiface(t)) + i |= KindDirectIface; + if(gcprog) + i |= KindGCProg; ot = duint8(s, ot, i); // kind if(alg >= 0) ot = dsymptr(s, ot, algarray, alg*sizeofAlg); else ot = dsymptr(s, ot, algsym, 0); - ot = dsymptr(s, ot, dgcsym(t), 0); // gc + // gc + if(gcprog) { + gengcprog(t, &gcprog0, &gcprog1); + if(gcprog0 != S) + ot = dsymptr(s, ot, gcprog0, 0); + else + ot = duintptr(s, ot, 0); + ot = dsymptr(s, ot, gcprog1, 0); + } else { + gengcmask(t, gcmask); + x1 = 0; + for(i=0; i<8; i++) + x1 = x1<<8 | gcmask[i]; + if(widthptr == 4) { + p = smprint("gcbits.%#016llux", x1); + } else { + x2 = 0; + for(i=0; i<8; i++) + x2 = x2<<8 | gcmask[i+8]; + p = smprint("gcbits.%#016llux%016llux", x1, x2); + } + sbits = pkglookup(p, runtimepkg); + if((sbits->flags & SymUniq) == 0) { + sbits->flags |= SymUniq; + for(i = 0; i < 2*widthptr; i++) + duint8(sbits, i, gcmask[i]); + ggloblsym(sbits, 2*widthptr, DUPOK|RODATA); + } + ot = dsymptr(s, ot, sbits, 0); + ot = duintptr(s, ot, 0); + } p = smprint("%-uT", t); //print("dcommontype: %s\n", p); ot = dgostringptr(s, ot, p); // string @@ -975,7 +982,9 @@ dtypesym(Type *t) tbase = t; if(isptr[t->etype] && t->sym == S && t->type->sym != S) tbase = t->type; - dupok = tbase->sym == S; + dupok = 0; + if(tbase->sym == S) + dupok = DUPOK; if(compiling_runtime && (tbase == types[tbase->etype] || @@ -1002,7 +1011,7 @@ ok: case TARRAY: if(t->bound >= 0) { - // ../../pkg/runtime/type.go:/ArrayType + // ../../runtime/type.go:/ArrayType s1 = dtypesym(t->type); t2 = typ(TARRAY); t2->type = t->type; @@ -1014,7 +1023,7 @@ ok: ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); } else { - // ../../pkg/runtime/type.go:/SliceType + // ../../runtime/type.go:/SliceType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1023,7 +1032,7 @@ ok: break; case TCHAN: - // ../../pkg/runtime/type.go:/ChanType + // ../../runtime/type.go:/ChanType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1073,14 +1082,14 @@ ok: n++; } - // ../../pkg/runtime/type.go:/InterfaceType + // ../../runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); for(a=m; a; a=a->link) { - // ../../pkg/runtime/type.go:/imethod + // ../../runtime/type.go:/imethod ot = dgostringptr(s, ot, a->name); ot = dgopkgpath(s, ot, a->pkg); ot = dsymptr(s, ot, dtypesym(a->type), 0); @@ -1088,7 +1097,7 @@ ok: break; case TMAP: - // ../../pkg/runtime/type.go:/MapType + // ../../runtime/type.go:/MapType s1 = dtypesym(t->down); s2 = dtypesym(t->type); s3 = dtypesym(mapbucket(t)); @@ -1099,16 +1108,31 @@ ok: ot = dsymptr(s, ot, s2, 0); ot = dsymptr(s, ot, s3, 0); ot = dsymptr(s, ot, s4, 0); + if(t->down->width > MAXKEYSIZE) { + ot = duint8(s, ot, widthptr); + ot = duint8(s, ot, 1); // indirect + } else { + ot = duint8(s, ot, t->down->width); + ot = duint8(s, ot, 0); // not indirect + } + if(t->type->width > MAXVALSIZE) { + ot = duint8(s, ot, widthptr); + ot = duint8(s, ot, 1); // indirect + } else { + ot = duint8(s, ot, t->type->width); + ot = duint8(s, ot, 0); // not indirect + } + ot = duint16(s, ot, mapbucket(t)->width); break; case TPTR32: case TPTR64: if(t->type->etype == TANY) { - // ../../pkg/runtime/type.go:/UnsafePointerType + // ../../runtime/type.go:/UnsafePointerType ot = dcommontype(s, ot, t); break; } - // ../../pkg/runtime/type.go:/PtrType + // ../../runtime/type.go:/PtrType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1116,7 +1140,7 @@ ok: break; case TSTRUCT: - // ../../pkg/runtime/type.go:/StructType + // ../../runtime/type.go:/StructType // for security, only the exported fields. n = 0; for(t1=t->type; t1!=T; t1=t1->down) { @@ -1129,7 +1153,7 @@ ok: ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); for(t1=t->type; t1!=T; t1=t1->down) { - // ../../pkg/runtime/type.go:/structField + // ../../runtime/type.go:/structField if(t1->sym && !t1->embedded) { ot = dgostringptr(s, ot, t1->sym->name); if(exportname(t1->sym->name)) @@ -1150,7 +1174,7 @@ ok: break; } ot = dextratype(s, ot, t, xt); - ggloblsym(s, ot, dupok, 1); + ggloblsym(s, ot, dupok|RODATA); // generate typelink.foo pointing at s = type.foo. // The linker will leave a table of all the typelinks for @@ -1164,7 +1188,7 @@ ok: case TMAP: slink = typelinksym(t); dsymptr(slink, 0, s, 0); - ggloblsym(slink, widthptr, dupok, 1); + ggloblsym(slink, widthptr, dupok|RODATA); } } @@ -1236,8 +1260,7 @@ static Sym* dalgsym(Type *t) { int ot; - Sym *s, *hash, *eq; - char buf[100]; + Sym *s, *hash, *hashfunc, *eq, *eqfunc; // dalgsym is only called for a type that needs an algorithm table, // which implies that the type is comparable (or else it would use ANOEQ). @@ -1248,55 +1271,225 @@ dalgsym(Type *t) eq = typesymprefix(".eq", t); geneq(eq, t); - // ../../pkg/runtime/runtime.h:/Alg + // make Go funcs (closures) for calling hash and equal from Go + hashfunc = typesymprefix(".hashfunc", t); + dsymptr(hashfunc, 0, hash, 0); + ggloblsym(hashfunc, widthptr, DUPOK|RODATA); + eqfunc = typesymprefix(".eqfunc", t); + dsymptr(eqfunc, 0, eq, 0); + ggloblsym(eqfunc, widthptr, DUPOK|RODATA); + + // ../../runtime/alg.go:/typeAlg ot = 0; - ot = dsymptr(s, ot, hash, 0); - ot = dsymptr(s, ot, eq, 0); - ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0); - switch(t->width) { - default: - ot = dsymptr(s, ot, pkglookup("memcopy", runtimepkg), 0); - break; - case 1: - case 2: - case 4: - case 8: - case 16: - snprint(buf, sizeof buf, "memcopy%d", (int)t->width*8); - ot = dsymptr(s, ot, pkglookup(buf, runtimepkg), 0); - break; - } + ot = dsymptr(s, ot, hashfunc, 0); + ot = dsymptr(s, ot, eqfunc, 0); - ggloblsym(s, ot, 1, 1); + ggloblsym(s, ot, DUPOK|RODATA); return s; } static int -gcinline(Type *t) +usegcprog(Type *t) { - switch(t->etype) { - case TARRAY: - if(t->bound == 1) - return 1; - if(t->width <= 4*widthptr) - return 1; - break; + vlong size, nptr; + + if(!haspointers(t)) + return 0; + if(t->width == BADWIDTH) + dowidth(t); + // Calculate size of the unrolled GC mask. + nptr = (t->width+widthptr-1)/widthptr; + size = nptr; + if(size%2) + size *= 2; // repeated + size = size*gcBits/8; // 4 bits per word + // Decide whether to use unrolled GC mask or GC program. + // We could use a more elaborate condition, but this seems to work well in practice. + // For small objects GC program can't give significant reduction. + // While large objects usually contain arrays; and even if it don't + // the program uses 2-bits per word while mask uses 4-bits per word, + // so the program is still smaller. + return size > 2*widthptr; +} + +// Generates sparse GC bitmask (4 bits per word). +static void +gengcmask(Type *t, uint8 gcmask[16]) +{ + Bvec *vec; + vlong xoffset, nptr, i, j; + int half, mw; + uint8 bits, *pos; + + memset(gcmask, 0, 16); + if(!haspointers(t)) + return; + + // Generate compact mask as stacks use. + xoffset = 0; + vec = bvalloc(2*widthptr*8); + twobitwalktype1(t, &xoffset, vec); + + // Unfold the mask for the GC bitmap format: + // 4 bits per word, 2 high bits encode pointer info. + pos = (uint8*)gcmask; + nptr = (t->width+widthptr-1)/widthptr; + half = 0; + mw = 0; + // If number of words is odd, repeat the mask. + // This makes simpler handling of arrays in runtime. + for(j=0; j<=(nptr%2); j++) { + for(i=0; ialign > 0 && (*off % t->align) != 0) - fatal("dgcsym1: invalid initial alignment, %T", t); +static void +proggeninit(ProgGen *g, Sym *s) +{ + g->s = s; + g->datasize = 0; + g->ot = 0; + memset(g->data, 0, sizeof(g->data)); +} + +static void +proggenemit(ProgGen *g, uint8 v) +{ + g->ot = duint8(g->s, g->ot, v); +} + +// Emits insData block from g->data. +static void +proggendataflush(ProgGen *g) +{ + int32 i, s; + + if(g->datasize == 0) + return; + proggenemit(g, insData); + proggenemit(g, g->datasize); + s = (g->datasize + PointersPerByte - 1)/PointersPerByte; + for(i = 0; i < s; i++) + proggenemit(g, g->data[i]); + g->datasize = 0; + memset(g->data, 0, sizeof(g->data)); +} + +static void +proggendata(ProgGen *g, uint8 d) +{ + g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); + g->datasize++; + if(g->datasize == 255) + proggendataflush(g); +} + +// Skip v bytes due to alignment, etc. +static void +proggenskip(ProgGen *g, vlong off, vlong v) +{ + vlong i; + + for(i = off; i < off+v; i++) { + if((i%widthptr) == 0) + proggendata(g, BitsScalar); + } +} + +// Emit insArray instruction. +static void +proggenarray(ProgGen *g, vlong len) +{ + int32 i; + + proggendataflush(g); + proggenemit(g, insArray); + for(i = 0; i < widthptr; i++, len >>= 8) + proggenemit(g, len); +} + +static void +proggenarrayend(ProgGen *g) +{ + proggendataflush(g); + proggenemit(g, insArrayEnd); +} + +static vlong +proggenfini(ProgGen *g) +{ + proggendataflush(g); + proggenemit(g, insEnd); + return g->ot; +} + +static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset); + +// Generates GC program for large types. +static void +gengcprog(Type *t, Sym **pgc0, Sym **pgc1) +{ + Sym *gc0, *gc1; + vlong nptr, size, ot, xoffset; + ProgGen g; + + nptr = (t->width+widthptr-1)/widthptr; + size = nptr; + if(size%2) + size *= 2; // repeated twice + size = size*PointersPerByte/8; // 4 bits per word + size++; // unroll flag in the beginning, used by runtime (see runtime.markallocated) + // emity space in BSS for unrolled program + *pgc0 = S; + // Don't generate it if it's too large, runtime will unroll directly into GC bitmap. + if(size <= MaxGCMask) { + gc0 = typesymprefix(".gc", t); + ggloblsym(gc0, size, DUPOK|NOPTR); + *pgc0 = gc0; + } + + // program in RODATA + gc1 = typesymprefix(".gcprog", t); + proggeninit(&g, gc1); + xoffset = 0; + gengcprog1(&g, t, &xoffset); + ot = proggenfini(&g); + ggloblsym(gc1, ot, DUPOK|RODATA); + *pgc1 = gc1; +} + +// Recursively walks type t and writes GC program into g. +static void +gengcprog1(ProgGen *g, Type *t, vlong *xoffset) +{ + vlong fieldoffset, i, o, n; + Type *t1; - if(t->width == BADWIDTH) - dowidth(t); - switch(t->etype) { case TINT8: case TUINT8: @@ -1314,187 +1507,71 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) case TFLOAT64: case TCOMPLEX64: case TCOMPLEX128: - *off += t->width; + proggenskip(g, *xoffset, t->width); + *xoffset += t->width; break; - case TPTR32: case TPTR64: - // NOTE: Any changes here need to be made to reflect.PtrTo as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - - // NOTE(rsc): Emitting GC_APTR here for *nonptrtype - // (pointer to non-pointer-containing type) means that - // we do not record 'nonptrtype' and instead tell the - // garbage collector to look up the type of the memory in - // type information stored in the heap. In effect we are telling - // the collector "we don't trust our information - use yours". - // It's not completely clear why we want to do this. - // It does have the effect that if you have a *SliceHeader and a *[]int - // pointing at the same actual slice header, *SliceHeader will not be - // used as an authoritative type for the memory, which is good: - // if the collector scanned the memory as type *SliceHeader, it would - // see no pointers inside but mark the block as scanned, preventing - // the seeing of pointers when we followed the *[]int pointer. - // Perhaps that kind of situation is the rationale. - if(!haspointers(t->type)) { - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - } else { - ot = duintptr(s, ot, GC_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(t->type), 0); - } - *off += t->width; - break; - case TUNSAFEPTR: case TFUNC: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - *off += t->width; - break; - - // struct Hchan* case TCHAN: - // NOTE: Any changes here need to be made to reflect.ChanOf as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_CHAN_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dtypesym(t), 0); - *off += t->width; - break; - - // struct Hmap* case TMAP: - // NOTE: Any changes here need to be made to reflect.MapOf as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(hmap(t)), 0); - *off += t->width; + proggendata(g, BitsPointer); + *xoffset += t->width; break; - - // struct { byte *str; int32 len; } case TSTRING: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_STRING); - ot = duintptr(s, ot, *off); - *off += t->width; + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); + *xoffset += t->width; break; - - // struct { Itab* tab; void* data; } - // struct { Type* type; void* data; } // When isnilinter(t)==true case TINTER: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - if(isnilinter(t)) { - ot = duintptr(s, ot, GC_EFACE); - ot = duintptr(s, ot, *off); - } else { - ot = duintptr(s, ot, GC_IFACE); - ot = duintptr(s, ot, *off); - } - *off += t->width; + proggendata(g, BitsMultiWord); + if(isnilinter(t)) + proggendata(g, BitsEface); + else + proggendata(g, BitsIface); + *xoffset += t->width; break; - case TARRAY: - if(t->bound < -1) - fatal("dgcsym1: invalid bound, %T", t); - if(t->type->width == BADWIDTH) - dowidth(t->type); if(isslice(t)) { - // NOTE: Any changes here need to be made to reflect.SliceOf as well. - // struct { byte* array; uint32 len; uint32 cap; } - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - if(t->type->width != 0) { - ot = duintptr(s, ot, GC_SLICE); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(t->type), 0); - } else { - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - } - *off += t->width; + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); + proggendata(g, BitsScalar); } else { - // NOTE: Any changes here need to be made to reflect.ArrayOf as well, - // at least once ArrayOf's gc info is implemented and ArrayOf is exported. - // struct { byte* array; uint32 len; uint32 cap; } - if(t->bound < 1 || !haspointers(t->type)) { - *off += t->width; - } else if(gcinline(t)) { - for(i=0; ibound; i++) - ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1 + t1 = t->type; + if(t1->width == 0) { + // ignore + } if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) { + for(i = 0; i < t->bound; i++) + gengcprog1(g, t1, xoffset); + } else if(!haspointers(t1)) { + n = t->width; + n -= -*xoffset&(widthptr-1); // skip to next ptr boundary + proggenarray(g, (n+widthptr-1)/widthptr); + proggendata(g, BitsScalar); + proggenarrayend(g); + *xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width; } else { - if(stack_size < GC_STACK_CAPACITY) { - ot = duintptr(s, ot, GC_ARRAY_START); // a stack push during GC - ot = duintptr(s, ot, *off); - ot = duintptr(s, ot, t->bound); - ot = duintptr(s, ot, t->type->width); - off2 = 0; - ot = dgcsym1(s, ot, t->type, &off2, stack_size+1); // recursive call of dgcsym1 - ot = duintptr(s, ot, GC_ARRAY_NEXT); // a stack pop during GC - } else { - ot = duintptr(s, ot, GC_REGION); - ot = duintptr(s, ot, *off); - ot = duintptr(s, ot, t->width); - ot = dsymptr(s, ot, dgcsym(t), 0); - } - *off += t->width; + proggenarray(g, t->bound); + gengcprog1(g, t1, xoffset); + *xoffset += (t->bound-1)*t1->width; + proggenarrayend(g); } } break; - case TSTRUCT: o = 0; - for(t1=t->type; t1!=T; t1=t1->down) { + for(t1 = t->type; t1 != T; t1 = t1->down) { fieldoffset = t1->width; - *off += fieldoffset - o; - ot = dgcsym1(s, ot, t1->type, off, stack_size); // recursive call of dgcsym1 + proggenskip(g, *xoffset, fieldoffset - o); + *xoffset += fieldoffset - o; + gengcprog1(g, t1->type, xoffset); o = fieldoffset + t1->type->width; } - *off += t->width - o; + proggenskip(g, *xoffset, t->width - o); + *xoffset += t->width - o; break; - default: - fatal("dgcsym1: unexpected type %T", t); + fatal("gengcprog1: unexpected type, %T", t); } - - return ot; -} - -static Sym* -dgcsym(Type *t) -{ - int ot; - vlong off; - Sym *s; - - s = typesymprefix(".gc", t); - if(s->flags & SymGcgen) - return s; - s->flags |= SymGcgen; - - if(t->width == BADWIDTH) - dowidth(t); - - ot = 0; - off = 0; - ot = duintptr(s, ot, t->width); - ot = dgcsym1(s, ot, t, &off, 0); - ot = duintptr(s, ot, GC_END); - ggloblsym(s, ot, 1, 1); - - if(t->align > 0) - off = rnd(off, t->align); - if(off != t->width) - fatal("dgcsym: off=%lld, size=%lld, type %T", off, t->width, t); - - return s; } diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index fb5c2a150..0fb15c265 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -12,7 +12,7 @@ package PACKAGE // emitted by compiler, not referred to by go programs -func new(typ *byte) *any +func newobject(typ *byte) *any func panicindex() func panicslice() func panicdivide() @@ -20,12 +20,13 @@ func throwreturn() func throwinit() func panicwrap(string, string, string) -func panic(interface{}) -func recover(*int32) interface{} +func gopanic(interface{}) +func gorecover(*int32) interface{} func printbool(bool) func printfloat(float64) func printint(int64) +func printhex(uint64) func printuint(uint64) func printcomplex(complex128) func printstring(string) @@ -35,7 +36,6 @@ func printeface(any) func printslice(any) func printnl() func printsp() -func goprintf() func concatstring2(string, string) string func concatstring3(string, string, string) string @@ -53,7 +53,7 @@ func stringtoslicebyte(string) []byte func stringtoslicerune(string) []rune func stringiter(string, int) int func stringiter2(string, int) (retk int, retv rune) -func copy(to any, fr any, wid uintptr) int +func slicecopy(to any, fr any, wid uintptr) int func slicestringcopy(to any, fr any) int // interface conversions @@ -84,8 +84,6 @@ func efaceeq(i1 any, i2 any) (ret bool) func ifacethash(i1 any) (ret uint32) func efacethash(i1 any) (ret uint32) -func equal(typ *byte, x1, x2 any) (ret bool) - // *byte is really *runtime.Type func makemap(mapType *byte, hint int64) (hmap map[any]any) func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) @@ -108,11 +106,25 @@ func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool func chansend1(chanType *byte, hchan chan<- any, elem *any) func closechan(hchan any) +// *byte is really *runtime.Type +func writebarrierptr(dst *any, src any) +func writebarrierstring(dst *any, src any) +func writebarrierslice(dst *any, src any) +func writebarrieriface(dst *any, src any) + +// The unused *byte argument makes sure that src is 2-pointer-aligned, +// which is the maximum alignment on NaCl amd64p32 +// (and possibly on 32-bit systems if we start 64-bit aligning uint64s). +func writebarrierfat2(dst *any, _ *byte, src any) +func writebarrierfat3(dst *any, _ *byte, src any) +func writebarrierfat4(dst *any, _ *byte, src any) +func writebarrierfat(typ *byte, dst *any, src *any) + func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool -func newselect(size int32) (sel *byte) +func newselect(sel *byte, selsize int64, size int32) func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool) func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool) @@ -124,12 +136,12 @@ func makeslice(typ *byte, nel int64, cap int64) (ary []any) func growslice(typ *byte, old []any, n int64) (ary []any) func memmove(to *any, frm *any, length uintptr) -func memequal(eq *bool, size uintptr, x, y *any) -func memequal8(eq *bool, size uintptr, x, y *any) -func memequal16(eq *bool, size uintptr, x, y *any) -func memequal32(eq *bool, size uintptr, x, y *any) -func memequal64(eq *bool, size uintptr, x, y *any) -func memequal128(eq *bool, size uintptr, x, y *any) +func memequal(x, y *any, size uintptr) bool +func memequal8(x, y *any, size uintptr) bool +func memequal16(x, y *any, size uintptr) bool +func memequal32(x, y *any, size uintptr) bool +func memequal64(x, y *any, size uintptr) bool +func memequal128(x, y *any, size uintptr) bool // only used on 32-bit func int64div(int64, int64) int64 diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 58a120674..965ad277f 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -10,6 +10,8 @@ #include #include "go.h" +static Type* selecttype(int32 size); + void typecheckselect(Node *sel) { @@ -95,7 +97,7 @@ void walkselect(Node *sel) { int lno, i; - Node *n, *r, *a, *var, *cas, *dflt, *ch; + Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch; NodeList *l, *init; if(sel->list == nil && sel->xoffset != 0) @@ -257,8 +259,12 @@ walkselect(Node *sel) // generate sel-struct setlineno(sel); - var = temp(ptrto(types[TUINT8])); - r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset))); + selv = temp(selecttype(sel->xoffset)); + r = nod(OAS, selv, N); + typecheck(&r, Etop); + init = list(init, r); + var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8])); + r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset)); typecheck(&r, Etop); init = list(init, r); @@ -301,6 +307,8 @@ walkselect(Node *sel) break; } } + // selv is no longer alive after use. + r->nbody = list(r->nbody, nod(OVARKILL, selv, N)); r->nbody = concat(r->nbody, cas->nbody); r->nbody = list(r->nbody, nod(OBREAK, N, N)); init = list(init, r); @@ -316,3 +324,54 @@ out: walkstmtlist(sel->nbody); lineno = lno; } + +// Keep in sync with src/runtime/chan.h. +static Type* +selecttype(int32 size) +{ + Node *sel, *sudog, *scase, *arr; + + // TODO(dvyukov): it's possible to generate SudoG and Scase only once + // and then cache; and also cache Select per size. + sudog = nod(OTSTRUCT, N, N); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8])))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8])))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("link")), typenod(ptrto(types[TUINT8])))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8])))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32]))); + sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8])))); + typecheck(&sudog, Etype); + sudog->type->noalg = 1; + sudog->type->local = 1; + + scase = nod(OTSTRUCT, N, N); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8])))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR]))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16]))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16]))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8])))); + scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); + typecheck(&scase, Etype); + scase->type->noalg = 1; + scase->type->local = 1; + + sel = nod(OTSTRUCT, N, N); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16]))); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16]))); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8])))); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8])))); + arr = nod(OTARRAY, nodintconst(size), scase); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr)); + arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8]))); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr)); + arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16])); + sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr)); + typecheck(&sel, Etype); + sel->type->noalg = 1; + sel->type->local = 1; + + return sel->type; +} diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 59804cd8d..8ad7ae7ab 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -17,7 +17,6 @@ enum InitPending = 2, }; -static int iszero(Node*); static void initplan(Node*); static NodeList *initlist; static void init2(Node*, NodeList**); @@ -207,7 +206,7 @@ init2(Node *n, NodeList **out) if(n->op == OCLOSURE) init2list(n->closure->nbody, out); - if(n->op == ODOTMETH) + if(n->op == ODOTMETH || n->op == OCALLPART) init2(n->type->nname, out); } @@ -633,11 +632,14 @@ structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init) a = nod(ODOT, var, newname(index->sym)); a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); if(pass == 1) { + walkexpr(&a, init); // add any assignments in r to top if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; + } else { + orderstmtinplace(&a); + walkstmt(&a); } *init = list(*init, a); } @@ -693,11 +695,14 @@ arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init) a = nod(OINDEX, var, index); a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); // add any assignments in r to top if(pass == 1) { + walkexpr(&a, init); if(a->op != OAS) - fatal("structlit: not as"); + fatal("arraylit: not as"); a->dodata = 2; + } else { + orderstmtinplace(&a); + walkstmt(&a); } *init = list(*init, a); } @@ -807,7 +812,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); - walkexpr(&a, init); + orderstmtinplace(&a); + walkstmt(&a); *init = list(*init, a); // put dynamics into slice (6) @@ -839,7 +845,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); + orderstmtinplace(&a); + walkstmt(&a); *init = list(*init, a); } } @@ -1060,7 +1067,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(t->etype != TSTRUCT) fatal("anylit: not struct"); - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1083,7 +1090,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < structcount(t)) { + if(simplename(var) || count(n->list) < structcount(t)) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); @@ -1100,7 +1107,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) break; } - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1123,7 +1130,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < t->bound) { + if(simplename(var) || count(n->list) < t->bound) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); @@ -1348,7 +1355,6 @@ no: return 0; } -static int iszero(Node*); static int isvaluelit(Node*); static InitEntry* entry(InitPlan*); static void addvalue(InitPlan*, vlong, Node*, Node*); @@ -1432,7 +1438,7 @@ addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n) e->expr = n; } -static int +int iszero(Node *n) { NodeList *l; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 72a9ac20c..c3bc5af3b 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -529,7 +529,8 @@ algtype1(Type *t, Type **bad) if(bad) *bad = T; - + if(t->broke) + return AMEM; if(t->noalg) return ANOEQ; @@ -656,11 +657,15 @@ maptype(Type *key, Type *val) { Type *t; Type *bad; - int atype; + int atype, mtype; if(key != nil) { atype = algtype1(key, &bad); - switch(bad == T ? key->etype : bad->etype) { + if(bad == T) + mtype = key->etype; + else + mtype = bad->etype; + switch(mtype) { default: if(atype == ANOEQ) yyerror("invalid map key type %T", key); @@ -2625,9 +2630,10 @@ hashmem(Type *t) n = newname(sym); n->class = PFUNC; tfn = nod(OTFUNC, N, N); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR])))); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); typecheck(&tfn, Etype); n->type = tfn->type; return n; @@ -2673,9 +2679,10 @@ hashfor(Type *t) n = newname(sym); n->class = PFUNC; tfn = nod(OTFUNC, N, N); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR])))); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); typecheck(&tfn, Etype); n->type = tfn->type; return n; @@ -2687,7 +2694,7 @@ hashfor(Type *t) void genhash(Sym *sym, Type *t) { - Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn; + Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r; Node *hashel; Type *first, *t1; int old_safemode; @@ -2700,21 +2707,23 @@ genhash(Sym *sym, Type *t) dclcontext = PEXTERN; markdcl(); - // func sym(h *uintptr, s uintptr, p *T) + // func sym(p *T, s uintptr, h uintptr) uintptr fn = nod(ODCLFUNC, N, N); fn->nname = newname(sym); fn->nname->class = PFUNC; tfn = nod(OTFUNC, N, N); fn->nname->ntype = tfn; - n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR]))); + n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); tfn->list = list(tfn->list, n); - nh = n->left; + np = n->left; n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); tfn->list = list(tfn->list, n); - n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); + n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR])); tfn->list = list(tfn->list, n); - np = n->left; + nh = n->left; + n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value + tfn->rlist = list(tfn->rlist, n); funchdr(fn); typecheck(&fn->nname->ntype, Etype); @@ -2740,15 +2749,17 @@ genhash(Sym *sym, Type *t) colasdefn(n->list, n); ni = n->list->n; - // *h = *h<<3 | *h>>61 + // TODO: with aeshash we don't need these shift/mul parts + + // h = h<<3 | h>>61 n->nbody = list(n->nbody, nod(OAS, - nod(OIND, nh, N), + nh, nod(OOR, - nod(OLSH, nod(OIND, nh, N), nodintconst(3)), - nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3))))); + nod(OLSH, nh, nodintconst(3)), + nod(ORSH, nh, nodintconst(widthptr*8-3))))); - // *h *= mul + // h *= mul // Same multipliers as in runtime.memhash. if(widthptr == 4) mul = 3267000013LL; @@ -2756,19 +2767,19 @@ genhash(Sym *sym, Type *t) mul = 23344194077549503LL; n->nbody = list(n->nbody, nod(OAS, - nod(OIND, nh, N), - nod(OMUL, nod(OIND, nh, N), nodintconst(mul)))); + nh, + nod(OMUL, nh, nodintconst(mul)))); - // hashel(h, sizeof(p[i]), &p[i]) + // h = hashel(&p[i], sizeof(p[i]), h) call = nod(OCALL, hashel, N); - call->list = list(call->list, nh); - call->list = list(call->list, nodintconst(t->type->width)); nx = nod(OINDEX, np, ni); nx->bounded = 1; na = nod(OADDR, nx, N); na->etype = 1; // no escape to heap call->list = list(call->list, na); - n->nbody = list(n->nbody, call); + call->list = list(call->list, nodintconst(t->type->width)); + call->list = list(call->list, nh); + n->nbody = list(n->nbody, nod(OAS, nh, call)); fn->nbody = list(fn->nbody, n); break; @@ -2793,15 +2804,15 @@ genhash(Sym *sym, Type *t) if(first != T) { size = offend - first->width; // first->width is offset hashel = hashmem(first->type); - // hashel(h, size, &p.first) + // h = hashel(&p.first, size, h) call = nod(OCALL, hashel, N); - call->list = list(call->list, nh); - call->list = list(call->list, nodintconst(size)); nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages? na = nod(OADDR, nx, N); na->etype = 1; // no escape to heap call->list = list(call->list, na); - fn->nbody = list(fn->nbody, call); + call->list = list(call->list, nodintconst(size)); + call->list = list(call->list, nh); + fn->nbody = list(fn->nbody, nod(OAS, nh, call)); first = T; } @@ -2812,20 +2823,21 @@ genhash(Sym *sym, Type *t) // Run hash for this field. hashel = hashfor(t1->type); - // hashel(h, size, &p.t1) + // h = hashel(&p.t1, size, h) call = nod(OCALL, hashel, N); - call->list = list(call->list, nh); - call->list = list(call->list, nodintconst(t1->type->width)); nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages? na = nod(OADDR, nx, N); na->etype = 1; // no escape to heap call->list = list(call->list, na); - fn->nbody = list(fn->nbody, call); + call->list = list(call->list, nodintconst(t1->type->width)); + call->list = list(call->list, nh); + fn->nbody = list(fn->nbody, nod(OAS, nh, call)); } - // make sure body is not empty. - fn->nbody = list(fn->nbody, nod(ORETURN, N, N)); break; } + r = nod(ORETURN, N, N); + r->list = list(r->list, nh); + fn->nbody = list(fn->nbody, r); if(debug['r']) dumplist("genhash body", fn->nbody); @@ -2849,18 +2861,19 @@ genhash(Sym *sym, Type *t) } // Return node for -// if p.field != q.field { *eq = false; return } +// if p.field != q.field { return false } static Node* -eqfield(Node *p, Node *q, Node *field, Node *eq) +eqfield(Node *p, Node *q, Node *field) { - Node *nif, *nx, *ny; + Node *nif, *nx, *ny, *r; nx = nod(OXDOT, p, field); ny = nod(OXDOT, q, field); nif = nod(OIF, N, N); nif->ntest = nod(ONE, nx, ny); - nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0))); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); return nif; } @@ -2889,11 +2902,11 @@ eqmemfunc(vlong size, Type *type) } // Return node for -// if memequal(size, &p.field, &q.field, eq); !*eq { return } +// if !memequal(&p.field, &q.field, size) { return false } static Node* -eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) +eqmem(Node *p, Node *q, Node *field, vlong size) { - Node *nif, *nx, *ny, *call; + Node *nif, *nx, *ny, *call, *r; nx = nod(OADDR, nod(OXDOT, p, field), N); nx->etype = 1; // does not escape @@ -2903,15 +2916,16 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) typecheck(&ny, Erv); call = nod(OCALL, eqmemfunc(size, nx->type->type), N); - call->list = list(call->list, eq); - call->list = list(call->list, nodintconst(size)); call->list = list(call->list, nx); call->list = list(call->list, ny); + call->list = list(call->list, nodintconst(size)); nif = nod(OIF, N, N); nif->ninit = list(nif->ninit, call); - nif->ntest = nod(ONOT, nod(OIND, eq, N), N); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + nif->ntest = nod(ONOT, call, N); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); return nif; } @@ -2921,7 +2935,7 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) void geneq(Sym *sym, Type *t) { - Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange; + Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r; Type *t1, *first; int old_safemode; int64 size; @@ -2934,24 +2948,23 @@ geneq(Sym *sym, Type *t) dclcontext = PEXTERN; markdcl(); - // func sym(eq *bool, s uintptr, p, q *T) + // func sym(p, q *T, s uintptr) bool fn = nod(ODCLFUNC, N, N); fn->nname = newname(sym); fn->nname->class = PFUNC; tfn = nod(OTFUNC, N, N); fn->nname->ntype = tfn; - n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL]))); - tfn->list = list(tfn->list, n); - neq = n->left; - n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); - tfn->list = list(tfn->list, n); n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); tfn->list = list(tfn->list, n); np = n->left; n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t))); tfn->list = list(tfn->list, n); nq = n->left; + n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); + tfn->list = list(tfn->list, n); + n = nod(ODCLFIELD, N, typenod(types[TBOOL])); + tfn->rlist = list(tfn->rlist, n); funchdr(fn); @@ -2977,7 +2990,7 @@ geneq(Sym *sym, Type *t) colasdefn(nrange->list, nrange); ni = nrange->list->n; - // if p[i] != q[i] { *eq = false; return } + // if p[i] != q[i] { return false } nx = nod(OINDEX, np, ni); nx->bounded = 1; ny = nod(OINDEX, nq, ni); @@ -2985,13 +2998,11 @@ geneq(Sym *sym, Type *t) nif = nod(OIF, N, N); nif->ntest = nod(ONE, nx, ny); - nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0))); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); nrange->nbody = list(nrange->nbody, nif); fn->nbody = list(fn->nbody, nrange); - - // *eq = true; - fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); break; case TSTRUCT: @@ -3016,16 +3027,16 @@ geneq(Sym *sym, Type *t) // cross-package unexported fields. if(first != T) { if(first->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); } else if(first->down->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); first = first->down; if(!isblanksym(first->sym)) - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); } else { // More than two fields: use memequal. size = offend - first->width; // first->width is offset - fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq)); + fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size)); } first = T; } @@ -3035,14 +3046,17 @@ geneq(Sym *sym, Type *t) continue; // Check this field, which is not just memory. - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym))); } - // *eq = true; - fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); break; } + // return true + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(1)); + fn->nbody = list(fn->nbody, r); + if(debug['r']) dumplist("geneq body", fn->nbody); @@ -3445,7 +3459,7 @@ smagic(Magic *m) mask = 0xffffffffLL; break; case 64: - mask = 0xffffffffffffffffLL; + mask = 0xffffffffffffffffULL; break; } two31 = mask ^ (mask>>1); @@ -3453,7 +3467,7 @@ smagic(Magic *m) p = m->w-1; ad = m->sd; if(m->sd < 0) - ad = -m->sd; + ad = -(uvlong)m->sd; // bad denominators if(ad == 0 || ad == 1 || ad == two31) { @@ -3543,7 +3557,7 @@ umagic(Magic *m) mask = 0xffffffffLL; break; case 64: - mask = 0xffffffffffffffffLL; + mask = 0xffffffffffffffffULL; break; } two31 = mask ^ (mask>>1); @@ -3628,7 +3642,7 @@ ngotype(Node *n) * users if we escape that as little as possible. * * If you edit this, edit ../ld/lib.c:/^pathtoprefix too. - * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. + * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) @@ -3785,3 +3799,42 @@ checknil(Node *x, NodeList **init) n->typecheck = 1; *init = list(*init, n); } + +/* + * Can this type be stored directly in an interface word? + */ +int +isdirectiface(Type *t) +{ + // Setting IfacePointerOnly = 1 changes the + // interface representation so that the data word + // in an interface value must always be a pointer. + // Setting it to 0 uses the original representation, + // where the data word can hold a pointer or any + // non-pointer value no bigger than a pointer. + enum { + IfacePointerOnly = 1, + }; + + if(IfacePointerOnly) { + switch(t->etype) { + case TPTR32: + case TPTR64: + case TCHAN: + case TMAP: + case TFUNC: + case TUNSAFEPTR: + return 1; + case TARRAY: + // Array of 1 direct iface type can be direct. + return t->bound == 1 && isdirectiface(t->type); + case TSTRUCT: + // Struct with 1 field of direct iface type can be direct. + return t->type != T && t->type->down == T && isdirectiface(t->type->type); + } + return 0; + } + + dowidth(t); + return t->width <= widthptr; +} diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index ce0190507..e1d8af878 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -34,6 +34,7 @@ struct Case Case* link; // linked list to link }; #define C ((Case*)nil) +/*c2go Case *C; */ void dumpcase(Case *c0) diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index c50b2285b..714c66268 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -33,7 +33,7 @@ static void stringtoarraylit(Node**); static Node* resolve(Node*); static void checkdefergo(Node*); static int checkmake(Type*, char*, Node*); -static int checksliceindex(Node*, Type*); +static int checksliceindex(Node*, Node*, Type*); static int checksliceconst(Node*, Node*); static NodeList* typecheckdefstack; @@ -311,6 +311,7 @@ typecheck1(Node **np, int top) Type *t, *tp, *missing, *have, *badtype; Val v; char *why, *desc, descbuf[64]; + vlong x; n = *np; @@ -382,16 +383,6 @@ reswitch: if(n->type == T) goto error; break; - - case OTPAREN: - ok |= Etype; - l = typecheck(&n->left, Etype); - if(l->type == T) - goto error; - n->op = OTYPE; - n->type = l->type; - n->left = N; - break; case OTARRAY: ok |= Etype; @@ -418,7 +409,10 @@ reswitch: v = toint(l->val); break; default: - yyerror("invalid array bound %N", l); + if(l->type != T && isint[l->type->etype] && l->op != OLITERAL) + yyerror("non-constant array bound %N", l); + else + yyerror("invalid array bound %N", l); goto error; } t->bound = mpgetfix(v.u.xval); @@ -535,19 +529,6 @@ reswitch: op = n->etype; goto arith; - case OADDPTR: - ok |= Erv; - l = typecheck(&n->left, Erv); - r = typecheck(&n->right, Erv); - if(l->type == T || r->type == T) - goto error; - if(l->type->etype != tptr) - fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left); - if(r->type->etype != TUINTPTR) - fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right); - n->type = types[tptr]; - goto ret; - case OADD: case OAND: case OANDAND: @@ -620,6 +601,10 @@ reswitch: } if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { defaultlit2(&l, &r, 1); + if(n->op == OASOP && n->implicit) { + yyerror("invalid operation: %N (non-numeric type %T)", n, l->type); + goto error; + } yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); goto error; } @@ -756,10 +741,6 @@ reswitch: l = n->left; if((t = l->type) == T) goto error; - // top&Eindir means this is &x in *&x. (or the arg to built-in print) - // n->etype means code generator flagged it as non-escaping. - if(debug['N'] && !(top & Eindir) && !n->etype) - addrescapes(n->left); n->type = ptrto(t); goto ret; @@ -915,11 +896,12 @@ reswitch: break; } if(isconst(n->right, CTINT)) { - if(mpgetfix(n->right->val.u.xval) < 0) + x = mpgetfix(n->right->val.u.xval); + if(x < 0) yyerror("invalid %s index %N (index must be non-negative)", why, n->right); - else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound) + else if(isfixedarray(t) && t->bound > 0 && x >= t->bound) yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound); - else if(isconst(n->left, CTSTR) && mpgetfix(n->right->val.u.xval) >= n->left->val.u.sval->len) + else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len) yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len); else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0) yyerror("invalid %s index %N (index too large)", why, n->right); @@ -1019,9 +1001,9 @@ reswitch: yyerror("cannot slice %N (type %T)", l, t); goto error; } - if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0) + if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) goto error; - if((hi = n->right->right) != N && checksliceindex(hi, tp) < 0) + if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0) goto error; if(checksliceconst(lo, hi) < 0) goto error; @@ -1068,11 +1050,11 @@ reswitch: yyerror("cannot slice %N (type %T)", l, t); goto error; } - if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0) + if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) goto error; - if((mid = n->right->right->left) != N && checksliceindex(mid, tp) < 0) + if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0) goto error; - if((hi = n->right->right->right) != N && checksliceindex(hi, tp) < 0) + if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0) goto error; if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0) goto error; @@ -1842,7 +1824,7 @@ out: } static int -checksliceindex(Node *r, Type *tp) +checksliceindex(Node *l, Node *r, Type *tp) { Type *t; @@ -1859,6 +1841,9 @@ checksliceindex(Node *r, Type *tp) } else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) { yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound); return -1; + } else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) { + yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len); + return -1; } else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) { yyerror("invalid slice index %N (index too large)", r); return -1; @@ -2139,18 +2124,19 @@ lookdot(Node *n, Type *t, int dostrcmp) if(!eqtype(rcvr, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { checklvalue(n->left, "call pointer method on"); - if(debug['N']) - addrescapes(n->left); n->left = nod(OADDR, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) { + } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) { n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) { + } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) { yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left); while(tt->etype == tptr) { + // Stop one level early for method with pointer receiver. + if(rcvr->etype == tptr && tt->type->etype != tptr) + break; n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); @@ -2831,6 +2817,33 @@ checkassignlist(NodeList *l) checkassign(l->n); } +// Check whether l and r are the same side effect-free expression, +// so that it is safe to reuse one instead of computing both. +static int +samesafeexpr(Node *l, Node *r) +{ + if(l->op != r->op || !eqtype(l->type, r->type)) + return 0; + + switch(l->op) { + case ONAME: + case OCLOSUREVAR: + return l == r; + + case ODOT: + case ODOTPTR: + return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left); + + case OIND: + return samesafeexpr(l->left, r->left); + + case OINDEX: + return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right); + } + + return 0; +} + /* * type check assignment. * if this assignment is the definition of a var on the left side, @@ -2868,6 +2881,29 @@ typecheckas(Node *n) n->typecheck = 1; if(n->left->typecheck == 0) typecheck(&n->left, Erv | Easgn); + + // Recognize slices being updated in place, for better code generation later. + // Don't rewrite if using race detector, to avoid needing to teach race detector + // about this optimization. + if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) { + switch(n->right->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + // For x = x[0:y], x can be updated in place, without touching pointer. + if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left))) + n->right->reslice = 1; + break; + + case OAPPEND: + // For x = append(x, ...), x can be updated in place when there is capacity, + // without touching the pointer; otherwise the emitted code to growslice + // can take care of updating the pointer, and only in that case. + if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n)) + n->right->reslice = 1; + break; + } + } } static void @@ -2975,7 +3011,7 @@ typecheckas2(Node *n) if(l->defn == n) l->type = r->type; l = n->list->next->n; - if(l->type != T) + if(l->type != T && l->type->etype != TBOOL) checkassignto(types[TBOOL], l); if(l->defn == n && l->ntype == N) l->type = types[TBOOL]; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 1cb25512e..ff9b36208 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -5,8 +5,11 @@ #include #include #include "go.h" +#include "../ld/textflag.h" -static Node* walkprint(Node*, NodeList**, int); +static Node* walkprint(Node*, NodeList**); +static Node* writebarrierfn(char*, Type*, Type*); +static Node* applywritebarrier(Node*, NodeList**); static Node* mapfn(char*, Type*); static Node* mapfndel(char*, Type*); static Node* ascompatee1(int, Node*, Node*, NodeList**); @@ -29,6 +32,7 @@ static void walkmul(Node**, NodeList**); static void walkdiv(Node**, NodeList**); static int bounded(Node*, int64); static Mpint mpzero; +static void walkprintfunc(Node**, NodeList**); void walk(Node *fn) @@ -134,6 +138,8 @@ walkstmt(Node **np) n = *np; if(n == N) return; + if(n->dodata == 2) // don't walk, generated by anylit. + return; setlineno(n); @@ -221,8 +227,7 @@ walkstmt(Node **np) switch(n->left->op) { case OPRINT: case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); + walkprintfunc(&n->left, &n->ninit); break; case OCOPY: n->left = copyany(n->left, &n->ninit, 1); @@ -255,8 +260,7 @@ walkstmt(Node **np) switch(n->left->op) { case OPRINT: case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); + walkprintfunc(&n->left, &n->ninit); break; case OCOPY: n->left = copyany(n->left, &n->ninit, 1); @@ -538,15 +542,15 @@ walkexpr(Node **np, NodeList **init) case OPRINT: case OPRINTN: walkexprlist(n->list, init); - n = walkprint(n, init, 0); + n = walkprint(n, init); goto ret; case OPANIC: - n = mkcall("panic", T, init, n->left); + n = mkcall("gopanic", T, init, n->left); goto ret; case ORECOVER: - n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N)); + n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N)); goto ret; case OLITERAL: @@ -609,7 +613,7 @@ walkexpr(Node **np, NodeList **init) if(oaslit(n, init)) goto ret; - if(n->right == N) + if(n->right == N || iszero(n->right) && !flag_race) goto ret; switch(n->right->op) { @@ -632,6 +636,7 @@ walkexpr(Node **np, NodeList **init) r = convas(nod(OAS, n->left, n->right), init); r->dodata = n->dodata; n = r; + n = applywritebarrier(n, init); } goto ret; @@ -643,6 +648,8 @@ walkexpr(Node **np, NodeList **init) walkexprlistsafe(n->rlist, init); ll = ascompatee(OAS, n->list, n->rlist, init); ll = reorder3(ll); + for(lr = ll; lr != nil; lr = lr->next) + lr->n = applywritebarrier(lr->n, init); n = liststmt(ll); goto ret; @@ -655,6 +662,8 @@ walkexpr(Node **np, NodeList **init) walkexpr(&r, init); ll = ascompatet(n->op, n->list, &r->type, 0, init); + for(lr = ll; lr != nil; lr = lr->next) + lr->n = applywritebarrier(lr->n, init); n = liststmt(concat(list1(r), ll)); goto ret; @@ -672,7 +681,7 @@ walkexpr(Node **np, NodeList **init) n1 = nod(OADDR, n->list->n, N); n1->etype = 1; // addr does not escape fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1); + r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1); n = nod(OAS, n->list->next->n, r); typecheck(&n, Etop); goto ret; @@ -687,7 +696,7 @@ walkexpr(Node **np, NodeList **init) walkexpr(&r->right, init); t = r->left->type; p = nil; - if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing. + if(t->type->width <= 128) { // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing. switch(simsimtype(t->down)) { case TINT32: case TUINT32: @@ -722,6 +731,12 @@ walkexpr(Node **np, NodeList **init) var->typecheck = 1; fn = mapfn(p, t); r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key); + + // mapaccess2* returns a typed bool, but due to spec changes, + // the boolean result of i.(T) is now untyped so we make it the + // same type as the variable on the lhs. + if(!isblank(n->list->next->n)) + r->type->type->down->type = n->list->next->n->type; n->rlist = list1(r); n->op = OAS2FUNC; n->list->n = var; @@ -769,6 +784,12 @@ walkexpr(Node **np, NodeList **init) *p = '\0'; fn = syslook(buf, 1); + + // runtime.assert(E|I)2TOK returns a typed bool, but due + // to spec changes, the boolean result of i.(T) is now untyped + // so we make it the same type as the variable on the lhs. + if(!isblank(n->list->next->n)) + fn->type->type->down->type->type = n->list->next->n->type; ll = list1(typename(r->type)); ll = list(ll, r->left); argtype(fn, r->left->type); @@ -821,9 +842,7 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); // Optimize convT2E as a two-word copy when T is uintptr-shaped. - if(!isinter(n->left->type) && isnilinter(n->type) && - (n->left->type->width == widthptr) && - isint[simsimtype(n->left->type)]) { + if(isnilinter(n->type) && isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) { l = nod(OEFACE, typename(n->left->type), n->left); l->type = n->type; l->typecheck = n->typecheck; @@ -865,14 +884,13 @@ walkexpr(Node **np, NodeList **init) l->class = PEXTERN; l->xoffset = 0; sym->def = l; - ggloblsym(sym, widthptr, 1, 0); + ggloblsym(sym, widthptr, DUPOK|NOPTR); } l = nod(OADDR, sym->def, N); l->addable = 1; ll = list(ll, l); - if(n->left->type->width == widthptr && - isint[simsimtype(n->left->type)]) { + if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) { /* For pointer types, we can make a special form of optimization * * These statements are put onto the expression init list: @@ -1073,7 +1091,7 @@ walkexpr(Node **np, NodeList **init) t = n->left->type; p = nil; - if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing. + if(t->type->width <= 128) { // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing. switch(simsimtype(t->down)) { case TINT32: case TUINT32: @@ -1371,7 +1389,6 @@ walkexpr(Node **np, NodeList **init) case OMAPLIT: case OSTRUCTLIT: case OPTRLIT: - // XXX TODO do we need to clear var? var = temp(n->type); anylit(0, n, var, init); n = var; @@ -1471,8 +1488,13 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) static int fncall(Node *l, Type *rt) { + Node r; + if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; + memset(&r, 0, sizeof r); + if(needwritebarrier(l, &r)) + return 1; if(eqtype(l->type, rt)) return 0; return 1; @@ -1523,8 +1545,10 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) a = nod(OAS, l, nodarg(r, fp)); a = convas(a, init); ullmancalc(a); - if(a->ullman >= UINF) + if(a->ullman >= UINF) { + dump("ascompatet ucount", a); ucount++; + } nn = list(nn, a); r = structnext(&saver); } @@ -1732,7 +1756,7 @@ ret: // generate code for print static Node* -walkprint(Node *nn, NodeList **init, int defer) +walkprint(Node *nn, NodeList **init) { Node *r; Node *n; @@ -1740,31 +1764,17 @@ walkprint(Node *nn, NodeList **init, int defer) Node *on; Type *t; int notfirst, et, op; - NodeList *calls, *intypes, *args; - Fmt fmt; + NodeList *calls; on = nil; op = nn->op; all = nn->list; calls = nil; notfirst = 0; - intypes = nil; - args = nil; - - memset(&fmt, 0, sizeof fmt); - if(defer) { - // defer print turns into defer printf with format string - fmtstrinit(&fmt); - intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING]))); - args = list1(nod(OXXX, N, N)); - } for(l=all; l; l=l->next) { if(notfirst) { - if(defer) - fmtprint(&fmt, " "); - else - calls = list(calls, mkcall("printsp", T, init)); + calls = list(calls, mkcall("printsp", T, init)); } notfirst = op == OPRINTN; @@ -1792,119 +1802,63 @@ walkprint(Node *nn, NodeList **init, int defer) t = n->type; et = n->type->etype; if(isinter(n->type)) { - if(defer) { - if(isnilinter(n->type)) - fmtprint(&fmt, "%%e"); - else - fmtprint(&fmt, "%%i"); - } else { - if(isnilinter(n->type)) - on = syslook("printeface", 1); - else - on = syslook("printiface", 1); - argtype(on, n->type); // any-1 - } + if(isnilinter(n->type)) + on = syslook("printeface", 1); + else + on = syslook("printiface", 1); + argtype(on, n->type); // any-1 } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) { - if(defer) { - fmtprint(&fmt, "%%p"); - } else { - on = syslook("printpointer", 1); - argtype(on, n->type); // any-1 - } + on = syslook("printpointer", 1); + argtype(on, n->type); // any-1 } else if(isslice(n->type)) { - if(defer) { - fmtprint(&fmt, "%%a"); - } else { - on = syslook("printslice", 1); - argtype(on, n->type); // any-1 - } + on = syslook("printslice", 1); + argtype(on, n->type); // any-1 } else if(isint[et]) { - if(defer) { - if(et == TUINT64) - fmtprint(&fmt, "%%U"); - else { - fmtprint(&fmt, "%%D"); - t = types[TINT64]; - } - } else { - if(et == TUINT64) - on = syslook("printuint", 0); + if(et == TUINT64) { + if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0) + on = syslook("printhex", 0); else - on = syslook("printint", 0); - } - } else if(isfloat[et]) { - if(defer) { - fmtprint(&fmt, "%%f"); - t = types[TFLOAT64]; + on = syslook("printuint", 0); } else - on = syslook("printfloat", 0); + on = syslook("printint", 0); + } else if(isfloat[et]) { + on = syslook("printfloat", 0); } else if(iscomplex[et]) { - if(defer) { - fmtprint(&fmt, "%%C"); - t = types[TCOMPLEX128]; - } else - on = syslook("printcomplex", 0); + on = syslook("printcomplex", 0); } else if(et == TBOOL) { - if(defer) - fmtprint(&fmt, "%%t"); - else - on = syslook("printbool", 0); + on = syslook("printbool", 0); } else if(et == TSTRING) { - if(defer) - fmtprint(&fmt, "%%S"); - else - on = syslook("printstring", 0); + on = syslook("printstring", 0); } else { badtype(OPRINT, n->type, T); continue; } - if(!defer) { - t = *getinarg(on->type); - if(t != nil) - t = t->type; - if(t != nil) - t = t->type; - } + t = *getinarg(on->type); + if(t != nil) + t = t->type; + if(t != nil) + t = t->type; if(!eqtype(t, n->type)) { n = nod(OCONV, n, N); n->type = t; } - if(defer) { - intypes = list(intypes, nod(ODCLFIELD, N, typenod(t))); - args = list(args, n); - } else { - r = nod(OCALL, on, N); - r->list = list1(n); - calls = list(calls, r); - } + r = nod(OCALL, on, N); + r->list = list1(n); + calls = list(calls, r); } - if(defer) { - if(op == OPRINTN) - fmtprint(&fmt, "\n"); - on = syslook("goprintf", 1); - on->type = functype(nil, intypes, nil); - args->n = nod(OLITERAL, N, N); - args->n->val.ctype = CTSTR; - args->n->val.u.sval = strlit(fmtstrflush(&fmt)); - r = nod(OCALL, on, N); - r->list = args; - typecheck(&r, Etop); - walkexpr(&r, init); - } else { - if(op == OPRINTN) - calls = list(calls, mkcall("printnl", T, nil)); - typechecklist(calls, Etop); - walkexprlist(calls, init); + if(op == OPRINTN) + calls = list(calls, mkcall("printnl", T, nil)); + typechecklist(calls, Etop); + walkexprlist(calls, init); - r = nod(OEMPTY, N, N); - typecheck(&r, Etop); - walkexpr(&r, init); - r->ninit = calls; - } + r = nod(OEMPTY, N, N); + typecheck(&r, Etop); + walkexpr(&r, init); + r->ninit = calls; return r; } @@ -1914,11 +1868,166 @@ callnew(Type *t) Node *fn; dowidth(t); - fn = syslook("new", 1); + fn = syslook("newobject", 1); argtype(fn, t); return mkcall1(fn, ptrto(t), nil, typename(t)); } +static int +isstack(Node *n) +{ + while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type)) + n = n->left; + + switch(n->op) { + case OINDREG: + // OINDREG only ends up in walk if it's indirect of SP. + return 1; + + case ONAME: + switch(n->class) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + return 1; + } + break; + } + + return 0; +} + +static int +isglobal(Node *n) +{ + while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type)) + n = n->left; + + switch(n->op) { + case ONAME: + switch(n->class) { + case PEXTERN: + return 1; + } + break; + } + + return 0; +} + +// Do we need a write barrier for the assignment l = r? +int +needwritebarrier(Node *l, Node *r) +{ + if(!use_writebarrier) + return 0; + + if(l == N || isblank(l)) + return 0; + + // No write barrier for write of non-pointers. + dowidth(l->type); + if(!haspointers(l->type)) + return 0; + + // No write barrier for write to stack. + if(isstack(l)) + return 0; + + // No write barrier for implicit or explicit zeroing. + if(r == N || iszero(r)) + return 0; + + // No write barrier for initialization to constant. + if(r->op == OLITERAL) + return 0; + + // No write barrier for storing static (read-only) data. + if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0) + return 0; + + // No write barrier for storing address of stack values, + // which are guaranteed only to be written to the stack. + if(r->op == OADDR && isstack(r->left)) + return 0; + + // No write barrier for storing address of global, which + // is live no matter what. + if(r->op == OADDR && isglobal(r->left)) + return 0; + + // No write barrier for reslice: x = x[0:y] or x = append(x, ...). + // Both are compiled to modify x directly. + // In the case of append, a write barrier may still be needed + // if the underlying array grows, but the append code can + // generate the write barrier directly in that case. + // (It does not yet, but the cost of the write barrier will be + // small compared to the cost of the allocation.) + if(r->reslice) { + switch(r->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + case OAPPEND: + break; + default: + dump("bad reslice-l", l); + dump("bad reslice-r", r); + break; + } + return 0; + } + + // Otherwise, be conservative and use write barrier. + return 1; +} + +// TODO(rsc): Perhaps componentgen should run before this. +static Node* +applywritebarrier(Node *n, NodeList **init) +{ + Node *l, *r; + Type *t; + + if(n->left && n->right && needwritebarrier(n->left, n->right)) { + t = n->left->type; + l = nod(OADDR, n->left, N); + l->etype = 1; // addr does not escape + if(t->width == widthptr) { + n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init, + l, n->right); + } else if(t->etype == TSTRING) { + n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init, + l, n->right); + } else if(isslice(t)) { + n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init, + l, n->right); + } else if(isinter(t)) { + n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init, + l, n->right); + } else if(t->width == 2*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init, + l, nodnil(), n->right); + } else if(t->width == 3*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init, + l, nodnil(), n->right); + } else if(t->width == 4*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init, + l, nodnil(), n->right); + } else { + r = n->right; + while(r->op == OCONVNOP) + r = r->left; + r = nod(OADDR, r, N); + r->etype = 1; // addr does not escape + //warnl(n->lineno, "writebarrierfat %T %N", t, r); + n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init, + typename(t), l, r); + } + } + return n; +} + static Node* convas(Node *n, NodeList **init) { @@ -1958,11 +2067,10 @@ convas(Node *n, NodeList **init) goto out; } - if(eqtype(lt, rt)) - goto out; - - n->right = assignconv(n->right, lt, "assignment"); - walkexpr(&n->right, init); + if(!eqtype(lt, rt)) { + n->right = assignconv(n->right, lt, "assignment"); + walkexpr(&n->right, init); + } out: ullmancalc(n); @@ -2355,6 +2463,8 @@ paramstoheap(Type **argin, int out) continue; // generate allocation & copying code + if(compiling_runtime) + yyerror("%N escapes to heap, not allowed in runtime.", v); if(v->alloc == nil) v->alloc = callnew(v->type); nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); @@ -2511,6 +2621,17 @@ mapfndel(char *name, Type *t) return fn; } +static Node* +writebarrierfn(char *name, Type *l, Type *r) +{ + Node *fn; + + fn = syslook(name, 1); + argtype(fn, l); + argtype(fn, r); + return fn; +} + static Node* addstr(Node *n, NodeList **init) { @@ -2620,7 +2741,7 @@ appendslice(Node *n, NodeList **init) if(l2->type->etype == TSTRING) fn = syslook("slicestringcopy", 1); else - fn = syslook("copy", 1); + fn = syslook("slicecopy", 1); argtype(fn, l1->type); argtype(fn, l2->type); nt = mkcall1(fn, types[TINT], &l, @@ -2758,7 +2879,7 @@ copyany(Node *n, NodeList **init, int runtimecall) if(n->right->type->etype == TSTRING) fn = syslook("slicestringcopy", 1); else - fn = syslook("copy", 1); + fn = syslook("slicecopy", 1); argtype(fn, n->left->type); argtype(fn, n->right->type); return mkcall1(fn, n->type, init, @@ -2863,14 +2984,14 @@ sliceany(Node* n, NodeList **init) lb = N; } - // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison - // generate - // if hb > bound || lb > hb { panicslice() } + // Checking src[lb:hb:cb] or src[lb:hb]. + // if chk0 || chk1 || chk2 { panicslice() } chk = N; - chk0 = N; - chk1 = N; - chk2 = N; + chk0 = N; // cap(src) < cb + chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] + chk2 = N; // hb < lb + // All comparisons are unsigned to avoid testing < 0. bt = types[simtype[TUINT]]; if(cb != N && cb->type->width > 4) bt = types[TUINT64]; @@ -3010,10 +3131,10 @@ eqfor(Type *t) n = newname(sym); n->class = PFUNC; ntype = nod(OTFUNC, N, N); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL])))); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL]))); typecheck(&ntype, Etype); n->type = ntype->type; return n; @@ -3034,10 +3155,9 @@ countfield(Type *t) static void walkcompare(Node **np, NodeList **init) { - Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr; + Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr; int andor, i; Type *t, *t1; - static Node *tempbool; n = *np; @@ -3055,17 +3175,25 @@ walkcompare(Node **np, NodeList **init) break; } - if(!islvalue(n->left) || !islvalue(n->right)) - goto hard; + cmpl = n->left; + while(cmpl != N && cmpl->op == OCONVNOP) + cmpl = cmpl->left; + cmpr = n->right; + while(cmpr != N && cmpr->op == OCONVNOP) + cmpr = cmpr->left; + + if(!islvalue(cmpl) || !islvalue(cmpr)) { + fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr); + } l = temp(ptrto(t)); - a = nod(OAS, l, nod(OADDR, n->left, N)); + a = nod(OAS, l, nod(OADDR, cmpl, N)); a->right->etype = 1; // addr does not escape typecheck(&a, Etop); *init = list(*init, a); r = temp(ptrto(t)); - a = nod(OAS, r, nod(OADDR, n->right, N)); + a = nod(OAS, r, nod(OADDR, cmpr, N)); a->right->etype = 1; // addr does not escape typecheck(&a, Etop); *init = list(*init, a); @@ -3115,57 +3243,16 @@ walkcompare(Node **np, NodeList **init) goto ret; } - // Chose not to inline, but still have addresses. - // Call equality function directly. - // The equality function requires a bool pointer for - // storing its address, because it has to be callable - // from C, and C can't access an ordinary Go return value. - // To avoid creating many temporaries, cache one per function. - if(tempbool == N || tempbool->curfn != curfn) - tempbool = temp(types[TBOOL]); - + // Chose not to inline. Call equality function directly. call = nod(OCALL, eqfor(t), N); - a = nod(OADDR, tempbool, N); - a->etype = 1; // does not escape - call->list = list(call->list, a); - call->list = list(call->list, nodintconst(t->width)); call->list = list(call->list, l); call->list = list(call->list, r); - typecheck(&call, Etop); - walkstmt(&call); - *init = list(*init, call); - - // tempbool cannot be used directly as multiple comparison - // expressions may exist in the same statement. Create another - // temporary to hold the value (its address is not taken so it can - // be optimized away). - r = temp(types[TBOOL]); - a = nod(OAS, r, tempbool); - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - + call->list = list(call->list, nodintconst(t->width)); + r = call; if(n->op != OEQ) r = nod(ONOT, r, N); goto ret; -hard: - // Cannot take address of one or both of the operands. - // Instead, pass directly to runtime helper function. - // Easier on the stack than passing the address - // of temporary variables, because we are better at reusing - // the argument space than temporary variable space. - fn = syslook("equal", 1); - l = n->left; - r = n->right; - argtype(fn, n->left->type); - argtype(fn, n->left->type); - r = mkcall1(fn, n->type, init, typename(n->left->type), l, r); - if(n->op == ONE) { - r = nod(ONOT, r, N); - } - goto ret; - ret: typecheck(&r, Erv); walkexpr(&r, init); @@ -3780,3 +3867,71 @@ candiscard(Node *n) return 1; } + +// rewrite +// print(x, y, z) +// into +// func(a1, a2, a3) { +// print(a1, a2, a3) +// }(x, y, z) +// and same for println. +static void +walkprintfunc(Node **np, NodeList **init) +{ + Node *n; + Node *a, *fn, *t, *oldfn; + NodeList *l, *printargs; + int num; + char buf[100]; + static int prgen; + + n = *np; + + if(n->ninit != nil) { + walkstmtlist(n->ninit); + *init = concat(*init, n->ninit); + n->ninit = nil; + } + + t = nod(OTFUNC, N, N); + num = 0; + printargs = nil; + for(l=n->list; l != nil; l=l->next) { + snprint(buf, sizeof buf, "a%d", num++); + a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type)); + t->list = list(t->list, a); + printargs = list(printargs, a->left); + } + + fn = nod(ODCLFUNC, N, N); + snprint(buf, sizeof buf, "print·%d", ++prgen); + fn->nname = newname(lookup(buf)); + fn->nname->defn = fn; + fn->nname->ntype = t; + declare(fn->nname, PFUNC); + + oldfn = curfn; + curfn = nil; + funchdr(fn); + + a = nod(n->op, N, N); + a->list = printargs; + typecheck(&a, Etop); + walkstmt(&a); + + fn->nbody = list1(a); + + funcbody(fn); + + typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + xtop = list(xtop, fn); + curfn = oldfn; + + a = nod(OCALL, N, N); + a->left = fn->nname; + a->list = n->list; + typecheck(&a, Etop); + walkexpr(&a, init); + *np = a; +} diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c index 08d8ecff2..f464126ac 100644 --- a/src/cmd/gc/y.tab.c +++ b/src/cmd/gc/y.tab.c @@ -440,16 +440,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 2270 +#define YYLAST 2201 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 76 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 142 /* YYNRULES -- Number of rules. */ -#define YYNRULES 351 +#define YYNRULES 352 /* YYNRULES -- Number of states. */ -#define YYNSTATES 667 +#define YYNSTATES 669 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -506,35 +506,35 @@ static const yytype_uint16 yyprhs[] = 129, 132, 137, 141, 146, 150, 152, 155, 157, 159, 162, 164, 168, 172, 176, 179, 182, 186, 192, 198, 201, 202, 207, 208, 212, 213, 216, 217, 222, 227, - 232, 238, 240, 242, 245, 246, 250, 252, 256, 257, - 258, 259, 268, 269, 275, 276, 279, 280, 283, 284, - 285, 293, 294, 300, 302, 306, 310, 314, 318, 322, - 326, 330, 334, 338, 342, 346, 350, 354, 358, 362, - 366, 370, 374, 378, 382, 384, 387, 390, 393, 396, - 399, 402, 405, 408, 412, 418, 425, 427, 429, 433, - 439, 445, 450, 457, 466, 468, 474, 480, 486, 494, - 496, 497, 501, 503, 508, 510, 515, 517, 521, 523, - 525, 527, 529, 531, 533, 535, 536, 538, 540, 542, - 544, 549, 554, 556, 558, 560, 563, 565, 567, 569, - 571, 573, 577, 579, 581, 583, 586, 588, 590, 592, - 594, 598, 600, 602, 604, 606, 608, 610, 612, 614, - 616, 620, 625, 630, 633, 637, 643, 645, 647, 650, - 654, 660, 664, 670, 674, 678, 684, 693, 699, 708, - 714, 715, 719, 720, 722, 726, 728, 733, 736, 737, - 741, 743, 747, 749, 753, 755, 759, 761, 765, 767, - 771, 775, 778, 783, 787, 793, 799, 801, 805, 807, - 810, 812, 816, 821, 823, 826, 829, 831, 833, 837, - 838, 841, 842, 844, 846, 848, 850, 852, 854, 856, - 858, 860, 861, 866, 868, 871, 874, 877, 880, 883, - 886, 888, 892, 894, 898, 900, 904, 906, 910, 912, - 916, 918, 920, 924, 928, 929, 932, 933, 935, 936, - 938, 939, 941, 942, 944, 945, 947, 948, 950, 951, - 953, 954, 956, 957, 959, 964, 969, 975, 982, 987, - 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, - 1014, 1019, 1025, 1030, 1035, 1038, 1041, 1046, 1050, 1054, - 1060, 1064, 1069, 1073, 1079, 1081, 1082, 1084, 1088, 1090, - 1092, 1095, 1097, 1099, 1105, 1106, 1109, 1111, 1115, 1117, - 1121, 1123 + 232, 235, 241, 243, 245, 248, 249, 253, 255, 259, + 260, 261, 262, 271, 272, 278, 279, 282, 283, 286, + 287, 288, 296, 297, 303, 305, 309, 313, 317, 321, + 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, + 365, 369, 373, 377, 381, 385, 387, 390, 393, 396, + 399, 402, 405, 408, 411, 415, 421, 428, 430, 432, + 436, 442, 448, 453, 460, 469, 471, 477, 483, 489, + 497, 499, 500, 504, 506, 511, 513, 518, 520, 524, + 526, 528, 530, 532, 534, 536, 538, 539, 541, 543, + 545, 547, 552, 557, 559, 561, 563, 566, 568, 570, + 572, 574, 576, 580, 582, 584, 586, 589, 591, 593, + 595, 597, 601, 603, 605, 607, 609, 611, 613, 615, + 617, 619, 623, 628, 633, 636, 640, 646, 648, 650, + 653, 657, 663, 667, 673, 677, 681, 687, 696, 702, + 711, 717, 718, 722, 723, 725, 729, 731, 736, 739, + 740, 744, 746, 750, 752, 756, 758, 762, 764, 768, + 770, 774, 778, 781, 786, 790, 796, 802, 804, 808, + 810, 813, 815, 819, 824, 826, 829, 832, 834, 836, + 840, 841, 844, 845, 847, 849, 851, 853, 855, 857, + 859, 861, 863, 864, 869, 871, 874, 877, 880, 883, + 886, 889, 891, 895, 897, 901, 903, 907, 909, 913, + 915, 919, 921, 923, 927, 931, 932, 935, 936, 938, + 939, 941, 942, 944, 945, 947, 948, 950, 951, 953, + 954, 956, 957, 959, 960, 962, 967, 972, 978, 985, + 990, 995, 997, 999, 1001, 1003, 1005, 1007, 1009, 1011, + 1013, 1017, 1022, 1028, 1033, 1038, 1041, 1044, 1049, 1053, + 1057, 1063, 1067, 1072, 1076, 1082, 1084, 1085, 1087, 1091, + 1093, 1095, 1098, 1100, 1102, 1108, 1109, 1112, 1114, 1118, + 1120, 1124, 1126 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ @@ -563,96 +563,96 @@ static const yytype_int16 yyrhs[] = -1, -1, 67, 101, 183, 68, -1, -1, 99, 103, 183, -1, -1, 104, 102, -1, -1, 35, 106, 183, 68, -1, 186, 65, 26, 126, -1, 186, 5, 26, - 126, -1, 194, 62, 194, 62, 194, -1, 194, -1, - 107, -1, 108, 105, -1, -1, 16, 111, 109, -1, - 194, -1, 194, 62, 194, -1, -1, -1, -1, 20, - 114, 112, 115, 105, 116, 119, 120, -1, -1, 14, - 20, 118, 112, 105, -1, -1, 119, 117, -1, -1, - 14, 100, -1, -1, -1, 30, 122, 112, 123, 35, - 104, 68, -1, -1, 28, 125, 35, 104, 68, -1, - 127, -1, 126, 47, 126, -1, 126, 33, 126, -1, - 126, 38, 126, -1, 126, 46, 126, -1, 126, 45, - 126, -1, 126, 43, 126, -1, 126, 39, 126, -1, - 126, 40, 126, -1, 126, 49, 126, -1, 126, 50, - 126, -1, 126, 51, 126, -1, 126, 52, 126, -1, - 126, 53, 126, -1, 126, 54, 126, -1, 126, 55, - 126, -1, 126, 56, 126, -1, 126, 34, 126, -1, - 126, 44, 126, -1, 126, 48, 126, -1, 126, 36, - 126, -1, 134, -1, 53, 127, -1, 56, 127, -1, - 49, 127, -1, 50, 127, -1, 69, 127, -1, 70, - 127, -1, 52, 127, -1, 36, 127, -1, 134, 59, - 60, -1, 134, 59, 187, 191, 60, -1, 134, 59, - 187, 11, 191, 60, -1, 3, -1, 143, -1, 134, - 63, 141, -1, 134, 63, 59, 135, 60, -1, 134, - 63, 59, 31, 60, -1, 134, 71, 126, 72, -1, - 134, 71, 192, 66, 192, 72, -1, 134, 71, 192, - 66, 192, 66, 192, 72, -1, 128, -1, 149, 59, - 126, 191, 60, -1, 150, 137, 130, 189, 68, -1, - 129, 67, 130, 189, 68, -1, 59, 135, 60, 67, - 130, 189, 68, -1, 165, -1, -1, 126, 66, 133, - -1, 126, -1, 67, 130, 189, 68, -1, 126, -1, - 67, 130, 189, 68, -1, 129, -1, 59, 135, 60, - -1, 126, -1, 147, -1, 146, -1, 35, -1, 67, - -1, 141, -1, 141, -1, -1, 138, -1, 24, -1, - 142, -1, 73, -1, 74, 3, 63, 24, -1, 74, - 3, 63, 73, -1, 141, -1, 138, -1, 11, -1, - 11, 146, -1, 155, -1, 161, -1, 153, -1, 154, - -1, 152, -1, 59, 146, 60, -1, 155, -1, 161, - -1, 153, -1, 53, 147, -1, 161, -1, 153, -1, - 154, -1, 152, -1, 59, 146, 60, -1, 161, -1, - 153, -1, 153, -1, 155, -1, 161, -1, 153, -1, - 154, -1, 152, -1, 143, -1, 143, 63, 141, -1, - 71, 192, 72, 146, -1, 71, 11, 72, 146, -1, - 8, 148, -1, 8, 36, 146, -1, 23, 71, 146, - 72, 146, -1, 156, -1, 157, -1, 53, 146, -1, - 36, 8, 146, -1, 29, 137, 170, 190, 68, -1, - 29, 137, 68, -1, 22, 137, 171, 190, 68, -1, - 22, 137, 68, -1, 17, 159, 162, -1, 141, 59, - 179, 60, 163, -1, 59, 179, 60, 141, 59, 179, - 60, 163, -1, 200, 59, 195, 60, 210, -1, 59, - 215, 60, 141, 59, 195, 60, 210, -1, 17, 59, - 179, 60, 163, -1, -1, 67, 183, 68, -1, -1, - 151, -1, 59, 179, 60, -1, 161, -1, 164, 137, - 183, 68, -1, 164, 1, -1, -1, 166, 90, 62, - -1, 93, -1, 167, 62, 93, -1, 95, -1, 168, - 62, 95, -1, 97, -1, 169, 62, 97, -1, 172, - -1, 170, 62, 172, -1, 175, -1, 171, 62, 175, - -1, 184, 146, 198, -1, 174, 198, -1, 59, 174, - 60, 198, -1, 53, 174, 198, -1, 59, 53, 174, - 60, 198, -1, 53, 59, 174, 60, 198, -1, 24, - -1, 24, 63, 141, -1, 173, -1, 138, 176, -1, - 173, -1, 59, 173, 60, -1, 59, 179, 60, 163, - -1, 136, -1, 141, 136, -1, 141, 145, -1, 145, - -1, 177, -1, 178, 75, 177, -1, -1, 178, 191, - -1, -1, 100, -1, 91, -1, 181, -1, 1, -1, - 98, -1, 110, -1, 121, -1, 124, -1, 113, -1, - -1, 144, 66, 182, 180, -1, 15, -1, 6, 140, - -1, 10, 140, -1, 18, 128, -1, 13, 128, -1, - 19, 138, -1, 27, 193, -1, 180, -1, 183, 62, - 180, -1, 138, -1, 184, 75, 138, -1, 139, -1, - 185, 75, 139, -1, 126, -1, 186, 75, 126, -1, - 135, -1, 187, 75, 135, -1, 131, -1, 132, -1, - 188, 75, 131, -1, 188, 75, 132, -1, -1, 188, - 191, -1, -1, 62, -1, -1, 75, -1, -1, 126, - -1, -1, 186, -1, -1, 98, -1, -1, 215, -1, - -1, 216, -1, -1, 217, -1, -1, 3, -1, 21, - 24, 3, 62, -1, 32, 200, 202, 62, -1, 9, - 200, 65, 213, 62, -1, 9, 200, 202, 65, 213, - 62, -1, 31, 201, 202, 62, -1, 17, 160, 162, - 62, -1, 142, -1, 200, -1, 204, -1, 205, -1, - 206, -1, 204, -1, 206, -1, 142, -1, 24, -1, - 71, 72, 202, -1, 71, 3, 72, 202, -1, 23, - 71, 202, 72, 202, -1, 29, 67, 196, 68, -1, - 22, 67, 197, 68, -1, 53, 202, -1, 8, 203, - -1, 8, 59, 205, 60, -1, 8, 36, 202, -1, - 36, 8, 202, -1, 17, 59, 195, 60, 210, -1, - 141, 202, 198, -1, 141, 11, 202, 198, -1, 141, - 202, 198, -1, 141, 59, 195, 60, 210, -1, 202, - -1, -1, 211, -1, 59, 195, 60, -1, 202, -1, - 3, -1, 50, 3, -1, 141, -1, 212, -1, 59, - 212, 49, 212, 60, -1, -1, 214, 199, -1, 207, - -1, 215, 75, 207, -1, 208, -1, 216, 62, 208, - -1, 209, -1, 217, 62, 209, -1 + 126, -1, 26, 126, -1, 194, 62, 194, 62, 194, + -1, 194, -1, 107, -1, 108, 105, -1, -1, 16, + 111, 109, -1, 194, -1, 194, 62, 194, -1, -1, + -1, -1, 20, 114, 112, 115, 105, 116, 119, 120, + -1, -1, 14, 20, 118, 112, 105, -1, -1, 119, + 117, -1, -1, 14, 100, -1, -1, -1, 30, 122, + 112, 123, 35, 104, 68, -1, -1, 28, 125, 35, + 104, 68, -1, 127, -1, 126, 47, 126, -1, 126, + 33, 126, -1, 126, 38, 126, -1, 126, 46, 126, + -1, 126, 45, 126, -1, 126, 43, 126, -1, 126, + 39, 126, -1, 126, 40, 126, -1, 126, 49, 126, + -1, 126, 50, 126, -1, 126, 51, 126, -1, 126, + 52, 126, -1, 126, 53, 126, -1, 126, 54, 126, + -1, 126, 55, 126, -1, 126, 56, 126, -1, 126, + 34, 126, -1, 126, 44, 126, -1, 126, 48, 126, + -1, 126, 36, 126, -1, 134, -1, 53, 127, -1, + 56, 127, -1, 49, 127, -1, 50, 127, -1, 69, + 127, -1, 70, 127, -1, 52, 127, -1, 36, 127, + -1, 134, 59, 60, -1, 134, 59, 187, 191, 60, + -1, 134, 59, 187, 11, 191, 60, -1, 3, -1, + 143, -1, 134, 63, 141, -1, 134, 63, 59, 135, + 60, -1, 134, 63, 59, 31, 60, -1, 134, 71, + 126, 72, -1, 134, 71, 192, 66, 192, 72, -1, + 134, 71, 192, 66, 192, 66, 192, 72, -1, 128, + -1, 149, 59, 126, 191, 60, -1, 150, 137, 130, + 189, 68, -1, 129, 67, 130, 189, 68, -1, 59, + 135, 60, 67, 130, 189, 68, -1, 165, -1, -1, + 126, 66, 133, -1, 126, -1, 67, 130, 189, 68, + -1, 126, -1, 67, 130, 189, 68, -1, 129, -1, + 59, 135, 60, -1, 126, -1, 147, -1, 146, -1, + 35, -1, 67, -1, 141, -1, 141, -1, -1, 138, + -1, 24, -1, 142, -1, 73, -1, 74, 3, 63, + 24, -1, 74, 3, 63, 73, -1, 141, -1, 138, + -1, 11, -1, 11, 146, -1, 155, -1, 161, -1, + 153, -1, 154, -1, 152, -1, 59, 146, 60, -1, + 155, -1, 161, -1, 153, -1, 53, 147, -1, 161, + -1, 153, -1, 154, -1, 152, -1, 59, 146, 60, + -1, 161, -1, 153, -1, 153, -1, 155, -1, 161, + -1, 153, -1, 154, -1, 152, -1, 143, -1, 143, + 63, 141, -1, 71, 192, 72, 146, -1, 71, 11, + 72, 146, -1, 8, 148, -1, 8, 36, 146, -1, + 23, 71, 146, 72, 146, -1, 156, -1, 157, -1, + 53, 146, -1, 36, 8, 146, -1, 29, 137, 170, + 190, 68, -1, 29, 137, 68, -1, 22, 137, 171, + 190, 68, -1, 22, 137, 68, -1, 17, 159, 162, + -1, 141, 59, 179, 60, 163, -1, 59, 179, 60, + 141, 59, 179, 60, 163, -1, 200, 59, 195, 60, + 210, -1, 59, 215, 60, 141, 59, 195, 60, 210, + -1, 17, 59, 179, 60, 163, -1, -1, 67, 183, + 68, -1, -1, 151, -1, 59, 179, 60, -1, 161, + -1, 164, 137, 183, 68, -1, 164, 1, -1, -1, + 166, 90, 62, -1, 93, -1, 167, 62, 93, -1, + 95, -1, 168, 62, 95, -1, 97, -1, 169, 62, + 97, -1, 172, -1, 170, 62, 172, -1, 175, -1, + 171, 62, 175, -1, 184, 146, 198, -1, 174, 198, + -1, 59, 174, 60, 198, -1, 53, 174, 198, -1, + 59, 53, 174, 60, 198, -1, 53, 59, 174, 60, + 198, -1, 24, -1, 24, 63, 141, -1, 173, -1, + 138, 176, -1, 173, -1, 59, 173, 60, -1, 59, + 179, 60, 163, -1, 136, -1, 141, 136, -1, 141, + 145, -1, 145, -1, 177, -1, 178, 75, 177, -1, + -1, 178, 191, -1, -1, 100, -1, 91, -1, 181, + -1, 1, -1, 98, -1, 110, -1, 121, -1, 124, + -1, 113, -1, -1, 144, 66, 182, 180, -1, 15, + -1, 6, 140, -1, 10, 140, -1, 18, 128, -1, + 13, 128, -1, 19, 138, -1, 27, 193, -1, 180, + -1, 183, 62, 180, -1, 138, -1, 184, 75, 138, + -1, 139, -1, 185, 75, 139, -1, 126, -1, 186, + 75, 126, -1, 135, -1, 187, 75, 135, -1, 131, + -1, 132, -1, 188, 75, 131, -1, 188, 75, 132, + -1, -1, 188, 191, -1, -1, 62, -1, -1, 75, + -1, -1, 126, -1, -1, 186, -1, -1, 98, -1, + -1, 215, -1, -1, 216, -1, -1, 217, -1, -1, + 3, -1, 21, 24, 3, 62, -1, 32, 200, 202, + 62, -1, 9, 200, 65, 213, 62, -1, 9, 200, + 202, 65, 213, 62, -1, 31, 201, 202, 62, -1, + 17, 160, 162, 62, -1, 142, -1, 200, -1, 204, + -1, 205, -1, 206, -1, 204, -1, 206, -1, 142, + -1, 24, -1, 71, 72, 202, -1, 71, 3, 72, + 202, -1, 23, 71, 202, 72, 202, -1, 29, 67, + 196, 68, -1, 22, 67, 197, 68, -1, 53, 202, + -1, 8, 203, -1, 8, 59, 205, 60, -1, 8, + 36, 202, -1, 36, 8, 202, -1, 17, 59, 195, + 60, 210, -1, 141, 202, 198, -1, 141, 11, 202, + 198, -1, 141, 202, 198, -1, 141, 59, 195, 60, + 210, -1, 202, -1, -1, 211, -1, 59, 195, 60, + -1, 202, -1, 3, -1, 50, 3, -1, 141, -1, + 212, -1, 59, 212, 49, 212, 60, -1, -1, 214, + 199, -1, 207, -1, 215, 75, 207, -1, 208, -1, + 216, 62, 208, -1, 209, -1, 217, 62, 209, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -663,37 +663,37 @@ static const yytype_uint16 yyrline[] = 263, 264, 271, 271, 284, 288, 289, 293, 298, 304, 308, 312, 316, 322, 328, 334, 339, 343, 347, 353, 359, 363, 367, 373, 377, 383, 384, 388, 394, 403, - 409, 427, 432, 444, 460, 465, 472, 492, 510, 519, - 538, 537, 552, 551, 583, 586, 593, 592, 603, 609, - 618, 629, 635, 638, 646, 645, 656, 662, 674, 678, - 683, 673, 704, 703, 716, 719, 725, 728, 740, 744, - 739, 762, 761, 777, 778, 782, 786, 790, 794, 798, - 802, 806, 810, 814, 818, 822, 826, 830, 834, 838, - 842, 846, 850, 855, 861, 862, 866, 877, 881, 885, - 889, 894, 898, 908, 912, 917, 925, 929, 930, 941, - 945, 949, 953, 957, 965, 966, 972, 979, 985, 992, - 995, 1002, 1008, 1025, 1032, 1033, 1040, 1041, 1060, 1061, - 1064, 1067, 1071, 1082, 1091, 1097, 1100, 1103, 1110, 1111, - 1117, 1130, 1145, 1153, 1165, 1170, 1176, 1177, 1178, 1179, - 1180, 1181, 1187, 1188, 1189, 1190, 1196, 1197, 1198, 1199, - 1200, 1206, 1207, 1210, 1213, 1214, 1215, 1216, 1217, 1220, - 1221, 1234, 1238, 1243, 1248, 1253, 1257, 1258, 1261, 1267, - 1274, 1280, 1287, 1293, 1304, 1318, 1347, 1387, 1412, 1430, - 1439, 1442, 1450, 1454, 1458, 1465, 1471, 1476, 1488, 1491, - 1501, 1502, 1508, 1509, 1515, 1519, 1525, 1526, 1532, 1536, - 1542, 1565, 1570, 1576, 1582, 1589, 1598, 1607, 1622, 1628, - 1633, 1637, 1644, 1657, 1658, 1664, 1670, 1673, 1677, 1683, - 1686, 1695, 1698, 1699, 1703, 1704, 1710, 1711, 1712, 1713, - 1714, 1716, 1715, 1730, 1736, 1740, 1744, 1748, 1752, 1757, - 1776, 1782, 1790, 1794, 1800, 1804, 1810, 1814, 1820, 1824, - 1833, 1837, 1841, 1845, 1851, 1854, 1862, 1863, 1865, 1866, - 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, - 1899, 1902, 1905, 1908, 1914, 1918, 1922, 1926, 1930, 1934, - 1954, 1961, 1972, 1973, 1974, 1977, 1978, 1981, 1985, 1995, - 1999, 2003, 2007, 2011, 2015, 2019, 2025, 2031, 2039, 2047, - 2053, 2060, 2076, 2098, 2102, 2108, 2111, 2114, 2118, 2128, - 2132, 2151, 2159, 2160, 2172, 2173, 2176, 2180, 2186, 2190, - 2196, 2200 + 409, 427, 432, 444, 460, 466, 474, 494, 512, 521, + 540, 539, 554, 553, 585, 588, 595, 594, 605, 611, + 618, 625, 636, 642, 645, 653, 652, 663, 669, 681, + 685, 690, 680, 711, 710, 723, 726, 732, 735, 747, + 751, 746, 769, 768, 784, 785, 789, 793, 797, 801, + 805, 809, 813, 817, 821, 825, 829, 833, 837, 841, + 845, 849, 853, 857, 862, 868, 869, 873, 884, 888, + 892, 896, 901, 905, 915, 919, 924, 932, 936, 937, + 948, 952, 956, 960, 964, 972, 973, 979, 986, 992, + 999, 1002, 1009, 1015, 1032, 1039, 1040, 1047, 1048, 1067, + 1068, 1071, 1074, 1078, 1089, 1098, 1104, 1107, 1110, 1117, + 1118, 1124, 1137, 1152, 1160, 1172, 1177, 1183, 1184, 1185, + 1186, 1187, 1188, 1194, 1195, 1196, 1197, 1203, 1204, 1205, + 1206, 1207, 1213, 1214, 1217, 1220, 1221, 1222, 1223, 1224, + 1227, 1228, 1241, 1245, 1250, 1255, 1260, 1264, 1265, 1268, + 1274, 1281, 1287, 1294, 1300, 1311, 1326, 1355, 1393, 1418, + 1436, 1445, 1448, 1456, 1460, 1464, 1471, 1477, 1482, 1494, + 1497, 1508, 1509, 1515, 1516, 1522, 1526, 1532, 1533, 1539, + 1543, 1549, 1572, 1577, 1583, 1589, 1596, 1605, 1614, 1629, + 1635, 1640, 1644, 1651, 1664, 1665, 1671, 1677, 1680, 1684, + 1690, 1693, 1702, 1705, 1706, 1710, 1711, 1717, 1718, 1719, + 1720, 1721, 1723, 1722, 1737, 1743, 1747, 1751, 1755, 1759, + 1764, 1783, 1789, 1797, 1801, 1807, 1811, 1817, 1821, 1827, + 1831, 1840, 1844, 1848, 1852, 1858, 1861, 1869, 1870, 1872, + 1873, 1876, 1879, 1882, 1885, 1888, 1891, 1894, 1897, 1900, + 1903, 1906, 1909, 1912, 1915, 1921, 1925, 1929, 1933, 1937, + 1941, 1961, 1968, 1979, 1980, 1981, 1984, 1985, 1988, 1992, + 2002, 2006, 2010, 2014, 2018, 2022, 2026, 2032, 2038, 2046, + 2054, 2060, 2067, 2083, 2105, 2109, 2115, 2118, 2121, 2125, + 2135, 2139, 2158, 2166, 2167, 2179, 2180, 2183, 2187, 2193, + 2197, 2203, 2207 }; #endif @@ -772,35 +772,35 @@ static const yytype_uint8 yyr1[] = 93, 93, 93, 94, 94, 95, 95, 95, 96, 97, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 101, 100, 103, 102, 104, 104, 106, 105, 107, 107, - 108, 108, 108, 109, 111, 110, 112, 112, 114, 115, - 116, 113, 118, 117, 119, 119, 120, 120, 122, 123, - 121, 125, 124, 126, 126, 126, 126, 126, 126, 126, + 107, 108, 108, 108, 109, 111, 110, 112, 112, 114, + 115, 116, 113, 118, 117, 119, 119, 120, 120, 122, + 123, 121, 125, 124, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 128, 128, 128, 129, 129, 129, 129, + 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 128, 128, 128, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 130, 131, 132, 132, 133, 133, 134, 134, 135, 135, - 136, 137, 137, 138, 139, 140, 140, 141, 141, 141, - 142, 142, 143, 144, 145, 145, 146, 146, 146, 146, - 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, - 148, 149, 149, 150, 151, 151, 151, 151, 151, 152, - 152, 153, 153, 153, 153, 153, 153, 153, 154, 155, - 156, 156, 157, 157, 158, 159, 159, 160, 160, 161, - 162, 162, 163, 163, 163, 164, 165, 165, 166, 166, - 167, 167, 168, 168, 169, 169, 170, 170, 171, 171, - 172, 172, 172, 172, 172, 172, 173, 173, 174, 175, - 175, 175, 176, 177, 177, 177, 177, 178, 178, 179, - 179, 180, 180, 180, 180, 180, 181, 181, 181, 181, - 181, 182, 181, 181, 181, 181, 181, 181, 181, 181, - 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, - 188, 188, 188, 188, 189, 189, 190, 190, 191, 191, - 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, - 197, 197, 198, 198, 199, 199, 199, 199, 199, 199, - 200, 201, 202, 202, 202, 203, 203, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 205, 206, - 207, 207, 208, 209, 209, 210, 210, 211, 211, 212, - 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, - 217, 217 + 129, 130, 131, 132, 132, 133, 133, 134, 134, 135, + 135, 136, 137, 137, 138, 139, 140, 140, 141, 141, + 141, 142, 142, 143, 144, 145, 145, 146, 146, 146, + 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, + 148, 148, 149, 149, 150, 151, 151, 151, 151, 151, + 152, 152, 153, 153, 153, 153, 153, 153, 153, 154, + 155, 156, 156, 157, 157, 158, 159, 159, 160, 160, + 161, 162, 162, 163, 163, 163, 164, 165, 165, 166, + 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, + 171, 172, 172, 172, 172, 172, 172, 173, 173, 174, + 175, 175, 175, 176, 177, 177, 177, 177, 178, 178, + 179, 179, 180, 180, 180, 180, 180, 181, 181, 181, + 181, 181, 182, 181, 181, 181, 181, 181, 181, 181, + 181, 183, 183, 184, 184, 185, 185, 186, 186, 187, + 187, 188, 188, 188, 188, 189, 189, 190, 190, 191, + 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, + 196, 197, 197, 198, 198, 199, 199, 199, 199, 199, + 199, 200, 201, 202, 202, 202, 203, 203, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 205, + 206, 207, 207, 208, 209, 209, 210, 210, 211, 211, + 212, 212, 212, 213, 213, 214, 214, 215, 215, 216, + 216, 217, 217 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -813,35 +813,35 @@ static const yytype_uint8 yyr2[] = 2, 4, 3, 4, 3, 1, 2, 1, 1, 2, 1, 3, 3, 3, 2, 2, 3, 5, 5, 2, 0, 4, 0, 3, 0, 2, 0, 4, 4, 4, - 5, 1, 1, 2, 0, 3, 1, 3, 0, 0, - 0, 8, 0, 5, 0, 2, 0, 2, 0, 0, - 7, 0, 5, 1, 3, 3, 3, 3, 3, 3, + 2, 5, 1, 1, 2, 0, 3, 1, 3, 0, + 0, 0, 8, 0, 5, 0, 2, 0, 2, 0, + 0, 7, 0, 5, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 5, 6, 1, 1, 3, 5, - 5, 4, 6, 8, 1, 5, 5, 5, 7, 1, - 0, 3, 1, 4, 1, 4, 1, 3, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 4, 4, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 3, 4, 4, 2, 3, 5, 1, 1, 2, 3, - 5, 3, 5, 3, 3, 5, 8, 5, 8, 5, - 0, 3, 0, 1, 3, 1, 4, 2, 0, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 3, 2, 4, 3, 5, 5, 1, 3, 1, 2, - 1, 3, 4, 1, 2, 2, 1, 1, 3, 0, - 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 4, 1, 2, 2, 2, 2, 2, 2, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 1, 3, 3, 0, 2, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 4, 4, 5, 6, 4, 4, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, - 4, 5, 4, 4, 2, 2, 4, 3, 3, 5, - 3, 4, 3, 5, 1, 0, 1, 3, 1, 1, - 2, 1, 1, 5, 0, 2, 1, 3, 1, 3, - 1, 3 + 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 5, 6, 1, 1, 3, + 5, 5, 4, 6, 8, 1, 5, 5, 5, 7, + 1, 0, 3, 1, 4, 1, 4, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 4, 4, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 4, 4, 2, 3, 5, 1, 1, 2, + 3, 5, 3, 5, 3, 3, 5, 8, 5, 8, + 5, 0, 3, 0, 1, 3, 1, 4, 2, 0, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 3, 2, 4, 3, 5, 5, 1, 3, 1, + 2, 1, 3, 4, 1, 2, 2, 1, 1, 3, + 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 4, 1, 2, 2, 2, 2, 2, + 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 1, 3, 3, 0, 2, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 4, 4, 5, 6, 4, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 4, 5, 4, 4, 2, 2, 4, 3, 3, + 5, 3, 4, 3, 5, 1, 0, 1, 3, 1, + 1, 2, 1, 1, 5, 0, 2, 1, 3, 1, + 3, 1, 3 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -849,656 +849,642 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 5, 0, 3, 0, 1, 0, 7, 0, 22, 157, - 159, 0, 0, 158, 218, 20, 6, 344, 0, 4, + 5, 0, 3, 0, 1, 0, 7, 0, 22, 158, + 160, 0, 0, 159, 219, 20, 6, 345, 0, 4, 0, 0, 0, 21, 0, 0, 0, 16, 0, 0, - 9, 22, 0, 8, 28, 126, 155, 0, 39, 155, - 0, 263, 74, 0, 0, 0, 78, 0, 0, 292, - 91, 0, 88, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 290, 0, 25, 0, 256, 257, - 260, 258, 259, 50, 93, 134, 146, 114, 163, 162, - 127, 0, 0, 0, 183, 196, 197, 26, 215, 0, - 139, 27, 0, 19, 0, 0, 0, 0, 0, 0, - 345, 160, 161, 11, 14, 286, 18, 22, 13, 17, - 156, 264, 153, 0, 0, 0, 0, 162, 189, 193, - 179, 177, 178, 176, 265, 134, 0, 294, 249, 0, - 210, 134, 268, 294, 151, 152, 0, 0, 276, 293, - 269, 0, 0, 294, 0, 0, 36, 48, 0, 29, - 274, 154, 0, 122, 117, 118, 121, 115, 116, 0, - 0, 148, 0, 149, 174, 172, 173, 119, 120, 0, - 291, 0, 219, 0, 32, 0, 0, 0, 0, 0, + 9, 22, 0, 8, 28, 127, 156, 0, 39, 156, + 0, 264, 75, 0, 0, 0, 79, 0, 0, 293, + 92, 0, 89, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 291, 0, 25, 0, 257, 258, + 261, 259, 260, 50, 94, 135, 147, 115, 164, 163, + 128, 0, 0, 0, 184, 197, 198, 26, 216, 0, + 140, 27, 0, 19, 0, 0, 0, 0, 0, 0, + 346, 161, 162, 11, 14, 287, 18, 22, 13, 17, + 157, 265, 154, 0, 0, 0, 0, 163, 190, 194, + 180, 178, 179, 177, 266, 135, 0, 295, 250, 0, + 211, 135, 269, 295, 152, 153, 0, 0, 277, 294, + 270, 0, 0, 295, 0, 0, 36, 48, 0, 29, + 275, 155, 0, 123, 118, 119, 122, 116, 117, 0, + 0, 149, 0, 150, 175, 173, 174, 120, 121, 0, + 292, 0, 220, 0, 32, 0, 0, 0, 0, 0, 55, 0, 0, 0, 54, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, - 0, 0, 290, 261, 0, 140, 217, 0, 0, 0, - 0, 310, 0, 0, 210, 0, 0, 311, 0, 0, - 23, 287, 0, 12, 249, 0, 0, 194, 170, 168, - 169, 166, 167, 198, 0, 0, 295, 72, 0, 75, - 0, 71, 164, 243, 162, 246, 150, 247, 288, 0, - 249, 0, 204, 79, 76, 157, 0, 203, 0, 286, - 240, 228, 0, 64, 0, 0, 201, 272, 286, 226, - 238, 302, 0, 89, 38, 224, 286, 49, 31, 220, - 286, 0, 0, 40, 0, 175, 147, 0, 0, 35, - 286, 0, 0, 51, 95, 110, 113, 96, 100, 101, - 99, 111, 98, 97, 94, 112, 102, 103, 104, 105, - 106, 107, 108, 109, 284, 123, 278, 288, 0, 128, - 291, 0, 0, 288, 284, 255, 60, 253, 252, 270, - 254, 0, 53, 52, 277, 0, 0, 0, 0, 318, - 0, 0, 0, 0, 0, 317, 0, 312, 313, 314, - 0, 346, 0, 0, 296, 0, 0, 0, 15, 10, - 0, 0, 0, 180, 190, 66, 73, 0, 0, 294, - 165, 244, 245, 289, 250, 212, 0, 0, 0, 294, - 0, 236, 0, 249, 239, 287, 0, 0, 0, 0, - 302, 0, 0, 287, 0, 303, 231, 0, 302, 0, - 287, 0, 287, 0, 42, 275, 0, 0, 0, 199, - 170, 168, 169, 167, 140, 192, 191, 287, 0, 44, - 0, 140, 142, 280, 281, 288, 0, 288, 289, 0, - 0, 0, 131, 290, 262, 289, 0, 0, 0, 0, - 216, 0, 0, 325, 315, 316, 296, 300, 0, 298, - 0, 324, 339, 0, 0, 341, 342, 0, 0, 0, - 0, 0, 302, 0, 0, 309, 0, 297, 304, 308, - 305, 212, 171, 0, 0, 0, 0, 248, 249, 162, - 213, 188, 186, 187, 184, 185, 209, 212, 211, 80, - 77, 237, 241, 0, 229, 202, 195, 0, 0, 92, - 62, 65, 0, 233, 0, 302, 227, 200, 273, 230, - 64, 225, 37, 221, 30, 41, 0, 284, 45, 222, - 286, 47, 33, 43, 284, 0, 289, 285, 137, 0, - 279, 124, 130, 129, 0, 135, 136, 0, 271, 327, - 0, 0, 318, 0, 317, 0, 334, 350, 301, 0, - 0, 0, 348, 299, 328, 340, 0, 306, 0, 319, - 0, 302, 330, 0, 347, 335, 0, 69, 68, 294, - 0, 249, 205, 84, 212, 0, 59, 0, 302, 302, - 232, 0, 171, 0, 287, 0, 46, 0, 140, 144, - 141, 282, 283, 125, 290, 132, 61, 326, 335, 296, - 323, 0, 0, 302, 322, 0, 0, 320, 307, 331, - 296, 296, 338, 207, 336, 67, 70, 214, 0, 86, - 242, 0, 0, 56, 0, 63, 235, 234, 90, 138, - 223, 34, 143, 284, 0, 329, 0, 351, 321, 332, - 349, 0, 0, 0, 212, 0, 85, 81, 0, 0, - 0, 133, 335, 343, 335, 337, 206, 82, 87, 58, - 57, 145, 333, 208, 294, 0, 83 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, + 0, 0, 291, 262, 0, 141, 218, 0, 0, 0, + 0, 311, 0, 0, 211, 0, 0, 312, 0, 0, + 23, 288, 0, 12, 250, 0, 0, 195, 171, 169, + 170, 167, 168, 199, 0, 0, 0, 296, 73, 0, + 76, 0, 72, 165, 244, 163, 247, 151, 248, 289, + 0, 250, 0, 205, 80, 77, 158, 0, 204, 0, + 287, 241, 229, 0, 64, 0, 0, 202, 273, 287, + 227, 239, 303, 0, 90, 38, 225, 287, 49, 31, + 221, 287, 0, 0, 40, 0, 176, 148, 0, 0, + 35, 287, 0, 0, 51, 96, 111, 114, 97, 101, + 102, 100, 112, 99, 98, 95, 113, 103, 104, 105, + 106, 107, 108, 109, 110, 285, 124, 279, 289, 0, + 129, 292, 0, 0, 289, 285, 256, 60, 254, 253, + 271, 255, 0, 53, 52, 278, 0, 0, 0, 0, + 319, 0, 0, 0, 0, 0, 318, 0, 313, 314, + 315, 0, 347, 0, 0, 297, 0, 0, 0, 15, + 10, 0, 0, 0, 181, 191, 70, 66, 74, 0, + 0, 295, 166, 245, 246, 290, 251, 213, 0, 0, + 0, 295, 0, 237, 0, 250, 240, 288, 0, 0, + 0, 0, 303, 0, 0, 288, 0, 304, 232, 0, + 303, 0, 288, 0, 288, 0, 42, 276, 0, 0, + 0, 200, 171, 169, 170, 168, 141, 193, 192, 288, + 0, 44, 0, 141, 143, 281, 282, 289, 0, 289, + 290, 0, 0, 0, 132, 291, 263, 290, 0, 0, + 0, 0, 217, 0, 0, 326, 316, 317, 297, 301, + 0, 299, 0, 325, 340, 0, 0, 342, 343, 0, + 0, 0, 0, 0, 303, 0, 0, 310, 0, 298, + 305, 309, 306, 213, 172, 0, 0, 0, 0, 249, + 250, 163, 214, 189, 187, 188, 185, 186, 210, 213, + 212, 81, 78, 238, 242, 0, 230, 203, 196, 0, + 0, 93, 62, 65, 0, 234, 0, 303, 228, 201, + 274, 231, 64, 226, 37, 222, 30, 41, 0, 285, + 45, 223, 287, 47, 33, 43, 285, 0, 290, 286, + 138, 0, 280, 125, 131, 130, 0, 136, 137, 0, + 272, 328, 0, 0, 319, 0, 318, 0, 335, 351, + 302, 0, 0, 0, 349, 300, 329, 341, 0, 307, + 0, 320, 0, 303, 331, 0, 348, 336, 0, 69, + 68, 295, 0, 250, 206, 85, 213, 0, 59, 0, + 303, 303, 233, 0, 172, 0, 288, 0, 46, 0, + 141, 145, 142, 283, 284, 126, 291, 133, 61, 327, + 336, 297, 324, 0, 0, 303, 323, 0, 0, 321, + 308, 332, 297, 297, 339, 208, 337, 67, 71, 215, + 0, 87, 243, 0, 0, 56, 0, 63, 236, 235, + 91, 139, 224, 34, 144, 285, 0, 330, 0, 352, + 322, 333, 350, 0, 0, 0, 213, 0, 86, 82, + 0, 0, 0, 134, 336, 344, 336, 338, 207, 83, + 88, 58, 57, 146, 334, 209, 295, 0, 84 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 1, 6, 2, 3, 14, 21, 30, 105, 31, - 8, 24, 16, 17, 65, 327, 67, 149, 518, 519, - 145, 146, 68, 500, 328, 438, 501, 577, 388, 366, - 473, 237, 238, 239, 69, 127, 253, 70, 133, 378, - 573, 646, 664, 619, 647, 71, 143, 399, 72, 141, - 73, 74, 75, 76, 314, 423, 424, 590, 77, 316, - 243, 136, 78, 150, 111, 117, 13, 80, 81, 245, - 246, 163, 119, 82, 83, 480, 228, 84, 230, 231, - 85, 86, 87, 130, 214, 88, 252, 486, 89, 90, - 22, 280, 520, 276, 268, 259, 269, 270, 271, 261, - 384, 247, 248, 249, 329, 330, 322, 331, 272, 152, - 92, 317, 425, 426, 222, 374, 171, 140, 254, 466, - 551, 545, 396, 100, 212, 218, 612, 443, 347, 348, - 349, 351, 552, 547, 613, 614, 456, 457, 25, 467, - 553, 548 + 8, 24, 16, 17, 65, 328, 67, 149, 520, 521, + 145, 146, 68, 502, 329, 440, 503, 579, 390, 368, + 475, 238, 239, 240, 69, 127, 254, 70, 133, 380, + 575, 648, 666, 621, 649, 71, 143, 401, 72, 141, + 73, 74, 75, 76, 315, 425, 426, 592, 77, 317, + 244, 136, 78, 150, 111, 117, 13, 80, 81, 246, + 247, 163, 119, 82, 83, 482, 228, 84, 230, 231, + 85, 86, 87, 130, 214, 88, 253, 488, 89, 90, + 22, 281, 522, 277, 269, 260, 270, 271, 272, 262, + 386, 248, 249, 250, 330, 331, 323, 332, 273, 152, + 92, 318, 427, 428, 222, 376, 171, 140, 255, 468, + 553, 547, 398, 100, 212, 218, 614, 445, 348, 349, + 350, 352, 554, 549, 615, 616, 458, 459, 25, 469, + 555, 550 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -474 +#define YYPACT_NINF -473 static const yytype_int16 yypact[] = { - -474, 48, 28, 35, -474, 258, -474, 37, -474, -474, - -474, 61, 12, -474, 85, 107, -474, -474, 70, -474, - 156, 82, 1059, -474, 122, 328, 22, -474, 56, 199, - -474, 35, 211, -474, -474, -474, 258, 767, -474, 258, - 459, -474, -474, 152, 459, 258, -474, 23, 145, 1650, - -474, 23, -474, 294, 359, 1650, 1650, 1650, 1650, 1650, - 1650, 1693, 1650, 1650, 1289, 159, -474, 412, -474, -474, - -474, -474, -474, 939, -474, -474, 157, 302, -474, 168, - -474, 175, 184, 23, 204, -474, -474, -474, 219, 54, - -474, -474, 47, -474, 227, -12, 269, 227, 227, 239, - -474, -474, -474, -474, -474, 240, -474, -474, -474, -474, - -474, -474, -474, 250, 1813, 1813, 1813, -474, 259, -474, - -474, -474, -474, -474, -474, 64, 302, 1650, 1805, 262, - 260, 174, -474, 1650, -474, -474, 221, 1813, 2166, 255, - -474, 290, 237, 1650, 304, 1813, -474, -474, 420, -474, - -474, -474, 580, -474, -474, -474, -474, -474, -474, 1736, - 1693, 2166, 280, -474, 253, -474, 50, -474, -474, 275, - 2166, 285, -474, 430, -474, 612, 1650, 1650, 1650, 1650, - -474, 1650, 1650, 1650, -474, 1650, 1650, 1650, 1650, 1650, - 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, -474, - 1332, 428, 1650, -474, 1650, -474, -474, 1234, 1650, 1650, - 1650, -474, 763, 258, 260, 293, 369, -474, 1992, 1992, - -474, 51, 326, -474, 1805, 392, 1813, -474, -474, -474, - -474, -474, -474, -474, 341, 258, -474, -474, 371, -474, - 89, 342, 1813, -474, 1805, -474, -474, -474, 335, 360, - 1805, 1234, -474, -474, 357, 99, 399, -474, 365, 380, - -474, -474, 377, -474, 173, 151, -474, -474, 381, -474, - -474, 456, 1779, -474, -474, -474, 401, -474, -474, -474, - 404, 1650, 258, 366, 1838, -474, 405, 1813, 1813, -474, - 407, 1650, 410, 2166, 650, -474, 2190, 877, 877, 877, - 877, -474, 877, 877, 2214, -474, 461, 461, 461, 461, - -474, -474, -474, -474, 1387, -474, -474, 52, 1442, -474, - 2064, 411, 1160, 2031, 1387, -474, -474, -474, -474, -474, - -474, 19, 255, 255, 2166, 1905, 447, 441, 439, -474, - 444, 505, 1992, 225, 27, -474, 454, -474, -474, -474, - 1931, -474, 125, 458, 258, 460, 465, 466, -474, -474, - 463, 1813, 480, -474, -474, -474, -474, 1497, 1552, 1650, - -474, -474, -474, 1805, -474, 1872, 484, 24, 371, 1650, - 258, 485, 487, 1805, -474, 472, 481, 1813, 81, 399, - 456, 399, 490, 289, 483, -474, -474, 258, 456, 519, - 258, 495, 258, 496, 255, -474, 1650, 1897, 1813, -474, - 321, 349, 350, 354, -474, -474, -474, 258, 497, 255, - 1650, -474, 2094, -474, -474, 488, 491, 489, 1693, 498, - 500, 502, -474, 1650, -474, -474, 506, 503, 1234, 1160, - -474, 1992, 534, -474, -474, -474, 258, 1958, 1992, 258, - 1992, -474, -474, 565, 149, -474, -474, 510, 504, 1992, - 225, 1992, 456, 258, 258, -474, 514, 507, -474, -474, - -474, 1872, -474, 1234, 1650, 1650, 515, -474, 1805, 520, - -474, -474, -474, -474, -474, -474, -474, 1872, -474, -474, - -474, -474, -474, 518, -474, -474, -474, 1693, 517, -474, - -474, -474, 524, -474, 525, 456, -474, -474, -474, -474, - -474, -474, -474, -474, -474, 255, 526, 1387, -474, -474, - 527, 612, -474, 255, 1387, 1595, 1387, -474, -474, 530, - -474, -474, -474, -474, 116, -474, -474, 141, -474, -474, - 539, 540, 521, 542, 546, 538, -474, -474, 548, 543, - 1992, 549, -474, 552, -474, -474, 562, -474, 1992, -474, - 556, 456, -474, 560, -474, 1984, 238, 2166, 2166, 1650, - 561, 1805, -474, -474, 1872, 32, -474, 1160, 456, 456, - -474, 186, 370, 554, 258, 563, 410, 557, -474, 2166, - -474, -474, -474, -474, 1650, -474, -474, -474, 1984, 258, - -474, 1958, 1992, 456, -474, 258, 149, -474, -474, -474, - 258, 258, -474, -474, -474, -474, -474, -474, 564, 613, - -474, 1650, 1650, -474, 1693, 566, -474, -474, -474, -474, - -474, -474, -474, 1387, 558, -474, 571, -474, -474, -474, - -474, 577, 582, 583, 1872, 36, -474, -474, 2118, 2142, - 572, -474, 1984, -474, 1984, -474, -474, -474, -474, -474, - -474, -474, -474, -474, 1650, 371, -474 + -473, 65, 22, 49, -473, 261, -473, 64, -473, -473, + -473, 95, 52, -473, 143, 145, -473, -473, 104, -473, + 68, 128, 1049, -473, 142, 305, 16, -473, 56, 204, + -473, 49, 220, -473, -473, -473, 261, 974, -473, 261, + 562, -473, -473, 288, 562, 261, -473, 14, 147, 1615, + -473, 14, -473, 395, 401, 1615, 1615, 1615, 1615, 1615, + 1615, 1658, 1615, 1615, 737, 168, -473, 414, -473, -473, + -473, -473, -473, 649, -473, -473, 165, 122, -473, 169, + -473, 177, 218, 14, 219, -473, -473, -473, 235, 89, + -473, -473, 34, -473, 206, 124, 286, 206, 206, 260, + -473, -473, -473, -473, -473, 265, -473, -473, -473, -473, + -473, -473, -473, 270, 1803, 1803, 1803, -473, 269, -473, + -473, -473, -473, -473, -473, 39, 122, 882, 1777, 283, + 277, 230, -473, 1615, -473, -473, 292, 1803, 2097, 280, + -473, 332, 315, 1615, 215, 1803, -473, -473, 244, -473, + -473, -473, 949, -473, -473, -473, -473, -473, -473, 1701, + 1658, 2097, 298, -473, 9, -473, 59, -473, -473, 303, + 2097, 319, -473, 330, -473, 1744, 1615, 1615, 1615, 1615, + -473, 1615, 1615, 1615, -473, 1615, 1615, 1615, 1615, 1615, + 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, -473, + 1297, 455, 1615, -473, 1615, -473, -473, 1225, 1615, 1615, + 1615, -473, 594, 261, 277, 328, 403, -473, 1308, 1308, + -473, 152, 352, -473, 1777, 405, 1803, -473, -473, -473, + -473, -473, -473, -473, 354, 261, 1615, -473, -473, 382, + -473, 47, 360, 1803, -473, 1777, -473, -473, -473, 351, + 367, 1777, 1225, -473, -473, 366, 84, 407, -473, 374, + 373, -473, -473, 372, -473, 138, 42, -473, -473, 377, + -473, -473, 442, 1769, -473, -473, -473, 384, -473, -473, + -473, 389, 1615, 261, 391, 1830, -473, 394, 1803, 1803, + -473, 409, 1615, 411, 2097, 1935, -473, 2121, 1080, 1080, + 1080, 1080, -473, 1080, 1080, 2145, -473, 503, 503, 503, + 503, -473, -473, -473, -473, 1352, -473, -473, 27, 1407, + -473, 1995, 412, 1147, 1962, 1352, -473, -473, -473, -473, + -473, -473, 7, 280, 280, 2097, 698, 418, 415, 413, + -473, 416, 477, 1308, 188, 31, -473, 425, -473, -473, + -473, 1897, -473, 221, 433, 261, 434, 436, 439, -473, + -473, 432, 1803, 452, -473, -473, 2097, -473, -473, 1462, + 1517, 1615, -473, -473, -473, 1777, -473, 1856, 453, 91, + 382, 1615, 261, 454, 456, 1777, -473, 475, 451, 1803, + 133, 407, 442, 407, 460, 326, 462, -473, -473, 261, + 442, 467, 261, 478, 261, 486, 280, -473, 1615, 1864, + 1803, -473, 26, 248, 264, 430, -473, -473, -473, 261, + 492, 280, 1615, -473, 2025, -473, -473, 485, 493, 487, + 1658, 504, 506, 508, -473, 1615, -473, -473, 512, 505, + 1225, 1147, -473, 1308, 517, -473, -473, -473, 261, 1889, + 1308, 261, 1308, -473, -473, 571, 155, -473, -473, 514, + 509, 1308, 188, 1308, 442, 261, 261, -473, 518, 507, + -473, -473, -473, 1856, -473, 1225, 1615, 1615, 521, -473, + 1777, 528, -473, -473, -473, -473, -473, -473, -473, 1856, + -473, -473, -473, -473, -473, 520, -473, -473, -473, 1658, + 522, -473, -473, -473, 530, -473, 532, 442, -473, -473, + -473, -473, -473, -473, -473, -473, -473, 280, 535, 1352, + -473, -473, 536, 1744, -473, 280, 1352, 1560, 1352, -473, + -473, 539, -473, -473, -473, -473, 247, -473, -473, 308, + -473, -473, 541, 543, 545, 546, 547, 544, -473, -473, + 551, 548, 1308, 554, -473, 557, -473, -473, 576, -473, + 1308, -473, 564, 442, -473, 568, -473, 1923, 318, 2097, + 2097, 1615, 569, 1777, -473, -473, 1856, 156, -473, 1147, + 442, 442, -473, 243, 483, 563, 261, 577, 411, 570, + -473, 2097, -473, -473, -473, -473, 1615, -473, -473, -473, + 1923, 261, -473, 1889, 1308, 442, -473, 261, 155, -473, + -473, -473, 261, 261, -473, -473, -473, -473, -473, -473, + 579, 627, -473, 1615, 1615, -473, 1658, 580, -473, -473, + -473, -473, -473, -473, -473, 1352, 572, -473, 583, -473, + -473, -473, -473, 585, 586, 590, 1856, 77, -473, -473, + 2049, 2073, 584, -473, 1923, -473, 1923, -473, -473, -473, + -473, -473, -473, -473, -473, -473, 1615, 382, -473 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -474, -474, -474, -474, -474, -474, -474, -15, -474, -474, - 616, -474, -3, -474, -474, 622, -474, -125, -27, 66, - -474, -124, -112, -474, 11, -474, -474, -474, 147, -368, - -474, -474, -474, -474, -474, -474, -140, -474, -474, -474, - -474, -474, -474, -474, -474, -474, -474, -474, -474, -474, - 532, 10, 247, -474, -194, 132, 135, -474, 279, -59, - 418, 67, 5, 384, 624, 425, 317, 20, -474, 424, - 636, 509, -474, -474, -474, -474, -36, -37, -31, -49, - -474, -474, -474, -474, -474, -32, 464, -473, -474, -474, - -474, -474, -474, -474, -474, -474, 277, -119, -231, 287, - -474, 300, -474, -205, -300, 652, -474, -242, -474, -63, - 106, 182, -474, -316, -241, -285, -195, -474, -111, -420, - -474, -474, -245, -474, 402, -474, -176, -474, 345, 249, - 346, 218, 87, 96, -415, -474, -429, 252, -474, 522, - -474, -474 + -473, -473, -473, -473, -473, -473, -473, -12, -473, -473, + 624, -473, -1, -473, -473, 635, -473, -137, -48, 74, + -473, -130, -112, -473, 11, -473, -473, -473, 149, -372, + -473, -473, -473, -473, -473, -473, -140, -473, -473, -473, + -473, -473, -473, -473, -473, -473, -473, -473, -473, -473, + 662, 448, 257, -473, -196, 135, 139, -473, 262, -59, + 424, -16, -3, 387, 632, 427, 313, 20, -473, 428, + -89, 524, -473, -473, -473, -473, -36, -37, -31, -49, + -473, -473, -473, -473, -473, -32, 458, -472, -473, -473, + -473, -473, -473, -473, -473, -473, 279, -108, -211, 290, + -473, 306, -473, -214, -291, 658, -473, -230, -473, -63, + -6, 191, -473, -302, -219, -254, -195, -473, -107, -435, + -473, -473, -347, -473, 323, -473, 72, -473, 371, 268, + 380, 242, 102, 110, -468, -473, -438, 255, -473, 515, + -473, -473 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -277 +#define YYTABLE_NINF -278 static const yytype_int16 yytable[] = { - 121, 120, 162, 273, 175, 123, 122, 321, 437, 377, - 489, 324, 165, 104, 572, 236, 241, 260, 386, 360, - 275, 236, 434, 279, 164, 556, 541, 394, 108, 166, - 458, 236, 429, 390, 392, 401, 346, 621, 436, 403, - 174, 110, 356, 357, 110, 376, 101, 213, 4, 418, - 132, -215, 208, 5, 27, 206, 657, 118, 134, 27, - 7, 15, 11, 427, 18, 153, 154, 155, 156, 157, - 158, -267, 167, 168, 19, 9, -267, 229, 229, 229, - 9, 439, 232, 232, 232, -215, 439, 440, 497, 134, - 135, 229, 488, 498, 367, 102, 232, 622, 623, 459, - 229, 620, -236, 326, 223, 232, 20, 624, 229, -181, - 175, 165, 209, 232, 29, 229, 103, -215, 142, 29, - 232, 135, 210, 164, 10, 11, -267, 428, 166, 10, - 11, 23, -267, 26, 118, 118, 118, 382, 229, 538, - 527, 258, 529, 232, 33, 503, 290, 267, 118, 499, - 205, 165, 452, 509, 368, 139, 207, 118, 502, 27, - 504, -236, 380, 164, 210, 118, 451, -236, 166, 153, - 157, 656, 118, 9, 462, 381, 9, 641, 493, 636, - 9, -266, 594, 635, 93, 463, -266, 229, 595, 229, - 642, 643, 232, 497, 232, 118, 537, 381, 498, 453, - 464, 583, 106, 439, 391, 229, 358, 229, 587, 596, - 232, 128, 232, 229, 109, 28, 137, 562, 232, 29, - 517, 172, 10, 11, 199, 10, 11, 524, 452, 10, - 11, 566, 389, 240, -153, 229, -266, 662, 534, 663, - 232, 203, -266, 204, 118, 255, 118, 411, 410, 9, - 229, 229, 413, 412, 628, 232, 232, 236, 476, 431, - 580, 255, 118, -182, 118, 539, 260, 236, 490, 165, - 118, 546, 549, 570, 554, 453, 511, 513, -181, 585, - 256, 164, 9, 559, 454, 561, 166, 125, -183, 257, - 264, 131, 118, 216, 10, 11, 265, 666, 10, 11, - 439, 11, 221, 220, 118, 266, 615, 118, 118, 224, - 10, 11, -182, 255, 332, 333, 609, 650, 9, 126, - -183, 250, 235, 126, 229, 263, 484, 251, 9, 232, - 210, 10, 11, 626, 627, 625, 229, 94, 482, 481, - 286, 232, 264, 485, 483, 95, 229, 287, 265, 96, - 229, 232, 354, 144, 521, 232, -179, 288, 639, 97, - 98, 200, 10, 11, 274, 201, 618, 10, 11, 530, - 229, 229, 355, 202, 603, 232, 232, 10, 11, 165, - -179, 118, 607, 9, -177, -178, 359, 404, -179, -176, - 258, 164, 99, 118, 633, 118, 166, 419, 267, 634, - 361, 363, 508, 118, 369, -180, 365, 118, -177, -178, - 373, 211, 211, -176, 211, 211, -177, -178, 148, 379, - 375, -176, 484, 381, 383, 546, 638, 118, 118, -180, - 12, 406, 10, 11, 482, 481, 9, -180, 484, 485, - 483, 229, 385, 393, 9, 32, 232, 79, 165, 387, - 482, 481, 9, 32, 9, 485, 483, 236, 616, 395, - 164, 112, 35, 400, 112, 166, 402, 37, 129, 417, - 112, 173, 414, 332, 333, 420, 113, 433, 147, 151, - 278, 47, 48, 9, 229, 10, 11, 318, 51, 232, - 289, 118, 151, 10, 11, 178, 255, 215, 118, 217, - 219, 10, 11, 10, 11, 186, 446, 118, 447, 190, - 448, 449, 515, 450, 195, 196, 197, 198, 61, 460, - 465, 521, 468, 471, 665, 484, 523, 469, 470, 345, - 64, 256, 10, 11, 229, 345, 345, 482, 481, 232, - 472, 118, 485, 483, 487, 10, 11, 492, 380, 495, - 505, 507, 236, 244, 510, 512, 514, 522, 531, 528, - 532, 112, 533, 526, 435, 530, 535, 112, 555, 147, - 341, 536, 557, 151, 565, 165, 558, 569, 574, 571, - -157, 138, 464, 576, 578, 579, 582, 164, 37, 584, - 593, 118, 166, 161, 118, 484, 170, 113, 151, 597, - 598, 599, 47, 48, 9, -158, 600, 482, 481, 51, - 601, 606, 485, 483, 605, 602, 225, 604, 608, 610, - 37, 617, 629, 631, 644, 632, 319, 645, 439, 113, - 651, 652, 79, 115, 47, 48, 9, 653, 350, 226, - 661, 51, 654, 655, 66, 281, 32, 107, 225, 244, - 630, 64, 345, 10, 11, 282, 658, 581, 591, 345, - 364, 592, 371, 124, 118, 115, 405, 345, 372, 285, - 506, 226, 494, 477, 91, 244, 79, 291, 353, 575, - 444, 445, 564, 64, 178, 10, 11, 282, 181, 182, - 183, 540, 640, 185, 186, 187, 188, 637, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 151, 293, 294, - 295, 296, 560, 297, 298, 299, 0, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 0, 161, 0, 320, 352, 323, 0, 0, 0, - 138, 138, 334, 0, 0, 0, 0, 79, 0, 0, - 227, 233, 234, 0, 0, 0, 0, 0, 345, 0, - 0, 0, 0, 0, 544, 345, 0, 345, 455, 0, - 0, 335, 0, 262, 0, 37, 345, 0, 345, 350, - 336, 277, 0, 0, 113, 337, 338, 339, 283, 47, - 48, 9, 340, 0, 0, 0, 51, 0, 244, 341, - 479, 0, 0, 114, 0, 491, 0, 0, 244, 0, - 112, 292, 0, 138, 0, 0, 342, 0, 112, 0, - 115, 0, 112, 138, 0, 147, 116, 151, 343, 0, - 0, 0, 0, 0, 344, 0, 0, 11, 64, 0, - 10, 11, 151, 0, 0, 0, 422, 0, 0, 0, - 161, 0, 0, 0, 0, 0, 422, 0, 0, 0, - 0, 0, 362, 79, 79, 0, 0, 345, 0, 0, - 0, 350, 543, 0, 550, 345, 0, 0, 370, 455, - 0, 0, 345, 0, 0, 455, 0, 0, 563, 350, - 0, 0, 0, 0, 0, 0, 0, 0, 79, 138, - 138, 0, 0, 244, 0, 0, 0, 0, 398, 0, - 0, 178, 0, 0, 0, 345, 0, 0, 544, 345, - 409, 186, 0, 415, 416, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 176, -276, 0, 0, 0, 0, 0, - 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, - 161, 0, 0, 0, 0, 170, 0, 0, 0, 345, - 0, 345, 177, 178, 0, 179, 180, 181, 182, 183, - 0, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 244, 409, 0, 0, - 0, 0, 79, 0, -276, 0, 567, 568, 0, 151, - 0, 0, 0, 0, -276, 0, 0, 0, 0, 0, - 0, 0, 0, 496, 350, 0, 543, 0, 0, 161, - 550, 455, 0, 0, 0, 350, 350, 0, 0, 0, - 0, 0, 0, 227, 516, 0, 0, 0, 0, 422, - 0, 0, 0, 0, 0, 0, 422, 589, 422, -2, + 121, 120, 162, 274, 175, 123, 122, 322, 491, 325, + 361, 280, 165, 543, 276, 237, 104, 574, 558, 174, + 242, 237, 379, 439, 164, 227, 233, 234, 261, 166, + 108, 237, 436, 110, 460, 142, 110, 378, 429, 208, + 101, 388, 132, 139, -184, 505, -268, 5, 263, 134, + 396, -268, 369, 511, 392, 394, 278, 118, 403, 27, + -216, -180, 405, 284, 431, 4, 383, 205, -183, 441, + 438, 27, 420, 207, 7, 442, -184, 229, 229, 229, + 9, 135, 232, 232, 232, -180, 293, -237, 15, 102, + 206, 229, 9, -180, -216, 393, 232, 659, 18, 209, + 229, -268, 430, 461, 622, 232, 223, -268, 229, 210, + 175, 165, 370, 232, 19, 229, 103, 564, -182, 29, + 232, 241, 210, 164, 134, 291, -216, 28, 166, 10, + 11, 29, 637, 259, 118, 118, 118, 363, 229, 268, + 499, 10, 11, 232, 327, 500, -237, 382, 118, 384, + 540, 165, -237, 441, 372, 27, 135, 118, 454, 490, + 582, 623, 383, 164, 20, 118, 638, 26, 166, 23, + 643, 495, 118, 529, 658, 531, 9, 644, 645, 9, + 504, 200, 506, 213, 400, 201, 664, 229, 665, 229, + 33, 454, 232, 202, 232, 118, 411, 391, 11, 417, + 418, 501, 333, 334, 93, 455, 229, 106, 229, 359, + 539, 232, 9, 232, 229, 29, 611, 585, 137, 232, + 519, 624, 625, 109, 589, 10, 11, 526, 10, 11, + 172, 626, 199, 628, 629, -154, 229, -267, 455, 9, + 536, 232, -267, 203, 118, 568, 118, 456, 413, 412, + 499, 229, 229, 415, 414, 500, 232, 232, 641, 237, + 433, 10, 11, 118, 478, 118, 572, 515, 9, 237, + 165, 118, 513, 411, 492, 275, 406, 204, -183, 261, + 11, 465, 164, -178, 347, 9, 421, 166, 10, 11, + 357, 358, -267, 118, -182, 668, 466, 125, -267, -179, + 498, 131, 126, 587, 279, 118, 126, -178, 118, 118, + 216, 630, 9, 596, 94, -178, 256, 10, 11, 597, + 227, 518, 95, -179, 220, 229, 96, 221, 486, 224, + 232, -179, 235, 652, 10, 11, 97, 98, 229, 256, + 484, 483, 251, 232, 252, 487, 485, 128, 229, 627, + 256, 257, 229, 232, 9, 210, 523, 232, 287, 620, + 258, 10, 11, 333, 334, 10, 11, 264, 265, 99, + 441, 532, 229, 229, 266, 288, 598, 232, 232, 265, + 441, 165, 118, 267, 259, 266, 617, 355, 10, 11, + 290, 289, 268, 164, 635, 118, 510, 118, 166, 10, + 11, 636, 517, 10, 11, 118, 356, 211, 211, 118, + 211, 211, 360, 362, 364, 453, 525, 367, 215, 9, + 217, 219, 371, 464, 486, 9, 375, 377, 381, 118, + 118, 383, 12, 385, 588, 387, 484, 483, 9, 395, + 486, 487, 485, 229, 389, 397, 402, 32, 232, 79, + 165, 404, 484, 483, 144, 32, 408, 487, 485, 237, + 148, 416, 164, 112, 618, -177, 112, 166, 10, 11, + 129, 419, 112, 173, 10, 11, 422, 448, 435, 9, + 147, 151, 449, 451, 450, 452, 229, 10, 11, -177, + 462, 232, 473, 118, 151, 467, 470, -177, 471, 256, + 118, 472, 512, 153, 154, 155, 156, 157, 158, 118, + 167, 168, 474, 489, 319, 541, 494, 382, -181, 497, + 507, 548, 551, 523, 556, 346, 667, 486, 10, 11, + 509, 346, 346, 561, 257, 563, 229, 178, 514, 484, + 483, 232, -181, 118, 487, 485, 516, 186, 10, 11, + -181, 190, 524, 342, 237, 245, 195, 196, 197, 198, + 528, 530, 437, 112, 533, 35, 534, 532, 535, 112, + 37, 147, 537, 538, 557, 151, 559, 165, 567, 113, + 576, 560, 466, 571, 47, 48, 9, 573, 578, 164, + 580, 51, 581, 118, 166, 584, 118, 486, 586, 595, + 151, 599, 336, 600, -158, 601, -159, 153, 157, 484, + 483, 337, 602, 603, 487, 485, 338, 339, 340, 607, + 604, 61, 606, 341, 605, 608, 610, 612, 320, 619, + 342, 631, 609, 64, 79, 10, 11, 633, 634, 646, + 351, 647, 441, 654, 653, 655, 656, 343, 32, 346, + 657, 245, 663, 176, -277, 107, 346, 66, 660, 344, + 632, 583, 365, 593, 346, 345, 118, 594, 11, 373, + 407, 124, 354, 374, 508, 548, 640, 496, 245, 79, + 91, 479, 177, 178, 286, 179, 180, 181, 182, 183, + 577, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 336, 446, 566, 642, + 151, 138, 542, 639, -277, 337, 447, 562, 0, 0, + 338, 339, 340, 161, -277, 0, 170, 341, 353, 0, + 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, + 35, 0, 0, 0, 0, 37, 0, 0, 169, 0, + 79, 343, 0, 0, 113, 0, 346, 444, 0, 47, + 48, 9, 546, 346, 0, 346, 51, 0, 0, 345, + 0, 457, 11, 55, 346, 0, 346, 0, 0, 0, + 0, 0, 351, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 0, 61, 0, 0, 0, + 0, 0, 245, 0, 481, 0, 62, 63, 64, 493, + 10, 11, 245, 0, 112, 0, 0, 0, 0, 0, + 0, 0, 112, 0, 0, 0, 112, 0, 0, 147, + 0, 151, 0, 0, 0, 0, 0, 0, 294, 295, + 296, 297, 0, 298, 299, 300, 151, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 0, 161, 0, 321, 346, 324, 79, 79, 0, + 138, 138, 335, 346, 0, 351, 545, 0, 552, 0, + 346, 0, 0, 457, 0, 35, 0, 0, 0, 457, + 37, 0, 565, 351, 0, 0, 0, 0, 366, 113, + 0, 0, 79, 0, 47, 48, 9, 245, 236, 0, + 0, 51, 0, 346, 0, 0, 546, 346, 55, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, + 0, 61, 0, 0, 138, 0, 0, 0, 0, 0, + 0, 62, 63, 64, 138, 10, 11, 37, 0, 0, + 0, 0, 0, 0, 0, 0, 113, 346, 0, 346, + 0, 47, 48, 9, 0, 0, 0, 424, 51, 0, + 0, 161, 37, 0, 0, 225, 0, 424, 0, 0, + 0, 113, 0, 0, 0, 0, 47, 48, 9, 0, + 245, 0, 115, 51, 0, 0, 79, 0, 226, 0, + 114, 0, 0, 151, 282, 0, 0, 0, 0, 0, + 64, 0, 10, 11, 283, 0, 0, 115, 351, 0, + 545, 138, 138, 116, 552, 457, 0, 0, 0, 351, + 351, 0, 0, 0, 0, 64, 0, 10, 11, -2, 34, 0, 35, 0, 0, 36, 0, 37, 38, 39, 0, 0, 40, 0, 41, 42, 43, 44, 45, 46, - 0, 47, 48, 9, 0, 0, 49, 50, 51, 52, - 53, 54, 0, 0, 0, 55, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 56, 57, + 138, 47, 48, 9, 0, 0, 49, 50, 51, 52, + 53, 54, 0, 0, 138, 55, 0, 0, 0, 0, + 0, 0, 161, 0, 0, 0, 0, 170, 56, 57, 0, 58, 59, 0, 0, 60, 0, 0, 61, 0, - 0, -24, 0, 0, 0, 0, 170, 0, 62, 63, - 64, 0, 10, 11, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 648, 649, 0, 161, 586, 0, 0, - 0, 325, 0, 35, 0, 422, 36, -251, 37, 38, - 39, 0, -251, 40, 0, 41, 42, 113, 44, 45, - 46, 0, 47, 48, 9, 0, 0, 49, 50, 51, - 52, 53, 54, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, - 57, 0, 58, 59, 0, 0, 60, 0, 0, 61, - 0, 0, -251, 0, 0, 0, 0, 326, -251, 62, - 63, 64, 0, 10, 11, 325, 0, 35, 0, 0, - 36, 0, 37, 38, 39, 0, 0, 40, 0, 41, - 42, 113, 44, 45, 46, 0, 47, 48, 9, 0, - 0, 49, 50, 51, 52, 53, 54, 0, 0, 0, - 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 56, 57, 0, 58, 59, 0, 0, - 60, 0, 35, 61, 0, 0, -251, 37, 0, 0, - 169, 326, -251, 62, 63, 64, 113, 10, 11, 0, - 0, 47, 48, 9, 0, 0, 0, 0, 51, 0, - 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 35, 0, 0, 56, 57, - 37, 58, 59, 0, 0, 60, 0, 0, 61, 113, - 0, 0, 0, 0, 47, 48, 9, 0, 62, 63, - 64, 51, 10, 11, 0, 0, 0, 0, 159, 0, + 0, -24, 0, 0, 178, 0, 0, 0, 62, 63, + 64, 0, 10, 11, 186, 0, 0, 0, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 0, 569, 570, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 0, + 35, 0, 0, 36, -252, 37, 38, 39, 0, -252, + 40, 161, 41, 42, 113, 44, 45, 46, 0, 47, + 48, 9, 0, 0, 49, 50, 51, 52, 53, 54, + 0, 424, 0, 55, 0, 0, 0, 0, 424, 591, + 424, 0, 0, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 0, 61, 0, 0, -252, + 0, 0, 0, 0, 327, -252, 62, 63, 64, 0, + 10, 11, 0, 0, 0, 0, 326, 0, 35, 0, + 0, 36, 0, 37, 38, 39, 0, 0, 40, 0, + 41, 42, 113, 44, 45, 46, 0, 47, 48, 9, + 0, 0, 49, 50, 51, 52, 53, 54, 170, 0, + 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 56, 57, 0, 58, 59, 0, + 0, 60, 0, 0, 61, 650, 651, -252, 161, 0, + 0, 0, 327, -252, 62, 63, 64, 424, 10, 11, + 35, 0, 0, 0, 0, 37, 0, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 336, 0, 0, 47, + 48, 9, 0, 0, 0, 337, 51, 0, 0, 0, + 338, 339, 340, 159, 0, 0, 0, 341, 0, 0, + 0, 0, 0, 0, 342, 0, 56, 57, 0, 58, + 160, 0, 0, 60, 0, 35, 61, 316, 0, 0, + 37, 343, 0, 0, 0, 0, 62, 63, 64, 113, + 10, 11, 0, 0, 47, 48, 9, 0, 0, 345, + 0, 51, 11, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 58, 160, 0, 0, 60, 0, - 35, 61, 315, 0, 0, 37, 0, 0, 0, 0, + 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, + 35, 61, 0, 0, 0, 37, 0, 0, 0, 423, 0, 62, 63, 64, 113, 10, 11, 0, 0, 47, - 48, 9, 0, 0, 0, 0, 51, 0, 0, 0, - 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, + 48, 9, 0, 0, 0, 0, 51, 0, 432, 0, + 0, 0, 0, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, - 59, 0, 0, 60, 0, 35, 61, 0, 0, 0, - 37, 0, 0, 0, 421, 0, 62, 63, 64, 113, - 10, 11, 0, 0, 47, 48, 9, 0, 0, 0, - 0, 51, 0, 430, 0, 0, 0, 0, 159, 0, + 160, 0, 0, 60, 0, 35, 61, 0, 0, 0, + 37, 0, 0, 0, 0, 0, 62, 63, 64, 113, + 10, 11, 0, 0, 47, 48, 9, 0, 476, 0, + 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 58, 160, 0, 0, 60, 0, + 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, 35, 61, 0, 0, 0, 37, 0, 0, 0, 0, 0, 62, 63, 64, 113, 10, 11, 0, 0, 47, - 48, 9, 0, 474, 0, 0, 51, 0, 0, 0, + 48, 9, 0, 477, 0, 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, - 59, 0, 0, 60, 0, 35, 61, 0, 0, 0, - 37, 0, 0, 0, 0, 0, 62, 63, 64, 113, - 10, 11, 0, 0, 47, 48, 9, 0, 475, 0, - 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 56, 57, 37, 58, 59, 0, 0, 60, 0, - 0, 61, 113, 0, 0, 0, 0, 47, 48, 9, - 0, 62, 63, 64, 51, 10, 11, 0, 0, 0, + 0, 0, 0, 35, 0, 0, 56, 57, 37, 58, + 59, 0, 0, 60, 0, 0, 61, 113, 0, 0, + 0, 0, 47, 48, 9, 0, 62, 63, 64, 51, + 10, 11, 0, 0, 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, + 57, 0, 58, 59, 0, 0, 60, 0, 35, 61, + 0, 0, 0, 37, 0, 0, 0, 590, 0, 62, + 63, 64, 113, 10, 11, 0, 0, 47, 48, 9, + 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 56, 57, 0, 58, 59, 0, - 0, 60, 0, 35, 61, 0, 0, 0, 37, 0, - 0, 0, 588, 0, 62, 63, 64, 113, 10, 11, - 0, 0, 47, 48, 9, 0, 0, 0, 0, 51, - 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 35, 0, 0, 56, - 57, 37, 58, 59, 0, 0, 60, 0, 0, 61, - 113, 0, 0, 0, 0, 47, 48, 9, 0, 62, - 63, 64, 51, 10, 11, 0, 0, 0, 0, 159, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, - 0, 0, 56, 57, 284, 58, 160, 0, 0, 60, - 0, 0, 61, 113, 0, 0, 0, 0, 47, 48, - 9, 0, 62, 63, 64, 51, 10, 11, 0, 0, - 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 56, 57, 37, 58, 59, - 0, 0, 60, 0, 0, 61, 113, 0, 0, 0, - 0, 47, 48, 9, 0, 62, 63, 64, 51, 10, - 11, 0, 0, 37, 0, 225, 242, 0, 0, 0, - 0, 37, 113, 0, 0, 0, 0, 47, 48, 9, - 113, 0, 115, 0, 51, 47, 48, 9, 226, 0, - 0, 225, 51, 0, 0, 0, 37, 0, 0, 225, - 64, 0, 10, 11, 397, 113, 0, 0, 115, 0, - 47, 48, 9, 0, 226, 0, 115, 51, 0, 0, - 0, 0, 226, 0, 407, 0, 64, 0, 10, 11, - 37, 0, 0, 0, 64, 0, 10, 11, 0, 113, - 0, 115, 0, 0, 47, 48, 9, 408, 0, 0, - 0, 51, 0, 0, 0, 284, 0, 0, 225, 64, - 0, 10, 11, 335, 113, 0, 0, 0, 0, 47, - 48, 9, 336, 0, 0, 115, 51, 337, 338, 339, - 0, 478, 0, 225, 340, 0, 0, 0, 0, 335, - 0, 441, 461, 64, 0, 10, 11, 0, 336, 0, - 115, 0, 0, 337, 338, 339, 226, 0, 342, 0, - 340, 0, 0, 0, 442, 0, 335, 341, 64, 0, - 10, 11, 0, 0, 0, 336, 344, 0, 0, 11, - 337, 338, 542, 0, 342, 0, 0, 340, 0, 0, - 0, 0, 335, 0, 341, 0, 0, 0, 0, 0, - 335, 336, 344, 0, 0, 11, 337, 338, 339, 336, - 0, 342, 0, 340, 337, 338, 339, 0, 0, 0, - 341, 340, 0, 0, 0, 0, 0, 0, 341, 344, - 0, 10, 11, 0, 0, 0, 0, 342, 0, 0, - 0, 0, 0, 611, 0, 342, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 344, 0, 0, 11, 0, - 0, 0, 0, 344, 177, 178, 11, 179, 0, 181, + 0, 35, 0, 0, 56, 57, 37, 58, 59, 0, + 0, 60, 0, 0, 61, 113, 0, 0, 0, 0, + 47, 48, 9, 0, 62, 63, 64, 51, 10, 11, + 0, 0, 0, 0, 159, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 35, 0, 0, 56, 57, 285, + 58, 160, 0, 0, 60, 0, 0, 61, 113, 0, + 0, 0, 0, 47, 48, 9, 0, 62, 63, 64, + 51, 10, 11, 0, 0, 0, 0, 55, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 56, 57, 37, 58, 59, 0, 0, 60, 0, 0, + 61, 113, 0, 0, 0, 0, 47, 48, 9, 0, + 62, 63, 64, 51, 10, 11, 0, 37, 0, 0, + 225, 0, 0, 0, 0, 37, 113, 0, 243, 0, + 0, 47, 48, 9, 113, 0, 0, 115, 51, 47, + 48, 9, 0, 226, 0, 225, 51, 0, 0, 292, + 0, 37, 0, 225, 0, 64, 0, 10, 11, 283, + 113, 0, 115, 0, 0, 47, 48, 9, 226, 0, + 115, 0, 51, 0, 0, 0, 226, 0, 37, 225, + 64, 0, 10, 11, 399, 0, 0, 113, 64, 0, + 10, 11, 47, 48, 9, 0, 115, 0, 0, 51, + 0, 0, 226, 0, 37, 0, 409, 0, 0, 0, + 0, 0, 285, 113, 64, 0, 10, 11, 47, 48, + 9, 113, 0, 115, 0, 51, 47, 48, 9, 410, + 0, 0, 225, 51, 0, 0, 0, 336, 0, 0, + 225, 64, 0, 10, 11, 336, 337, 0, 463, 115, + 0, 338, 339, 544, 337, 480, 0, 115, 341, 338, + 339, 340, 0, 226, 0, 342, 341, 64, 0, 10, + 11, 336, 0, 342, 0, 64, 0, 10, 11, 0, + 337, 0, 343, 0, 0, 338, 339, 340, 0, 0, + 343, 0, 341, 0, 0, 0, 0, 0, 0, 342, + 345, 0, 10, 11, 0, 0, 0, 0, 345, 178, + 0, 11, 0, 181, 182, 183, 343, 0, 185, 186, + 187, 188, 613, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 0, 0, 345, 177, 178, 11, 179, 0, + 181, 182, 183, 0, 0, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 177, 178, + 0, 179, 0, 181, 182, 183, 0, 437, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 0, 0, 0, 0, 0, 0, 177, 178, + 0, 179, 0, 181, 182, 183, 0, 434, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 177, 178, 0, 179, 0, 181, 182, 183, + 0, 527, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 177, 178, 0, 179, + 0, 181, 182, 183, 0, 661, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 177, 178, 0, 179, 0, 181, 182, 183, 0, 662, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 177, 178, 0, 0, 0, 181, 182, 183, 0, 0, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 177, 178, 0, - 179, 0, 181, 182, 183, 0, 435, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 0, 0, 0, 0, 0, 0, 177, 178, 0, - 179, 0, 181, 182, 183, 0, 432, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 177, 178, 0, 179, 0, 181, 182, 183, 0, - 525, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 177, 178, 0, 179, 0, - 181, 182, 183, 0, 659, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 177, - 178, 0, 179, 0, 181, 182, 183, 0, 660, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 177, 178, 0, 0, 0, 181, 182, - 183, 0, 0, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 177, 178, 0, - 0, 0, 181, 182, 183, 0, 0, 185, 186, 187, - 188, 0, 190, 191, 192, 193, 194, 195, 196, 197, - 198 + 191, 192, 193, 194, 195, 196, 197, 198, 177, 178, + 0, 0, 0, 181, 182, 183, 0, 0, 185, 186, + 187, 188, 0, 190, 191, 192, 193, 194, 195, 196, + 197, 198 }; static const yytype_int16 yycheck[] = { - 37, 37, 61, 143, 67, 37, 37, 202, 324, 251, - 378, 205, 61, 28, 487, 127, 127, 136, 259, 224, - 144, 133, 322, 148, 61, 454, 446, 268, 31, 61, - 3, 143, 317, 264, 265, 276, 212, 5, 323, 280, - 67, 36, 218, 219, 39, 250, 24, 59, 0, 290, - 45, 1, 5, 25, 3, 1, 20, 37, 35, 3, - 25, 24, 74, 11, 3, 55, 56, 57, 58, 59, - 60, 7, 62, 63, 62, 24, 12, 114, 115, 116, - 24, 62, 114, 115, 116, 35, 62, 68, 7, 35, - 67, 128, 68, 12, 5, 73, 128, 65, 66, 72, - 137, 574, 3, 67, 107, 137, 21, 75, 145, 59, - 173, 160, 65, 145, 63, 152, 60, 67, 51, 63, - 152, 67, 75, 160, 73, 74, 62, 75, 160, 73, - 74, 24, 68, 63, 114, 115, 116, 256, 175, 439, - 425, 136, 427, 175, 62, 390, 173, 142, 128, 68, - 83, 200, 3, 398, 65, 49, 89, 137, 389, 3, - 391, 62, 63, 200, 75, 145, 342, 68, 200, 159, - 160, 644, 152, 24, 350, 24, 24, 606, 383, 599, - 24, 7, 66, 598, 62, 60, 12, 224, 72, 226, - 610, 611, 224, 7, 226, 175, 438, 24, 12, 50, - 75, 517, 3, 62, 53, 242, 221, 244, 524, 68, - 242, 59, 244, 250, 3, 59, 71, 462, 250, 63, - 414, 62, 73, 74, 67, 73, 74, 421, 3, 73, - 74, 473, 59, 127, 66, 272, 62, 652, 433, 654, - 272, 66, 68, 59, 224, 24, 226, 284, 284, 24, - 287, 288, 284, 284, 68, 287, 288, 369, 369, 318, - 505, 24, 242, 59, 244, 441, 385, 379, 379, 318, - 250, 447, 448, 478, 450, 50, 400, 402, 59, 520, - 59, 318, 24, 459, 59, 461, 318, 40, 35, 68, - 53, 44, 272, 24, 73, 74, 59, 665, 73, 74, - 62, 74, 62, 64, 284, 68, 68, 287, 288, 59, - 73, 74, 59, 24, 208, 209, 561, 633, 24, 40, - 67, 59, 63, 44, 361, 35, 375, 67, 24, 361, - 75, 73, 74, 578, 579, 577, 373, 9, 375, 375, - 60, 373, 53, 375, 375, 17, 383, 72, 59, 21, - 387, 383, 59, 59, 417, 387, 35, 72, 603, 31, - 32, 59, 73, 74, 60, 63, 571, 73, 74, 428, - 407, 408, 3, 71, 550, 407, 408, 73, 74, 428, - 59, 361, 558, 24, 35, 35, 60, 281, 67, 35, - 385, 428, 64, 373, 588, 375, 428, 291, 393, 594, - 8, 60, 397, 383, 62, 35, 35, 387, 59, 59, - 75, 94, 95, 59, 97, 98, 67, 67, 59, 62, - 60, 67, 471, 24, 59, 601, 602, 407, 408, 59, - 5, 65, 73, 74, 471, 471, 24, 67, 487, 471, - 471, 478, 62, 62, 24, 20, 478, 22, 497, 72, - 487, 487, 24, 28, 24, 487, 487, 569, 569, 3, - 497, 36, 3, 62, 39, 497, 62, 8, 43, 62, - 45, 59, 67, 367, 368, 65, 17, 66, 53, 54, - 60, 22, 23, 24, 521, 73, 74, 59, 29, 521, - 60, 471, 67, 73, 74, 34, 24, 95, 478, 97, - 98, 73, 74, 73, 74, 44, 59, 487, 67, 48, - 71, 67, 406, 8, 53, 54, 55, 56, 59, 65, - 62, 584, 62, 60, 664, 574, 420, 62, 62, 212, - 71, 59, 73, 74, 571, 218, 219, 574, 574, 571, - 60, 521, 574, 574, 60, 73, 74, 60, 63, 68, - 60, 68, 664, 128, 35, 60, 60, 60, 60, 68, - 60, 136, 60, 75, 75, 624, 60, 142, 3, 144, - 36, 68, 62, 148, 60, 624, 72, 62, 60, 59, - 59, 49, 75, 66, 60, 60, 60, 624, 8, 62, - 60, 571, 624, 61, 574, 644, 64, 17, 173, 60, - 60, 59, 22, 23, 24, 59, 68, 644, 644, 29, - 62, 49, 644, 644, 62, 72, 36, 68, 62, 59, - 8, 60, 68, 60, 60, 68, 201, 14, 62, 17, - 72, 60, 207, 53, 22, 23, 24, 60, 213, 59, - 68, 29, 60, 60, 22, 65, 221, 31, 36, 224, - 584, 71, 335, 73, 74, 75, 645, 510, 526, 342, - 235, 526, 244, 39, 644, 53, 282, 350, 244, 160, - 393, 59, 385, 373, 22, 250, 251, 65, 214, 497, - 335, 335, 464, 71, 34, 73, 74, 75, 38, 39, - 40, 442, 605, 43, 44, 45, 46, 601, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 282, 176, 177, - 178, 179, 460, 181, 182, 183, -1, 185, 186, 187, + 37, 37, 61, 143, 67, 37, 37, 202, 380, 205, + 224, 148, 61, 448, 144, 127, 28, 489, 456, 67, + 127, 133, 252, 325, 61, 114, 115, 116, 136, 61, + 31, 143, 323, 36, 3, 51, 39, 251, 11, 5, + 24, 260, 45, 49, 35, 392, 7, 25, 137, 35, + 269, 12, 5, 400, 265, 266, 145, 37, 277, 3, + 1, 35, 281, 152, 318, 0, 24, 83, 59, 62, + 324, 3, 291, 89, 25, 68, 67, 114, 115, 116, + 24, 67, 114, 115, 116, 59, 175, 3, 24, 73, + 1, 128, 24, 67, 35, 53, 128, 20, 3, 65, + 137, 62, 75, 72, 576, 137, 107, 68, 145, 75, + 173, 160, 65, 145, 62, 152, 60, 464, 59, 63, + 152, 127, 75, 160, 35, 173, 67, 59, 160, 73, + 74, 63, 600, 136, 114, 115, 116, 226, 175, 142, + 7, 73, 74, 175, 67, 12, 62, 63, 128, 257, + 441, 200, 68, 62, 243, 3, 67, 137, 3, 68, + 507, 5, 24, 200, 21, 145, 601, 63, 200, 24, + 608, 385, 152, 427, 646, 429, 24, 612, 613, 24, + 391, 59, 393, 59, 273, 63, 654, 224, 656, 226, + 62, 3, 224, 71, 226, 175, 285, 59, 74, 288, + 289, 68, 208, 209, 62, 50, 243, 3, 245, 221, + 440, 243, 24, 245, 251, 63, 563, 519, 71, 251, + 416, 65, 66, 3, 526, 73, 74, 423, 73, 74, + 62, 75, 67, 580, 581, 66, 273, 7, 50, 24, + 435, 273, 12, 66, 224, 475, 226, 59, 285, 285, + 7, 288, 289, 285, 285, 12, 288, 289, 605, 371, + 319, 73, 74, 243, 371, 245, 480, 404, 24, 381, + 319, 251, 402, 362, 381, 60, 282, 59, 59, 387, + 74, 60, 319, 35, 212, 24, 292, 319, 73, 74, + 218, 219, 62, 273, 59, 667, 75, 40, 68, 35, + 389, 44, 40, 522, 60, 285, 44, 59, 288, 289, + 24, 68, 24, 66, 9, 67, 24, 73, 74, 72, + 409, 410, 17, 59, 64, 362, 21, 62, 377, 59, + 362, 67, 63, 635, 73, 74, 31, 32, 375, 24, + 377, 377, 59, 375, 67, 377, 377, 59, 385, 579, + 24, 59, 389, 385, 24, 75, 419, 389, 60, 573, + 68, 73, 74, 369, 370, 73, 74, 35, 53, 64, + 62, 430, 409, 410, 59, 72, 68, 409, 410, 53, + 62, 430, 362, 68, 387, 59, 68, 59, 73, 74, + 60, 72, 395, 430, 590, 375, 399, 377, 430, 73, + 74, 596, 408, 73, 74, 385, 3, 94, 95, 389, + 97, 98, 60, 8, 60, 343, 422, 35, 95, 24, + 97, 98, 62, 351, 473, 24, 75, 60, 62, 409, + 410, 24, 5, 59, 523, 62, 473, 473, 24, 62, + 489, 473, 473, 480, 72, 3, 62, 20, 480, 22, + 499, 62, 489, 489, 59, 28, 65, 489, 489, 571, + 59, 67, 499, 36, 571, 35, 39, 499, 73, 74, + 43, 62, 45, 59, 73, 74, 65, 59, 66, 24, + 53, 54, 67, 67, 71, 8, 523, 73, 74, 59, + 65, 523, 60, 473, 67, 62, 62, 67, 62, 24, + 480, 62, 35, 55, 56, 57, 58, 59, 60, 489, + 62, 63, 60, 60, 59, 443, 60, 63, 35, 68, + 60, 449, 450, 586, 452, 212, 666, 576, 73, 74, + 68, 218, 219, 461, 59, 463, 573, 34, 60, 576, + 576, 573, 59, 523, 576, 576, 60, 44, 73, 74, + 67, 48, 60, 36, 666, 128, 53, 54, 55, 56, + 75, 68, 75, 136, 60, 3, 60, 626, 60, 142, + 8, 144, 60, 68, 3, 148, 62, 626, 60, 17, + 60, 72, 75, 62, 22, 23, 24, 59, 66, 626, + 60, 29, 60, 573, 626, 60, 576, 646, 62, 60, + 173, 60, 8, 60, 59, 59, 59, 159, 160, 646, + 646, 17, 68, 62, 646, 646, 22, 23, 24, 62, + 72, 59, 68, 29, 552, 49, 62, 59, 201, 60, + 36, 68, 560, 71, 207, 73, 74, 60, 68, 60, + 213, 14, 62, 60, 72, 60, 60, 53, 221, 336, + 60, 224, 68, 4, 5, 31, 343, 22, 647, 65, + 586, 512, 235, 528, 351, 71, 646, 528, 74, 245, + 283, 39, 214, 245, 395, 603, 604, 387, 251, 252, + 22, 375, 33, 34, 160, 36, 37, 38, 39, 40, + 499, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 8, 336, 466, 607, + 283, 49, 444, 603, 65, 17, 336, 462, -1, -1, + 22, 23, 24, 61, 75, -1, 64, 29, 213, -1, + -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, + 3, -1, -1, -1, -1, 8, -1, -1, 11, -1, + 323, 53, -1, -1, 17, -1, 443, 59, -1, 22, + 23, 24, 449, 450, -1, 452, 29, -1, -1, 71, + -1, 344, 74, 36, 461, -1, 463, -1, -1, -1, + -1, -1, 355, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, -1, 59, -1, -1, -1, + -1, -1, 375, -1, 377, -1, 69, 70, 71, 382, + 73, 74, 385, -1, 387, -1, -1, -1, -1, -1, + -1, -1, 395, -1, -1, -1, 399, -1, -1, 402, + -1, 404, -1, -1, -1, -1, -1, -1, 176, 177, + 178, 179, -1, 181, 182, 183, 419, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, -1, 202, 213, 204, -1, -1, -1, - 208, 209, 210, -1, -1, -1, -1, 322, -1, -1, - 114, 115, 116, -1, -1, -1, -1, -1, 441, -1, - -1, -1, -1, -1, 447, 448, -1, 450, 343, -1, - -1, 8, -1, 137, -1, 8, 459, -1, 461, 354, - 17, 145, -1, -1, 17, 22, 23, 24, 152, 22, - 23, 24, 29, -1, -1, -1, 29, -1, 373, 36, - 375, -1, -1, 36, -1, 380, -1, -1, 383, -1, - 385, 175, -1, 281, -1, -1, 53, -1, 393, -1, - 53, -1, 397, 291, -1, 400, 59, 402, 65, -1, - -1, -1, -1, -1, 71, -1, -1, 74, 71, -1, - 73, 74, 417, -1, -1, -1, 314, -1, -1, -1, - 318, -1, -1, -1, -1, -1, 324, -1, -1, -1, - -1, -1, 226, 438, 439, -1, -1, 550, -1, -1, - -1, 446, 447, -1, 449, 558, -1, -1, 242, 454, - -1, -1, 565, -1, -1, 460, -1, -1, 463, 464, - -1, -1, -1, -1, -1, -1, -1, -1, 473, 367, - 368, -1, -1, 478, -1, -1, -1, -1, 272, -1, - -1, 34, -1, -1, -1, 598, -1, -1, 601, 602, - 284, 44, -1, 287, 288, 48, 49, 50, 51, 52, - 53, 54, 55, 56, -1, -1, -1, -1, 406, -1, - -1, -1, -1, 4, 5, -1, -1, -1, -1, -1, - -1, -1, 420, -1, -1, -1, -1, -1, -1, -1, - 428, -1, -1, -1, -1, 433, -1, -1, -1, 652, - -1, 654, 33, 34, -1, 36, 37, 38, 39, 40, - -1, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 571, 361, -1, -1, - -1, -1, 577, -1, 65, -1, 474, 475, -1, 584, - -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, - -1, -1, -1, 387, 599, -1, 601, -1, -1, 497, - 605, 606, -1, -1, -1, 610, 611, -1, -1, -1, - -1, -1, -1, 407, 408, -1, -1, -1, -1, 517, - -1, -1, -1, -1, -1, -1, 524, 525, 526, 0, + 198, -1, 200, -1, 202, 552, 204, 440, 441, -1, + 208, 209, 210, 560, -1, 448, 449, -1, 451, -1, + 567, -1, -1, 456, -1, 3, -1, -1, -1, 462, + 8, -1, 465, 466, -1, -1, -1, -1, 236, 17, + -1, -1, 475, -1, 22, 23, 24, 480, 26, -1, + -1, 29, -1, 600, -1, -1, 603, 604, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, + -1, 59, -1, -1, 282, -1, -1, -1, -1, -1, + -1, 69, 70, 71, 292, 73, 74, 8, -1, -1, + -1, -1, -1, -1, -1, -1, 17, 654, -1, 656, + -1, 22, 23, 24, -1, -1, -1, 315, 29, -1, + -1, 319, 8, -1, -1, 36, -1, 325, -1, -1, + -1, 17, -1, -1, -1, -1, 22, 23, 24, -1, + 573, -1, 53, 29, -1, -1, 579, -1, 59, -1, + 36, -1, -1, 586, 65, -1, -1, -1, -1, -1, + 71, -1, 73, 74, 75, -1, -1, 53, 601, -1, + 603, 369, 370, 59, 607, 608, -1, -1, -1, 612, + 613, -1, -1, -1, -1, 71, -1, 73, 74, 0, 1, -1, 3, -1, -1, 6, -1, 8, 9, 10, -1, -1, 13, -1, 15, 16, 17, 18, 19, 20, - -1, 22, 23, 24, -1, -1, 27, 28, 29, 30, - 31, 32, -1, -1, -1, 36, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 49, 50, + 408, 22, 23, 24, -1, -1, 27, 28, 29, 30, + 31, 32, -1, -1, 422, 36, -1, -1, -1, -1, + -1, -1, 430, -1, -1, -1, -1, 435, 49, 50, -1, 52, 53, -1, -1, 56, -1, -1, 59, -1, - -1, 62, -1, -1, -1, -1, 594, -1, 69, 70, - 71, -1, 73, 74, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 621, 622, -1, 624, 521, -1, -1, - -1, 1, -1, 3, -1, 633, 6, 7, 8, 9, - 10, -1, 12, 13, -1, 15, 16, 17, 18, 19, - 20, -1, 22, 23, 24, -1, -1, 27, 28, 29, - 30, 31, 32, -1, -1, -1, 36, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, - 50, -1, 52, 53, -1, -1, 56, -1, -1, 59, - -1, -1, 62, -1, -1, -1, -1, 67, 68, 69, - 70, 71, -1, 73, 74, 1, -1, 3, -1, -1, - 6, -1, 8, 9, 10, -1, -1, 13, -1, 15, - 16, 17, 18, 19, 20, -1, 22, 23, 24, -1, - -1, 27, 28, 29, 30, 31, 32, -1, -1, -1, - 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, - 56, -1, 3, 59, -1, -1, 62, 8, -1, -1, - 11, 67, 68, 69, 70, 71, 17, 73, 74, -1, - -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, - -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3, -1, -1, 49, 50, - 8, 52, 53, -1, -1, 56, -1, -1, 59, 17, - -1, -1, -1, -1, 22, 23, 24, -1, 69, 70, - 71, 29, 73, 74, -1, -1, -1, -1, 36, -1, + -1, 62, -1, -1, 34, -1, -1, -1, 69, 70, + 71, -1, 73, 74, 44, -1, -1, -1, 48, 49, + 50, 51, 52, 53, 54, 55, 56, -1, 476, 477, + -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, + 3, -1, -1, 6, 7, 8, 9, 10, -1, 12, + 13, 499, 15, 16, 17, 18, 19, 20, -1, 22, + 23, 24, -1, -1, 27, 28, 29, 30, 31, 32, + -1, 519, -1, 36, -1, -1, -1, -1, 526, 527, + 528, -1, -1, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, -1, 59, -1, -1, 62, + -1, -1, -1, -1, 67, 68, 69, 70, 71, -1, + 73, 74, -1, -1, -1, -1, 1, -1, 3, -1, + -1, 6, -1, 8, 9, 10, -1, -1, 13, -1, + 15, 16, 17, 18, 19, 20, -1, 22, 23, 24, + -1, -1, 27, 28, 29, 30, 31, 32, 596, -1, + -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, + -1, 56, -1, -1, 59, 623, 624, 62, 626, -1, + -1, -1, 67, 68, 69, 70, 71, 635, 73, 74, + 3, -1, -1, -1, -1, 8, -1, -1, -1, -1, + -1, -1, -1, -1, 17, -1, 8, -1, -1, 22, + 23, 24, -1, -1, -1, 17, 29, -1, -1, -1, + 22, 23, 24, 36, -1, -1, -1, 29, -1, -1, + -1, -1, -1, -1, 36, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, 3, 59, 60, -1, -1, + 8, 53, -1, -1, -1, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, -1, 71, + -1, 29, 74, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, - 3, 59, 60, -1, -1, 8, -1, -1, -1, -1, + 3, 59, -1, -1, -1, 8, -1, -1, -1, 67, -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, - 23, 24, -1, -1, -1, -1, 29, -1, -1, -1, + 23, 24, -1, -1, -1, -1, 29, -1, 31, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, 3, 59, -1, -1, -1, - 8, -1, -1, -1, 67, -1, 69, 70, 71, 17, - 73, 74, -1, -1, 22, 23, 24, -1, -1, -1, - -1, 29, -1, 31, -1, -1, -1, -1, 36, -1, + 8, -1, -1, -1, -1, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, 26, -1, + -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, 3, 59, -1, -1, -1, 8, -1, -1, -1, -1, -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, 23, 24, -1, 26, -1, -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, - 53, -1, -1, 56, -1, 3, 59, -1, -1, -1, - 8, -1, -1, -1, -1, -1, 69, 70, 71, 17, - 73, 74, -1, -1, 22, 23, 24, -1, 26, -1, - -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, - -1, 49, 50, 8, 52, 53, -1, -1, 56, -1, - -1, 59, 17, -1, -1, -1, -1, 22, 23, 24, - -1, 69, 70, 71, 29, 73, 74, -1, -1, -1, + -1, -1, -1, 3, -1, -1, 49, 50, 8, 52, + 53, -1, -1, 56, -1, -1, 59, 17, -1, -1, + -1, -1, 22, 23, 24, -1, 69, 70, 71, 29, + 73, 74, -1, -1, -1, -1, 36, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, + 50, -1, 52, 53, -1, -1, 56, -1, 3, 59, + -1, -1, -1, 8, -1, -1, -1, 67, -1, 69, + 70, 71, 17, 73, 74, -1, -1, 22, 23, 24, + -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, - -1, 56, -1, 3, 59, -1, -1, -1, 8, -1, - -1, -1, 67, -1, 69, 70, 71, 17, 73, 74, - -1, -1, 22, 23, 24, -1, -1, -1, -1, 29, - -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3, -1, -1, 49, - 50, 8, 52, 53, -1, -1, 56, -1, -1, 59, - 17, -1, -1, -1, -1, 22, 23, 24, -1, 69, - 70, 71, 29, 73, 74, -1, -1, -1, -1, 36, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, - -1, -1, 49, 50, 8, 52, 53, -1, -1, 56, - -1, -1, 59, 17, -1, -1, -1, -1, 22, 23, - 24, -1, 69, 70, 71, 29, 73, 74, -1, -1, - -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 49, 50, 8, 52, 53, - -1, -1, 56, -1, -1, 59, 17, -1, -1, -1, - -1, 22, 23, 24, -1, 69, 70, 71, 29, 73, - 74, -1, -1, 8, -1, 36, 11, -1, -1, -1, - -1, 8, 17, -1, -1, -1, -1, 22, 23, 24, - 17, -1, 53, -1, 29, 22, 23, 24, 59, -1, - -1, 36, 29, -1, -1, -1, 8, -1, -1, 36, - 71, -1, 73, 74, 75, 17, -1, -1, 53, -1, - 22, 23, 24, -1, 59, -1, 53, 29, -1, -1, - -1, -1, 59, -1, 36, -1, 71, -1, 73, 74, - 8, -1, -1, -1, 71, -1, 73, 74, -1, 17, - -1, 53, -1, -1, 22, 23, 24, 59, -1, -1, - -1, 29, -1, -1, -1, 8, -1, -1, 36, 71, - -1, 73, 74, 8, 17, -1, -1, -1, -1, 22, - 23, 24, 17, -1, -1, 53, 29, 22, 23, 24, - -1, 59, -1, 36, 29, -1, -1, -1, -1, 8, - -1, 36, 11, 71, -1, 73, 74, -1, 17, -1, - 53, -1, -1, 22, 23, 24, 59, -1, 53, -1, - 29, -1, -1, -1, 59, -1, 8, 36, 71, -1, - 73, 74, -1, -1, -1, 17, 71, -1, -1, 74, - 22, 23, 24, -1, 53, -1, -1, 29, -1, -1, - -1, -1, 8, -1, 36, -1, -1, -1, -1, -1, - 8, 17, 71, -1, -1, 74, 22, 23, 24, 17, - -1, 53, -1, 29, 22, 23, 24, -1, -1, -1, - 36, 29, -1, -1, -1, -1, -1, -1, 36, 71, - -1, 73, 74, -1, -1, -1, -1, 53, -1, -1, - -1, -1, -1, 59, -1, 53, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 71, -1, -1, 74, -1, - -1, -1, -1, 71, 33, 34, 74, 36, -1, 38, + -1, 3, -1, -1, 49, 50, 8, 52, 53, -1, + -1, 56, -1, -1, 59, 17, -1, -1, -1, -1, + 22, 23, 24, -1, 69, 70, 71, 29, 73, 74, + -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, -1, -1, 49, 50, 8, + 52, 53, -1, -1, 56, -1, -1, 59, 17, -1, + -1, -1, -1, 22, 23, 24, -1, 69, 70, 71, + 29, 73, 74, -1, -1, -1, -1, 36, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 49, 50, 8, 52, 53, -1, -1, 56, -1, -1, + 59, 17, -1, -1, -1, -1, 22, 23, 24, -1, + 69, 70, 71, 29, 73, 74, -1, 8, -1, -1, + 36, -1, -1, -1, -1, 8, 17, -1, 11, -1, + -1, 22, 23, 24, 17, -1, -1, 53, 29, 22, + 23, 24, -1, 59, -1, 36, 29, -1, -1, 65, + -1, 8, -1, 36, -1, 71, -1, 73, 74, 75, + 17, -1, 53, -1, -1, 22, 23, 24, 59, -1, + 53, -1, 29, -1, -1, -1, 59, -1, 8, 36, + 71, -1, 73, 74, 75, -1, -1, 17, 71, -1, + 73, 74, 22, 23, 24, -1, 53, -1, -1, 29, + -1, -1, 59, -1, 8, -1, 36, -1, -1, -1, + -1, -1, 8, 17, 71, -1, 73, 74, 22, 23, + 24, 17, -1, 53, -1, 29, 22, 23, 24, 59, + -1, -1, 36, 29, -1, -1, -1, 8, -1, -1, + 36, 71, -1, 73, 74, 8, 17, -1, 11, 53, + -1, 22, 23, 24, 17, 59, -1, 53, 29, 22, + 23, 24, -1, 59, -1, 36, 29, 71, -1, 73, + 74, 8, -1, 36, -1, 71, -1, 73, 74, -1, + 17, -1, 53, -1, -1, 22, 23, 24, -1, -1, + 53, -1, 29, -1, -1, -1, -1, -1, -1, 36, + 71, -1, 73, 74, -1, -1, -1, -1, 71, 34, + -1, 74, -1, 38, 39, 40, 53, -1, 43, 44, + 45, 46, 59, 48, 49, 50, 51, 52, 53, 54, + 55, 56, -1, -1, 71, 33, 34, 74, 36, -1, + 38, 39, 40, -1, -1, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 33, 34, + -1, 36, -1, 38, 39, 40, -1, 75, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, -1, -1, -1, -1, -1, -1, 33, 34, + -1, 36, -1, 38, 39, 40, -1, 72, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 33, 34, -1, 36, -1, 38, 39, 40, + -1, 66, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 33, 34, -1, 36, + -1, 38, 39, 40, -1, 66, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 33, 34, -1, 36, -1, 38, 39, 40, -1, 66, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 33, 34, -1, -1, -1, 38, 39, 40, -1, -1, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 33, 34, -1, - 36, -1, 38, 39, 40, -1, 75, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, -1, -1, -1, -1, -1, -1, 33, 34, -1, - 36, -1, 38, 39, 40, -1, 72, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 33, 34, -1, 36, -1, 38, 39, 40, -1, - 66, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 33, 34, -1, 36, -1, - 38, 39, 40, -1, 66, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 33, - 34, -1, 36, -1, 38, 39, 40, -1, 66, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 33, 34, -1, -1, -1, 38, 39, - 40, -1, -1, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 33, 34, -1, - -1, -1, 38, 39, 40, -1, -1, 43, 44, 45, - 46, -1, 48, 49, 50, 51, 52, 53, 54, 55, - 56 + 49, 50, 51, 52, 53, 54, 55, 56, 33, 34, + -1, -1, -1, 38, 39, 40, -1, -1, 43, 44, + 45, 46, -1, 48, 49, 50, 51, 52, 53, 54, + 55, 56 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1528,50 +1514,50 @@ static const yytype_uint8 yystos[] = 59, 63, 71, 66, 59, 137, 1, 137, 5, 65, 75, 142, 200, 59, 160, 200, 24, 200, 201, 200, 64, 62, 190, 88, 59, 36, 59, 146, 152, 153, - 154, 155, 161, 146, 146, 63, 98, 107, 108, 109, - 186, 194, 11, 136, 141, 145, 146, 177, 178, 179, - 59, 67, 162, 112, 194, 24, 59, 68, 138, 171, - 173, 175, 146, 35, 53, 59, 68, 138, 170, 172, - 173, 174, 184, 112, 60, 97, 169, 146, 60, 93, - 167, 65, 75, 146, 8, 147, 60, 72, 72, 60, - 94, 65, 146, 126, 126, 126, 126, 126, 126, 126, + 154, 155, 161, 146, 146, 63, 26, 98, 107, 108, + 109, 186, 194, 11, 136, 141, 145, 146, 177, 178, + 179, 59, 67, 162, 112, 194, 24, 59, 68, 138, + 171, 173, 175, 146, 35, 53, 59, 68, 138, 170, + 172, 173, 174, 184, 112, 60, 97, 169, 146, 60, + 93, 167, 65, 75, 146, 8, 147, 60, 72, 72, + 60, 94, 65, 146, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 130, 60, 135, 187, 59, 141, - 126, 192, 182, 126, 130, 1, 67, 91, 100, 180, - 181, 183, 186, 186, 126, 8, 17, 22, 23, 24, - 29, 36, 53, 65, 71, 142, 202, 204, 205, 206, - 141, 207, 215, 162, 59, 3, 202, 202, 83, 60, - 179, 8, 146, 60, 141, 35, 105, 5, 65, 62, - 146, 136, 145, 75, 191, 60, 179, 183, 115, 62, - 63, 24, 173, 59, 176, 62, 190, 72, 104, 59, - 174, 53, 174, 62, 190, 3, 198, 75, 146, 123, - 62, 190, 62, 190, 186, 139, 65, 36, 59, 146, - 152, 153, 154, 161, 67, 146, 146, 62, 190, 186, - 65, 67, 126, 131, 132, 188, 189, 11, 75, 191, - 31, 135, 72, 66, 180, 75, 191, 189, 101, 62, - 68, 36, 59, 203, 204, 206, 59, 67, 71, 67, - 8, 202, 3, 50, 59, 141, 212, 213, 3, 72, - 65, 11, 202, 60, 75, 62, 195, 215, 62, 62, - 62, 60, 60, 106, 26, 26, 194, 177, 59, 141, - 151, 152, 153, 154, 155, 161, 163, 60, 68, 105, - 194, 141, 60, 179, 175, 68, 146, 7, 12, 68, - 99, 102, 174, 198, 174, 60, 172, 68, 138, 198, - 35, 97, 60, 93, 60, 186, 146, 130, 94, 95, - 168, 185, 60, 186, 130, 66, 75, 191, 68, 191, - 135, 60, 60, 60, 192, 60, 68, 183, 180, 202, - 205, 195, 24, 141, 142, 197, 202, 209, 217, 202, - 141, 196, 208, 216, 202, 3, 212, 62, 72, 202, - 213, 202, 198, 141, 207, 60, 183, 126, 126, 62, - 179, 59, 163, 116, 60, 187, 66, 103, 60, 60, - 198, 104, 60, 189, 62, 190, 146, 189, 67, 126, - 133, 131, 132, 60, 66, 72, 68, 60, 60, 59, - 68, 62, 72, 202, 68, 62, 49, 202, 62, 198, - 59, 59, 202, 210, 211, 68, 194, 60, 179, 119, - 163, 5, 65, 66, 75, 183, 198, 198, 68, 68, - 95, 60, 68, 130, 192, 210, 195, 209, 202, 198, - 208, 212, 195, 195, 60, 14, 117, 120, 126, 126, - 189, 72, 60, 60, 60, 60, 163, 20, 100, 66, - 66, 68, 210, 210, 118, 112, 105 + 126, 126, 126, 126, 126, 130, 60, 135, 187, 59, + 141, 126, 192, 182, 126, 130, 1, 67, 91, 100, + 180, 181, 183, 186, 186, 126, 8, 17, 22, 23, + 24, 29, 36, 53, 65, 71, 142, 202, 204, 205, + 206, 141, 207, 215, 162, 59, 3, 202, 202, 83, + 60, 179, 8, 146, 60, 141, 126, 35, 105, 5, + 65, 62, 146, 136, 145, 75, 191, 60, 179, 183, + 115, 62, 63, 24, 173, 59, 176, 62, 190, 72, + 104, 59, 174, 53, 174, 62, 190, 3, 198, 75, + 146, 123, 62, 190, 62, 190, 186, 139, 65, 36, + 59, 146, 152, 153, 154, 161, 67, 146, 146, 62, + 190, 186, 65, 67, 126, 131, 132, 188, 189, 11, + 75, 191, 31, 135, 72, 66, 180, 75, 191, 189, + 101, 62, 68, 36, 59, 203, 204, 206, 59, 67, + 71, 67, 8, 202, 3, 50, 59, 141, 212, 213, + 3, 72, 65, 11, 202, 60, 75, 62, 195, 215, + 62, 62, 62, 60, 60, 106, 26, 26, 194, 177, + 59, 141, 151, 152, 153, 154, 155, 161, 163, 60, + 68, 105, 194, 141, 60, 179, 175, 68, 146, 7, + 12, 68, 99, 102, 174, 198, 174, 60, 172, 68, + 138, 198, 35, 97, 60, 93, 60, 186, 146, 130, + 94, 95, 168, 185, 60, 186, 130, 66, 75, 191, + 68, 191, 135, 60, 60, 60, 192, 60, 68, 183, + 180, 202, 205, 195, 24, 141, 142, 197, 202, 209, + 217, 202, 141, 196, 208, 216, 202, 3, 212, 62, + 72, 202, 213, 202, 198, 141, 207, 60, 183, 126, + 126, 62, 179, 59, 163, 116, 60, 187, 66, 103, + 60, 60, 198, 104, 60, 189, 62, 190, 146, 189, + 67, 126, 133, 131, 132, 60, 66, 72, 68, 60, + 60, 59, 68, 62, 72, 202, 68, 62, 49, 202, + 62, 198, 59, 59, 202, 210, 211, 68, 194, 60, + 179, 119, 163, 5, 65, 66, 75, 183, 198, 198, + 68, 68, 95, 60, 68, 130, 192, 210, 195, 209, + 202, 198, 208, 212, 195, 195, 60, 14, 117, 120, + 126, 126, 189, 72, 60, 60, 60, 60, 163, 20, + 100, 66, 66, 68, 210, 210, 118, 112, 105 }; #define yyerrok (yyerrstatus = 0) @@ -2795,20 +2781,22 @@ yyreduce: #line 461 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->implicit = 1; (yyval.node)->etype = OADD; } break; case 55: -#line 466 "go.y" +#line 467 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->implicit = 1; (yyval.node)->etype = OSUB; } break; case 56: -#line 473 "go.y" +#line 475 "go.y" { Node *n, *nn; @@ -2831,7 +2819,7 @@ yyreduce: break; case 57: -#line 493 "go.y" +#line 495 "go.y" { Node *n; @@ -2852,7 +2840,7 @@ yyreduce: break; case 58: -#line 511 "go.y" +#line 513 "go.y" { // will be converted to OCASE // right will point to next case @@ -2864,7 +2852,7 @@ yyreduce: break; case 59: -#line 520 "go.y" +#line 522 "go.y" { Node *n, *nn; @@ -2883,14 +2871,14 @@ yyreduce: break; case 60: -#line 538 "go.y" +#line 540 "go.y" { markdcl(); } break; case 61: -#line 542 "go.y" +#line 544 "go.y" { if((yyvsp[(3) - (4)].list) == nil) (yyval.node) = nod(OEMPTY, N, N); @@ -2901,7 +2889,7 @@ yyreduce: break; case 62: -#line 552 "go.y" +#line 554 "go.y" { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). @@ -2915,7 +2903,7 @@ yyreduce: break; case 63: -#line 563 "go.y" +#line 565 "go.y" { int last; @@ -2937,28 +2925,28 @@ yyreduce: break; case 64: -#line 583 "go.y" +#line 585 "go.y" { (yyval.list) = nil; } break; case 65: -#line 587 "go.y" +#line 589 "go.y" { (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); } break; case 66: -#line 593 "go.y" +#line 595 "go.y" { markdcl(); } break; case 67: -#line 597 "go.y" +#line 599 "go.y" { (yyval.list) = (yyvsp[(3) - (4)].list); popdcl(); @@ -2966,7 +2954,7 @@ yyreduce: break; case 68: -#line 604 "go.y" +#line 606 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -2975,7 +2963,7 @@ yyreduce: break; case 69: -#line 610 "go.y" +#line 612 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -2986,6 +2974,14 @@ yyreduce: case 70: #line 619 "go.y" + { + (yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node)); + (yyval.node)->etype = 0; // := flag + } + break; + + case 71: +#line 626 "go.y" { // init ; test ; incr if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0) @@ -2998,8 +2994,8 @@ yyreduce: } break; - case 71: -#line 630 "go.y" + case 72: +#line 637 "go.y" { // normal test (yyval.node) = nod(OFOR, N, N); @@ -3007,31 +3003,31 @@ yyreduce: } break; - case 73: -#line 639 "go.y" + case 74: +#line 646 "go.y" { (yyval.node) = (yyvsp[(1) - (2)].node); (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list)); } break; - case 74: -#line 646 "go.y" + case 75: +#line 653 "go.y" { markdcl(); } break; - case 75: -#line 650 "go.y" + case 76: +#line 657 "go.y" { (yyval.node) = (yyvsp[(3) - (3)].node); popdcl(); } break; - case 76: -#line 657 "go.y" + case 77: +#line 664 "go.y" { // test (yyval.node) = nod(OIF, N, N); @@ -3039,8 +3035,8 @@ yyreduce: } break; - case 77: -#line 663 "go.y" + case 78: +#line 670 "go.y" { // init ; test (yyval.node) = nod(OIF, N, N); @@ -3050,30 +3046,30 @@ yyreduce: } break; - case 78: -#line 674 "go.y" + case 79: +#line 681 "go.y" { markdcl(); } break; - case 79: -#line 678 "go.y" + case 80: +#line 685 "go.y" { if((yyvsp[(3) - (3)].node)->ntest == N) yyerror("missing condition in if statement"); } break; - case 80: -#line 683 "go.y" + case 81: +#line 690 "go.y" { (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); } break; - case 81: -#line 687 "go.y" + case 82: +#line 694 "go.y" { Node *n; NodeList *nn; @@ -3090,15 +3086,15 @@ yyreduce: } break; - case 82: -#line 704 "go.y" + case 83: +#line 711 "go.y" { markdcl(); } break; - case 83: -#line 708 "go.y" + case 84: +#line 715 "go.y" { if((yyvsp[(4) - (5)].node)->ntest == N) yyerror("missing condition in if statement"); @@ -3107,29 +3103,29 @@ yyreduce: } break; - case 84: -#line 716 "go.y" + case 85: +#line 723 "go.y" { (yyval.list) = nil; } break; - case 85: -#line 720 "go.y" + case 86: +#line 727 "go.y" { (yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); } break; - case 86: -#line 725 "go.y" + case 87: +#line 732 "go.y" { (yyval.list) = nil; } break; - case 87: -#line 729 "go.y" + case 88: +#line 736 "go.y" { NodeList *node; @@ -3140,15 +3136,15 @@ yyreduce: } break; - case 88: -#line 740 "go.y" + case 89: +#line 747 "go.y" { markdcl(); } break; - case 89: -#line 744 "go.y" + case 90: +#line 751 "go.y" { Node *n; n = (yyvsp[(3) - (3)].node)->ntest; @@ -3158,8 +3154,8 @@ yyreduce: } break; - case 90: -#line 752 "go.y" + case 91: +#line 759 "go.y" { (yyval.node) = (yyvsp[(3) - (7)].node); (yyval.node)->op = OSWITCH; @@ -3169,15 +3165,15 @@ yyreduce: } break; - case 91: -#line 762 "go.y" + case 92: +#line 769 "go.y" { typesw = nod(OXXX, typesw, N); } break; - case 92: -#line 766 "go.y" + case 93: +#line 773 "go.y" { (yyval.node) = nod(OSELECT, N, N); (yyval.node)->lineno = typesw->lineno; @@ -3186,155 +3182,155 @@ yyreduce: } break; - case 94: -#line 779 "go.y" + case 95: +#line 786 "go.y" { (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 95: -#line 783 "go.y" + case 96: +#line 790 "go.y" { (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 96: -#line 787 "go.y" + case 97: +#line 794 "go.y" { (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 97: -#line 791 "go.y" + case 98: +#line 798 "go.y" { (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 98: -#line 795 "go.y" + case 99: +#line 802 "go.y" { (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 99: -#line 799 "go.y" + case 100: +#line 806 "go.y" { (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 100: -#line 803 "go.y" + case 101: +#line 810 "go.y" { (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 101: -#line 807 "go.y" + case 102: +#line 814 "go.y" { (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 102: -#line 811 "go.y" + case 103: +#line 818 "go.y" { (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 103: -#line 815 "go.y" + case 104: +#line 822 "go.y" { (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 104: -#line 819 "go.y" + case 105: +#line 826 "go.y" { (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 105: -#line 823 "go.y" + case 106: +#line 830 "go.y" { (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 106: -#line 827 "go.y" + case 107: +#line 834 "go.y" { (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 107: -#line 831 "go.y" + case 108: +#line 838 "go.y" { (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 108: -#line 835 "go.y" + case 109: +#line 842 "go.y" { (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 109: -#line 839 "go.y" + case 110: +#line 846 "go.y" { (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 110: -#line 843 "go.y" + case 111: +#line 850 "go.y" { (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 111: -#line 847 "go.y" + case 112: +#line 854 "go.y" { (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 112: -#line 851 "go.y" + case 113: +#line 858 "go.y" { (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 113: -#line 856 "go.y" + case 114: +#line 863 "go.y" { (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 115: -#line 863 "go.y" + case 116: +#line 870 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; - case 116: -#line 867 "go.y" + case 117: +#line 874 "go.y" { if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) { // Special case for &T{...}: turn into (*T){...}. @@ -3347,66 +3343,66 @@ yyreduce: } break; - case 117: -#line 878 "go.y" + case 118: +#line 885 "go.y" { (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N); } break; - case 118: -#line 882 "go.y" + case 119: +#line 889 "go.y" { (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N); } break; - case 119: -#line 886 "go.y" + case 120: +#line 893 "go.y" { (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N); } break; - case 120: -#line 890 "go.y" + case 121: +#line 897 "go.y" { yyerror("the bitwise complement operator is ^"); (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); } break; - case 121: -#line 895 "go.y" + case 122: +#line 902 "go.y" { (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); } break; - case 122: -#line 899 "go.y" + case 123: +#line 906 "go.y" { (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N); } break; - case 123: -#line 909 "go.y" + case 124: +#line 916 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N); } break; - case 124: -#line 913 "go.y" + case 125: +#line 920 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); (yyval.node)->list = (yyvsp[(3) - (5)].list); } break; - case 125: -#line 918 "go.y" + case 126: +#line 925 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N); (yyval.node)->list = (yyvsp[(3) - (6)].list); @@ -3414,15 +3410,15 @@ yyreduce: } break; - case 126: -#line 926 "go.y" + case 127: +#line 933 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; - case 128: -#line 931 "go.y" + case 129: +#line 938 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -3435,36 +3431,36 @@ yyreduce: } break; - case 129: -#line 942 "go.y" + case 130: +#line 949 "go.y" { (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node)); } break; - case 130: -#line 946 "go.y" + case 131: +#line 953 "go.y" { (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node)); } break; - case 131: -#line 950 "go.y" + case 132: +#line 957 "go.y" { (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); } break; - case 132: -#line 954 "go.y" + case 133: +#line 961 "go.y" { (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node))); } break; - case 133: -#line 958 "go.y" + case 134: +#line 965 "go.y" { if((yyvsp[(5) - (8)].node) == N) yyerror("middle index required in 3-index slice"); @@ -3474,8 +3470,8 @@ yyreduce: } break; - case 135: -#line 967 "go.y" + case 136: +#line 974 "go.y" { // conversion (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); @@ -3483,8 +3479,8 @@ yyreduce: } break; - case 136: -#line 973 "go.y" + case 137: +#line 980 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3493,8 +3489,8 @@ yyreduce: } break; - case 137: -#line 980 "go.y" + case 138: +#line 987 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3502,8 +3498,8 @@ yyreduce: } break; - case 138: -#line 986 "go.y" + case 139: +#line 993 "go.y" { yyerror("cannot parenthesize type in composite literal"); (yyval.node) = (yyvsp[(5) - (7)].node); @@ -3512,8 +3508,8 @@ yyreduce: } break; - case 140: -#line 995 "go.y" + case 141: +#line 1002 "go.y" { // composite expression. // make node early so we get the right line number. @@ -3521,15 +3517,15 @@ yyreduce: } break; - case 141: -#line 1003 "go.y" + case 142: +#line 1010 "go.y" { (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; - case 142: -#line 1009 "go.y" + case 143: +#line 1016 "go.y" { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -3548,24 +3544,24 @@ yyreduce: } break; - case 143: -#line 1026 "go.y" + case 144: +#line 1033 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); } break; - case 145: -#line 1034 "go.y" + case 146: +#line 1041 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); } break; - case 147: -#line 1042 "go.y" + case 148: +#line 1049 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -3584,22 +3580,22 @@ yyreduce: } break; - case 151: -#line 1068 "go.y" + case 152: +#line 1075 "go.y" { (yyval.i) = LBODY; } break; - case 152: -#line 1072 "go.y" + case 153: +#line 1079 "go.y" { (yyval.i) = '{'; } break; - case 153: -#line 1083 "go.y" + case 154: +#line 1090 "go.y" { if((yyvsp[(1) - (1)].sym) == S) (yyval.node) = N; @@ -3608,22 +3604,22 @@ yyreduce: } break; - case 154: -#line 1092 "go.y" + case 155: +#line 1099 "go.y" { (yyval.node) = dclname((yyvsp[(1) - (1)].sym)); } break; - case 155: -#line 1097 "go.y" + case 156: +#line 1104 "go.y" { (yyval.node) = N; } break; - case 157: -#line 1104 "go.y" + case 158: +#line 1111 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); // during imports, unqualified non-exported identifiers are from builtinpkg @@ -3632,15 +3628,15 @@ yyreduce: } break; - case 159: -#line 1112 "go.y" + case 160: +#line 1119 "go.y" { (yyval.sym) = S; } break; - case 160: -#line 1118 "go.y" + case 161: +#line 1125 "go.y" { Pkg *p; @@ -3655,8 +3651,8 @@ yyreduce: } break; - case 161: -#line 1131 "go.y" + case 162: +#line 1138 "go.y" { Pkg *p; @@ -3671,8 +3667,8 @@ yyreduce: } break; - case 162: -#line 1146 "go.y" + case 163: +#line 1153 "go.y" { (yyval.node) = oldname((yyvsp[(1) - (1)].sym)); if((yyval.node)->pack != N) @@ -3680,44 +3676,44 @@ yyreduce: } break; - case 164: -#line 1166 "go.y" + case 165: +#line 1173 "go.y" { yyerror("final argument in variadic function missing type"); (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N); } break; - case 165: -#line 1171 "go.y" + case 166: +#line 1178 "go.y" { (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N); } break; - case 171: -#line 1182 "go.y" + case 172: +#line 1189 "go.y" { - (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); + (yyval.node) = (yyvsp[(2) - (3)].node); } break; - case 175: -#line 1191 "go.y" + case 176: +#line 1198 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; - case 180: -#line 1201 "go.y" + case 181: +#line 1208 "go.y" { - (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); + (yyval.node) = (yyvsp[(2) - (3)].node); } break; - case 190: -#line 1222 "go.y" + case 191: +#line 1229 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -3730,61 +3726,61 @@ yyreduce: } break; - case 191: -#line 1235 "go.y" + case 192: +#line 1242 "go.y" { (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node)); } break; - case 192: -#line 1239 "go.y" + case 193: +#line 1246 "go.y" { // array literal of nelem (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node)); } break; - case 193: -#line 1244 "go.y" + case 194: +#line 1251 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N); (yyval.node)->etype = Cboth; } break; - case 194: -#line 1249 "go.y" + case 195: +#line 1256 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Csend; } break; - case 195: -#line 1254 "go.y" + case 196: +#line 1261 "go.y" { (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); } break; - case 198: -#line 1262 "go.y" + case 199: +#line 1269 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; - case 199: -#line 1268 "go.y" + case 200: +#line 1275 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Crecv; } break; - case 200: -#line 1275 "go.y" + case 201: +#line 1282 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3792,16 +3788,16 @@ yyreduce: } break; - case 201: -#line 1281 "go.y" + case 202: +#line 1288 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); fixlbrace((yyvsp[(2) - (3)].i)); } break; - case 202: -#line 1288 "go.y" + case 203: +#line 1295 "go.y" { (yyval.node) = nod(OTINTER, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3809,16 +3805,16 @@ yyreduce: } break; - case 203: -#line 1294 "go.y" + case 204: +#line 1301 "go.y" { (yyval.node) = nod(OTINTER, N, N); fixlbrace((yyvsp[(2) - (3)].i)); } break; - case 204: -#line 1305 "go.y" + case 205: +#line 1312 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); if((yyval.node) == N) @@ -3828,12 +3824,13 @@ yyreduce: (yyval.node)->nbody = (yyvsp[(3) - (3)].list); (yyval.node)->endlineno = lineno; (yyval.node)->noescape = noescape; + (yyval.node)->nosplit = nosplit; funcbody((yyval.node)); } break; - case 205: -#line 1319 "go.y" + case 206: +#line 1327 "go.y" { Node *t; @@ -3864,8 +3861,8 @@ yyreduce: } break; - case 206: -#line 1348 "go.y" + case 207: +#line 1356 "go.y" { Node *rcvr, *t; @@ -3886,8 +3883,6 @@ yyreduce: yyerror("bad receiver in method"); break; } - if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) - yyerror("cannot parenthesize receiver type"); t = nod(OTFUNC, rcvr, N); t->list = (yyvsp[(6) - (8)].list); @@ -3905,8 +3900,8 @@ yyreduce: } break; - case 207: -#line 1388 "go.y" + case 208: +#line 1394 "go.y" { Sym *s; Type *t; @@ -3933,8 +3928,8 @@ yyreduce: } break; - case 208: -#line 1413 "go.y" + case 209: +#line 1419 "go.y" { (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); @@ -3952,8 +3947,8 @@ yyreduce: } break; - case 209: -#line 1431 "go.y" + case 210: +#line 1437 "go.y" { (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); (yyval.node) = nod(OTFUNC, N, N); @@ -3962,15 +3957,15 @@ yyreduce: } break; - case 210: -#line 1439 "go.y" + case 211: +#line 1445 "go.y" { (yyval.list) = nil; } break; - case 211: -#line 1443 "go.y" + case 212: +#line 1449 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); if((yyval.list) == nil) @@ -3978,119 +3973,120 @@ yyreduce: } break; - case 212: -#line 1451 "go.y" + case 213: +#line 1457 "go.y" { (yyval.list) = nil; } break; - case 213: -#line 1455 "go.y" + case 214: +#line 1461 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); } break; - case 214: -#line 1459 "go.y" + case 215: +#line 1465 "go.y" { (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); (yyval.list) = (yyvsp[(2) - (3)].list); } break; - case 215: -#line 1466 "go.y" + case 216: +#line 1472 "go.y" { closurehdr((yyvsp[(1) - (1)].node)); } break; - case 216: -#line 1472 "go.y" + case 217: +#line 1478 "go.y" { (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); fixlbrace((yyvsp[(2) - (4)].i)); } break; - case 217: -#line 1477 "go.y" + case 218: +#line 1483 "go.y" { (yyval.node) = closurebody(nil); } break; - case 218: -#line 1488 "go.y" + case 219: +#line 1494 "go.y" { (yyval.list) = nil; } break; - case 219: -#line 1492 "go.y" + case 220: +#line 1498 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); if(nsyntaxerrors == 0) testdclstack(); nointerface = 0; noescape = 0; + nosplit = 0; } break; - case 221: -#line 1503 "go.y" + case 222: +#line 1510 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; - case 223: -#line 1510 "go.y" + case 224: +#line 1517 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; - case 224: -#line 1516 "go.y" + case 225: +#line 1523 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 225: -#line 1520 "go.y" + case 226: +#line 1527 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 227: -#line 1527 "go.y" + case 228: +#line 1534 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; - case 228: -#line 1533 "go.y" + case 229: +#line 1540 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 229: -#line 1537 "go.y" + case 230: +#line 1544 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 230: -#line 1543 "go.y" + case 231: +#line 1550 "go.y" { NodeList *l; @@ -4115,16 +4111,16 @@ yyreduce: } break; - case 231: -#line 1566 "go.y" + case 232: +#line 1573 "go.y" { (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); (yyval.list) = list1((yyvsp[(1) - (2)].node)); } break; - case 232: -#line 1571 "go.y" + case 233: +#line 1578 "go.y" { (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); (yyval.list) = list1((yyvsp[(2) - (4)].node)); @@ -4132,8 +4128,8 @@ yyreduce: } break; - case 233: -#line 1577 "go.y" + case 234: +#line 1584 "go.y" { (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); @@ -4141,8 +4137,8 @@ yyreduce: } break; - case 234: -#line 1583 "go.y" + case 235: +#line 1590 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4151,8 +4147,8 @@ yyreduce: } break; - case 235: -#line 1590 "go.y" + case 236: +#line 1597 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4161,8 +4157,8 @@ yyreduce: } break; - case 236: -#line 1599 "go.y" + case 237: +#line 1606 "go.y" { Node *n; @@ -4173,8 +4169,8 @@ yyreduce: } break; - case 237: -#line 1608 "go.y" + case 238: +#line 1615 "go.y" { Pkg *pkg; @@ -4189,38 +4185,38 @@ yyreduce: } break; - case 238: -#line 1623 "go.y" + case 239: +#line 1630 "go.y" { (yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg); } break; - case 239: -#line 1629 "go.y" + case 240: +#line 1636 "go.y" { (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ifacedcl((yyval.node)); } break; - case 240: -#line 1634 "go.y" + case 241: +#line 1641 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); } break; - case 241: -#line 1638 "go.y" + case 242: +#line 1645 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); yyerror("cannot parenthesize embedded type"); } break; - case 242: -#line 1645 "go.y" + case 243: +#line 1652 "go.y" { // without func keyword (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); @@ -4230,8 +4226,8 @@ yyreduce: } break; - case 244: -#line 1659 "go.y" + case 245: +#line 1666 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4239,8 +4235,8 @@ yyreduce: } break; - case 245: -#line 1665 "go.y" + case 246: +#line 1672 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4248,65 +4244,65 @@ yyreduce: } break; - case 247: -#line 1674 "go.y" + case 248: +#line 1681 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 248: -#line 1678 "go.y" + case 249: +#line 1685 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 249: -#line 1683 "go.y" + case 250: +#line 1690 "go.y" { (yyval.list) = nil; } break; - case 250: -#line 1687 "go.y" + case 251: +#line 1694 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; - case 251: -#line 1695 "go.y" + case 252: +#line 1702 "go.y" { (yyval.node) = N; } break; - case 253: -#line 1700 "go.y" + case 254: +#line 1707 "go.y" { (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); } break; - case 255: -#line 1705 "go.y" + case 256: +#line 1712 "go.y" { (yyval.node) = N; } break; - case 261: -#line 1716 "go.y" + case 262: +#line 1723 "go.y" { (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions } break; - case 262: -#line 1721 "go.y" + case 263: +#line 1728 "go.y" { NodeList *l; @@ -4318,8 +4314,8 @@ yyreduce: } break; - case 263: -#line 1731 "go.y" + case 264: +#line 1738 "go.y" { // will be converted to OFALL (yyval.node) = nod(OXFALL, N, N); @@ -4327,44 +4323,44 @@ yyreduce: } break; - case 264: -#line 1737 "go.y" + case 265: +#line 1744 "go.y" { (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); } break; - case 265: -#line 1741 "go.y" + case 266: +#line 1748 "go.y" { (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); } break; - case 266: -#line 1745 "go.y" + case 267: +#line 1752 "go.y" { (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); } break; - case 267: -#line 1749 "go.y" + case 268: +#line 1756 "go.y" { (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); } break; - case 268: -#line 1753 "go.y" + case 269: +#line 1760 "go.y" { (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); (yyval.node)->sym = dclstack; // context, for goto restrictions } break; - case 269: -#line 1758 "go.y" + case 270: +#line 1765 "go.y" { (yyval.node) = nod(ORETURN, N, N); (yyval.node)->list = (yyvsp[(2) - (2)].list); @@ -4383,8 +4379,8 @@ yyreduce: } break; - case 270: -#line 1777 "go.y" + case 271: +#line 1784 "go.y" { (yyval.list) = nil; if((yyvsp[(1) - (1)].node) != N) @@ -4392,8 +4388,8 @@ yyreduce: } break; - case 271: -#line 1783 "go.y" + case 272: +#line 1790 "go.y" { (yyval.list) = (yyvsp[(1) - (3)].list); if((yyvsp[(3) - (3)].node) != N) @@ -4401,190 +4397,190 @@ yyreduce: } break; - case 272: -#line 1791 "go.y" + case 273: +#line 1798 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 273: -#line 1795 "go.y" + case 274: +#line 1802 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 274: -#line 1801 "go.y" + case 275: +#line 1808 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 275: -#line 1805 "go.y" + case 276: +#line 1812 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 276: -#line 1811 "go.y" + case 277: +#line 1818 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 277: -#line 1815 "go.y" + case 278: +#line 1822 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 278: -#line 1821 "go.y" + case 279: +#line 1828 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 279: -#line 1825 "go.y" + case 280: +#line 1832 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 280: -#line 1834 "go.y" + case 281: +#line 1841 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 281: -#line 1838 "go.y" + case 282: +#line 1845 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 282: -#line 1842 "go.y" + case 283: +#line 1849 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 283: -#line 1846 "go.y" + case 284: +#line 1853 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 284: -#line 1851 "go.y" + case 285: +#line 1858 "go.y" { (yyval.list) = nil; } break; - case 285: -#line 1855 "go.y" + case 286: +#line 1862 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; - case 290: -#line 1869 "go.y" + case 291: +#line 1876 "go.y" { (yyval.node) = N; } break; - case 292: -#line 1875 "go.y" + case 293: +#line 1882 "go.y" { (yyval.list) = nil; } break; - case 294: -#line 1881 "go.y" + case 295: +#line 1888 "go.y" { (yyval.node) = N; } break; - case 296: -#line 1887 "go.y" + case 297: +#line 1894 "go.y" { (yyval.list) = nil; } break; - case 298: -#line 1893 "go.y" + case 299: +#line 1900 "go.y" { (yyval.list) = nil; } break; - case 300: -#line 1899 "go.y" + case 301: +#line 1906 "go.y" { (yyval.list) = nil; } break; - case 302: -#line 1905 "go.y" + case 303: +#line 1912 "go.y" { (yyval.val).ctype = CTxxx; } break; - case 304: -#line 1915 "go.y" + case 305: +#line 1922 "go.y" { importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); } break; - case 305: -#line 1919 "go.y" + case 306: +#line 1926 "go.y" { importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); } break; - case 306: -#line 1923 "go.y" + case 307: +#line 1930 "go.y" { importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); } break; - case 307: -#line 1927 "go.y" + case 308: +#line 1934 "go.y" { importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); } break; - case 308: -#line 1931 "go.y" + case 309: +#line 1938 "go.y" { importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); } break; - case 309: -#line 1935 "go.y" + case 310: +#line 1942 "go.y" { if((yyvsp[(2) - (4)].node) == N) { dclcontext = PEXTERN; // since we skip the funcbody below @@ -4604,31 +4600,31 @@ yyreduce: } break; - case 310: -#line 1955 "go.y" + case 311: +#line 1962 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); structpkg = (yyval.sym)->pkg; } break; - case 311: -#line 1962 "go.y" + case 312: +#line 1969 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); importsym((yyvsp[(1) - (1)].sym), OTYPE); } break; - case 317: -#line 1982 "go.y" + case 318: +#line 1989 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); } break; - case 318: -#line 1986 "go.y" + case 319: +#line 1993 "go.y" { // predefined name like uint8 (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); @@ -4640,50 +4636,50 @@ yyreduce: } break; - case 319: -#line 1996 "go.y" + case 320: +#line 2003 "go.y" { (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); } break; - case 320: -#line 2000 "go.y" + case 321: +#line 2007 "go.y" { (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); } break; - case 321: -#line 2004 "go.y" + case 322: +#line 2011 "go.y" { (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); } break; - case 322: -#line 2008 "go.y" + case 323: +#line 2015 "go.y" { (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); } break; - case 323: -#line 2012 "go.y" + case 324: +#line 2019 "go.y" { (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); } break; - case 324: -#line 2016 "go.y" + case 325: +#line 2023 "go.y" { (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); } break; - case 325: -#line 2020 "go.y" + case 326: +#line 2027 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(2) - (2)].type); @@ -4691,8 +4687,8 @@ yyreduce: } break; - case 326: -#line 2026 "go.y" + case 327: +#line 2033 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (4)].type); @@ -4700,8 +4696,8 @@ yyreduce: } break; - case 327: -#line 2032 "go.y" + case 328: +#line 2039 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4709,8 +4705,8 @@ yyreduce: } break; - case 328: -#line 2040 "go.y" + case 329: +#line 2047 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4718,15 +4714,15 @@ yyreduce: } break; - case 329: -#line 2048 "go.y" + case 330: +#line 2055 "go.y" { (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); } break; - case 330: -#line 2054 "go.y" + case 331: +#line 2061 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); if((yyvsp[(1) - (3)].sym)) @@ -4735,8 +4731,8 @@ yyreduce: } break; - case 331: -#line 2061 "go.y" + case 332: +#line 2068 "go.y" { Type *t; @@ -4752,8 +4748,8 @@ yyreduce: } break; - case 332: -#line 2077 "go.y" + case 333: +#line 2084 "go.y" { Sym *s; Pkg *p; @@ -4775,50 +4771,50 @@ yyreduce: } break; - case 333: -#line 2099 "go.y" + case 334: +#line 2106 "go.y" { (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); } break; - case 334: -#line 2103 "go.y" + case 335: +#line 2110 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); } break; - case 335: -#line 2108 "go.y" + case 336: +#line 2115 "go.y" { (yyval.list) = nil; } break; - case 337: -#line 2115 "go.y" + case 338: +#line 2122 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); } break; - case 338: -#line 2119 "go.y" + case 339: +#line 2126 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); } break; - case 339: -#line 2129 "go.y" + case 340: +#line 2136 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; - case 340: -#line 2133 "go.y" + case 341: +#line 2140 "go.y" { (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); switch((yyval.node)->val.ctype){ @@ -4839,8 +4835,8 @@ yyreduce: } break; - case 341: -#line 2152 "go.y" + case 342: +#line 2159 "go.y" { (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); if((yyval.node)->op != OLITERAL) @@ -4848,8 +4844,8 @@ yyreduce: } break; - case 343: -#line 2161 "go.y" + case 344: +#line 2168 "go.y" { if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { (yyval.node) = (yyvsp[(2) - (5)].node); @@ -4862,43 +4858,43 @@ yyreduce: } break; - case 346: -#line 2177 "go.y" + case 347: +#line 2184 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 347: -#line 2181 "go.y" + case 348: +#line 2188 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 348: -#line 2187 "go.y" + case 349: +#line 2194 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 349: -#line 2191 "go.y" + case 350: +#line 2198 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; - case 350: -#line 2197 "go.y" + case 351: +#line 2204 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 351: -#line 2201 "go.y" + case 352: +#line 2208 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } @@ -4906,7 +4902,7 @@ yyreduce: /* Line 1267 of yacc.c. */ -#line 4911 "y.tab.c" +#line 4907 "y.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -5120,7 +5116,7 @@ yyreturn: } -#line 2205 "go.y" +#line 2212 "go.y" static void diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h index 1526d8231..d0dd639ff 100644 --- a/src/cmd/gc/yerr.h +++ b/src/cmd/gc/yerr.h @@ -14,66 +14,66 @@ static struct { // is converted by bisonerrors into the yystate and yychar caused // by that token list. - 222, ',', - "unexpected comma during import block", + {222, ',', + "unexpected comma during import block"}, - 32, ';', - "missing import path; require quoted string", + {32, ';', + "missing import path; require quoted string"}, - 378, ';', - "missing { after if clause", + {380, ';', + "missing { after if clause"}, - 399, ';', - "missing { after switch clause", + {401, ';', + "missing { after switch clause"}, - 238, ';', - "missing { after for clause", + {239, ';', + "missing { after for clause"}, - 476, LBODY, - "missing { after for clause", + {478, LBODY, + "missing { after for clause"}, - 22, '{', - "unexpected semicolon or newline before {", + {22, '{', + "unexpected semicolon or newline before {"}, - 145, ';', - "unexpected semicolon or newline in type declaration", + {145, ';', + "unexpected semicolon or newline in type declaration"}, - 37, '}', - "unexpected } in channel type", + {37, '}', + "unexpected } in channel type"}, - 37, ')', - "unexpected ) in channel type", + {37, ')', + "unexpected ) in channel type"}, - 37, ',', - "unexpected comma in channel type", + {37, ',', + "unexpected comma in channel type"}, - 439, LELSE, - "unexpected semicolon or newline before else", + {441, LELSE, + "unexpected semicolon or newline before else"}, - 258, ',', - "name list not allowed in interface type", + {259, ',', + "name list not allowed in interface type"}, - 238, LVAR, - "var declaration not allowed in for initializer", + {239, LVAR, + "var declaration not allowed in for initializer"}, - 65, '{', - "unexpected { at end of statement", + {65, '{', + "unexpected { at end of statement"}, - 377, '{', - "unexpected { at end of statement", + {379, '{', + "unexpected { at end of statement"}, - 126, ';', - "argument to go/defer must be function call", + {126, ';', + "argument to go/defer must be function call"}, - 426, ';', - "need trailing comma before newline in composite literal", + {428, ';', + "need trailing comma before newline in composite literal"}, - 437, ';', - "need trailing comma before newline in composite literal", + {439, ';', + "need trailing comma before newline in composite literal"}, - 113, LNAME, - "nested func not allowed", + {113, LNAME, + "nested func not allowed"}, - 645, ';', - "else must be followed by if or statement block" + {647, ';', + "else must be followed by if or statement block"} }; diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 3645f1c2d..1dd4314da 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -57,6 +57,7 @@ and test commands: -a force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. -n print the commands but do not run them. -p n @@ -64,7 +65,7 @@ and test commands: The default is the number of CPUs available. -race enable data race detection. - Supported only on linux/amd64, darwin/amd64 and windows/amd64. + Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. -v print the names of packages as they are compiled. -work @@ -284,23 +285,26 @@ func runBuild(cmd *Command, args []string) { } } + depMode := modeBuild + if buildI { + depMode = modeInstall + } + if *buildO != "" { if len(pkgs) > 1 { fatalf("go build: cannot use -o with multiple packages") + } else if len(pkgs) == 0 { + fatalf("no packages to build") } p := pkgs[0] p.target = "" // must build - not up to date - a := b.action(modeInstall, modeBuild, p) + a := b.action(modeInstall, depMode, p) a.target = *buildO b.do(a) return } a := &action{} - depMode := modeBuild - if buildI { - depMode = modeInstall - } for _, p := range packages(args) { a.deps = append(a.deps, b.action(modeBuild, depMode, p)) } @@ -431,12 +435,11 @@ const ( ) var ( - goroot = filepath.Clean(runtime.GOROOT()) - gobin = os.Getenv("GOBIN") - gorootBin = filepath.Join(goroot, "bin") - gorootSrcPkg = filepath.Join(goroot, "src/pkg") - gorootPkg = filepath.Join(goroot, "pkg") - gorootSrc = filepath.Join(goroot, "src") + goroot = filepath.Clean(runtime.GOROOT()) + gobin = os.Getenv("GOBIN") + gorootBin = filepath.Join(goroot, "bin") + gorootPkg = filepath.Join(goroot, "pkg") + gorootSrc = filepath.Join(goroot, "src") ) func (b *builder) init() { @@ -503,8 +506,13 @@ func goFilesPackage(gofiles []string) *Package { } ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil } - if !filepath.IsAbs(dir) { - dir = filepath.Join(cwd, dir) + var err error + if dir == "" { + dir = cwd + } + dir, err = filepath.Abs(dir) + if err != nil { + fatalf("%s", err) } bp, err := ctxt.ImportDir(dir, 0) @@ -823,12 +831,17 @@ func (b *builder) build(a *action) (err error) { } } - var gofiles, cfiles, sfiles, objects, cgoObjects []string + var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.p.GoFiles...) cfiles = append(cfiles, a.p.CFiles...) sfiles = append(sfiles, a.p.SFiles...) + if a.p.usesCgo() || a.p.usesSwig() { + if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { + return + } + } // Run cgo. if a.p.usesCgo() { // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. @@ -859,7 +872,7 @@ func (b *builder) build(a *action) (err error) { if a.cgo != nil && a.cgo.target != "" { cgoExe = a.cgo.target } - outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles) if err != nil { return err } @@ -872,9 +885,18 @@ func (b *builder) build(a *action) (err error) { // In a package using SWIG, any .c or .s files are // compiled with gcc. gccfiles := append(cfiles, sfiles...) + cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles cfiles = nil sfiles = nil - outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + + // Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config). + if a.p.usesCgo() { + cxxfiles = nil + gccfiles = nil + mfiles = nil + } + + outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles) if err != nil { return err } @@ -883,7 +905,7 @@ func (b *builder) build(a *action) (err error) { } if len(gofiles) == 0 { - return &build.NoGoError{a.p.Dir} + return &build.NoGoError{Dir: a.p.Dir} } // If we're doing coverage, preprocess the .go files and put them in the work directory @@ -1018,6 +1040,34 @@ func (b *builder) build(a *action) (err error) { return nil } +// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. +func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) { + if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { + var out []byte + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + cflags = strings.Fields(string(out)) + } + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + ldflags = strings.Fields(string(out)) + } + } + return +} + // install is the action for installing a single package or executable. func (b *builder) install(a *action) (err error) { defer func() { @@ -1253,7 +1303,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { // the source directory for the package that has failed to build. // showOutput rewrites mentions of dir with a relative path to dir // when the relative path is shorter. This is usually more pleasant. -// For example, if fmt doesn't compile and we are in src/pkg/html, +// For example, if fmt doesn't compile and we are in src/html, // the output is // // $ go build @@ -1265,7 +1315,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { // // $ go build // # fmt -// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf +// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf // $ // // showOutput also replaces references to the work directory with $WORK. @@ -1425,6 +1475,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter continue } + // err can be something like 'exit status 1'. + // Add information about what program was running. + // Note that if buf.Bytes() is non-empty, the caller usually + // shows buf.Bytes() and does not print err at all, so the + // prefix here does not make most output any more verbose. + if err != nil { + err = errors.New(cmdline[0] + ": " + err.Error()) + } return buf.Bytes(), err } } @@ -1587,7 +1645,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) if p.Standard { switch p.ImportPath { - case "os", "runtime/pprof", "sync", "time": + case "bytes", "net", "os", "runtime/pprof", "sync", "time": extFiles++ } } @@ -1611,8 +1669,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] } func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { + // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. + inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) sfile = mkAbs(p.Dir, sfile) - return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) + return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) } func (gcToolchain) pkgpath(basedir string, p *Package) string { @@ -1706,7 +1766,7 @@ func packInternal(b *builder, afile string, ofiles []string) error { func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { importArgs := b.includeArgs("-L", allactions) - cxx := false + cxx := len(p.CXXFiles) > 0 for _, a := range allactions { if a.p != nil && len(a.p.CXXFiles) > 0 { cxx = true @@ -1766,14 +1826,30 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) cfile = mkAbs(p.Dir, cfile) - args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) + warn := []string{"-w"} + if p.usesSwig() { + // When using SWIG, this compiler is only used to + // compile the C files generated by SWIG. + // We don't want warnings. + // See issue 9065 for details. + warn = nil + } + args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) return b.run(p.Dir, p.ImportPath, nil, args) } // The Gccgo toolchain. type gccgoToolchain struct{} -var gccgoBin, _ = exec.LookPath("gccgo") +var gccgoName, gccgoBin string + +func init() { + gccgoName = os.Getenv("GCCGO") + if gccgoName == "" { + gccgoName = "gccgo" + } + gccgoBin, _ = exec.LookPath(gccgoName) +} func (gccgoToolchain) compiler() string { return gccgoBin @@ -1784,7 +1860,7 @@ func (gccgoToolchain) linker() string { } func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - out := p.Name + ".o" + out := "_go_.o" ofile = obj + out gcargs := []string{"-g"} gcargs = append(gcargs, b.gccArchArgs()...) @@ -1794,7 +1870,7 @@ func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs if p.localPrefix != "" { gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix) } - args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) + args := stringList(gccgoName, importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) for _, f := range gofiles { args = append(args, mkAbs(p.Dir, f)) } @@ -1810,7 +1886,7 @@ func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) erro defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } defs = append(defs, b.gccArchArgs()...) - return b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile) + return b.run(p.Dir, p.ImportPath, nil, gccgoName, "-I", obj, "-o", ofile, defs, sfile) } func (gccgoToolchain) pkgpath(basedir string, p *Package) string { @@ -1836,8 +1912,8 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] ldflags := b.gccArchArgs() cgoldflags := []string{} usesCgo := false - cxx := false - objc := false + cxx := len(p.CXXFiles) > 0 + objc := len(p.MFiles) > 0 // Prefer the output of an install action to the output of a build action, // because the install action will delete the output of the build action. @@ -1877,6 +1953,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] } ldflags = append(ldflags, afiles...) ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) ldflags = append(ldflags, p.CgoLDFLAGS...) if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") @@ -1887,7 +1964,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] if objc { ldflags = append(ldflags, "-lobjc") } - return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) + return b.run(".", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) } func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { @@ -1898,8 +1975,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } - // TODO: Support using clang here (during gccgo build)? - return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g", + return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g", "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) } @@ -1950,9 +2026,9 @@ func (b *builder) libgcc(p *Package) (string, error) { return "$LIBGCC", nil } - // clang might not be able to find libgcc, and in that case, + // The compiler might not be able to find libgcc, and in that case, // it will simply return "libgcc.a", which is of no use to us. - if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) { + if !filepath.IsAbs(string(f)) { return "", nil } @@ -2090,36 +2166,16 @@ var ( cgoLibGccFileOnce sync.Once ) -func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true) _, cgoexeCFLAGS, _, _ := b.cflags(p, false) - + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) + cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc if len(mfiles) > 0 { cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") } - if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { - out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...) - } - out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...) - } - } - // Allows including _cgo_export.h from .[ch] files in the package. cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) @@ -2196,6 +2252,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles strings.HasSuffix(f, ".so"), strings.HasSuffix(f, ".dll"): continue + // Remove any -fsanitize=foo flags. + // Otherwise the compiler driver thinks that we are doing final link + // and links sanitizer runtime into the object file. But we are not doing + // the final link, we will link the resulting object file again. And + // so the program ends up with two copies of sanitizer runtime. + // See issue 8788 for details. + case strings.HasPrefix(f, "-fsanitize="): + continue default: bareLDFLAGS = append(bareLDFLAGS, f) } @@ -2262,13 +2326,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles linkobj = append(linkobj, p.SysoFiles...) dynobj := obj + "_cgo_.o" - if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym + pie := goarch == "arm" && (goos == "linux" || goos == "android") + if pie { // we need to use -pie for Linux/ARM to get accurate imported sym cgoLDFLAGS = append(cgoLDFLAGS, "-pie") } if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil { return nil, nil, err } - if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs + if pie { // but we don't need -pie for normal cgo programs cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1] } @@ -2302,7 +2367,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles nonGccObjs = append(nonGccObjs, f) } } - if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil { + ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) + + // Some systems, such as Ubuntu, always add --build-id to + // every link, but we don't want a build ID since we are + // producing an object file. On some of those system a plain + // -r (not -Wl,-r) will turn off --build-id, but clang 3.0 + // doesn't support a plain -r. I don't know how to turn off + // --build-id when using clang other than passing a trailing + // --build-id=none. So that is what we do, but only on + // systems likely to support it, which is to say, systems that + // normally use gold or the GNU linker. + switch goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + + if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil { return nil, nil, err } @@ -2317,7 +2398,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) @@ -2358,7 +2439,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } for _, f := range p.SwigFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) if err != nil { return nil, nil, err } @@ -2373,7 +2454,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } } for _, f := range p.SwigCXXFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) if err != nil { return nil, nil, err } @@ -2452,13 +2533,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { +func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) var cflags []string if cxx { - cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) } else { - cflags = stringList(cgoCPPFLAGS, cgoCFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) } n := 5 // length of ".swig" @@ -2484,6 +2565,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri "-o", obj + gccBase + gccExt, "-outdir", obj, } + + for _, f := range cflags { + if len(f) > 3 && f[:2] == "-I" { + args = append(args, f) + } + } + if gccgo { args = append(args, "-gccgo") if pkgpath := gccgoPkgpath(p); pkgpath != "" { @@ -2556,8 +2644,8 @@ func raceInit() { if !buildRace { return } - if goarch != "amd64" || goos != "linux" && goos != "darwin" && goos != "windows" { - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" { + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) os.Exit(2) } buildGcflags = append(buildGcflags, "-race") diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 9840804ce..d0d8a8a5b 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -19,6 +19,7 @@ The commands are: env print Go environment information fix run go tool fix on packages fmt run gofmt on package sources + generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages @@ -75,6 +76,7 @@ and test commands: -a force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. -n print the commands but do not run them. -p n @@ -82,7 +84,7 @@ and test commands: The default is the number of CPUs available. -race enable data race detection. - Supported only on linux/amd64, darwin/amd64 and windows/amd64. + Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. -v print the names of packages as they are compiled. -work @@ -219,11 +221,110 @@ To run gofmt with specific options, run gofmt itself. See also: go fix, go vet. +Generate Go files by processing source + +Usage: + + go generate [-run regexp] [file.go... | packages] + +Generate runs commands described by directives within existing +files. Those commands can run any process but the intent is to +create or update Go source files, for instance by running yacc. + +Go generate is never run automatically by go build, go get, go test, +and so on. It must be run explicitly. + +Go generate scans the file for directives, which are lines of +the form, + + //go:generate command argument... + +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +that can be run locally. It must either be in the shell path +(gofmt), a fully qualified path (/usr/you/bin/mytool), or a +command alias, described below. + +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. + +Quoted strings use Go syntax and are evaluated before execution; a +quoted string appears as a single argument to the generator. + +Go generate sets several variables when it runs the generator: + + $GOARCH + The execution architecture (arm, amd64, etc.) + $GOOS + The execution operating system (linux, windows, etc.) + $GOFILE + The base name of the file. + $GOPACKAGE + The name of the package of the file containing the directive. + +Other than variable substitution and quoted-string evaluation, no +special processing such as "globbing" is performed on the command +line. + +As a last step before running the command, any invocations of any +environment variables with alphanumeric names, such as $GOFILE or +$HOME, are expanded throughout the command line. The syntax for +variable expansion is $NAME on all operating systems. Due to the +order of evaluation, variables are expanded even inside quoted +strings. If the variable NAME is not set, $NAME expands to the +empty string. + +A directive of the form, + + //go:generate -command xxx args... + +specifies, for the remainder of this source file only, that the +string xxx represents the command identified by the arguments. This +can be used to create aliases or to handle multiword generators. +For example, + + //go:generate -command yacc go tool yacc + +specifies that the command "yacc" represents the generator +"go tool yacc". + +Generate processes packages in the order given on the command line, +one at a time. If the command line lists .go files, they are treated +as a single package. Within a package, generate processes the +source files in a package in file name order, one at a time. Within +a source file, generate runs generators in the order they appear +in the file, one at a time. + +If any generator returns an error exit status, "go generate" skips +all further processing for that package. + +The generator is run in the package's source directory. + +Go generate accepts one specific flag: + + -run="" + if non-empty, specifies a regular expression to + select directives whose command matches the expression. + +It also accepts the standard build flags -v, -n, and -x. +The -v flag prints the names of packages and files as they are +processed. +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +For more about specifying packages, see 'go help packages'. + + Download and install packages and dependencies Usage: - go get [-d] [-fix] [-t] [-u] [build flags] [packages] + go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages] Get downloads and installs the packages named by the import paths, along with their dependencies. @@ -231,6 +332,11 @@ along with their dependencies. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. @@ -291,28 +397,29 @@ syntax of package template. The default output is equivalent to -f '{{.ImportPath}}'. The struct being passed to the template is: type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - Name string // package name - Doc string // package documentation string - Target string // install path - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - Root string // Go root or Go path dir containing this package + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + Root string // Go root or Go path dir containing this package // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go sources files that import "C" IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive // Cgo directives CgoCFLAGS []string // cgo: flags for C compiler @@ -431,16 +538,23 @@ non-test installation. In addition to the build flags, the flags handled by 'go test' itself are: - -c Compile the test binary to pkg.test but do not run it. - (Where pkg is the last element of the package's import path.) + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. -i Install packages that are dependencies of the test. Do not run the test. - -exec xprog - Run the test binary using xprog. The behavior is the same as - in 'go run'. See 'go help run' for details. + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -488,7 +602,7 @@ Usage: Vet runs the Go vet command on the packages named by the import paths. -For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'. +For more about vet, see 'godoc golang.org/x/tools/cmd/vet'. For more about specifying packages, see 'go help packages'. To run the vet tool with specific options, run 'go tool vet'. @@ -681,6 +795,11 @@ A few common code hosting sites have special syntax: import "launchpad.net/~user/project/branch" import "launchpad.net/~user/project/branch/sub/directory" + IBM DevOps Services (Git) + + import "hub.jazz.net/git/user/project" + import "hub.jazz.net/git/user/project/sub/directory" + For code hosted on other servers, import paths may either be qualified with the version control type, or the go tool can dynamically fetch the import path over https/http and discover where the code resides @@ -756,7 +875,26 @@ listed in the GOPATH environment variable (see 'go help gopath'). The go command attempts to download the version of the package appropriate for the Go release being used. -Run 'go help install' for more. +Run 'go help get' for more. + +Import path checking + +When the custom import path feature described above redirects to a +known code hosting site, each of the resulting packages has two possible +import paths, using the custom domain or the known hosting site. + +A package statement is said to have an "import comment" if it is immediately +followed (before the next newline) by a comment of one of these two forms: + + package math // import "path" + package math /* import "path" * / + +The go command will refuse to install a package with an import comment +unless it is being referred to by that import path. In this way, import comments +let package authors make sure the custom import path is used and not a +direct path to the underlying code hosting site. + +See https://golang.org/s/go14customimport for details. Description of package lists @@ -812,7 +950,8 @@ single directory, the command is applied to a single synthesized package made up of exactly those files, ignoring any build constraints in those files and ignoring any other files in the directory. -File names that begin with "." or "_" are ignored by the go tool. +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". Description of testing flags @@ -844,6 +983,7 @@ control the execution of any test: -blockprofile block.out Write a goroutine blocking profile to the specified file when all tests are complete. + Writes test binary as -c would. -blockprofilerate n Control the detail provided in goroutine blocking profiles by @@ -875,8 +1015,7 @@ control the execution of any test: Sets -cover. -coverprofile cover.out - Write a coverage profile to the specified file after all tests - have passed. + Write a coverage profile to the file after all tests have passed. Sets -cover. -cpu 1,2,4 @@ -886,10 +1025,11 @@ control the execution of any test: -cpuprofile cpu.out Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. -memprofile mem.out - Write a memory profile to the specified file after all tests - have passed. + Write a memory profile to the file after all tests have passed. + Writes test binary as -c would. -memprofilerate n Enable more precise (and expensive) memory profiles by setting diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go new file mode 100644 index 000000000..baf4d2b55 --- /dev/null +++ b/src/cmd/go/generate.go @@ -0,0 +1,398 @@ +// Copyright 2011 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. + +package main + +import ( + "bufio" + "bytes" + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +var cmdGenerate = &Command{ + Run: runGenerate, + UsageLine: "generate [-run regexp] [file.go... | packages]", + Short: "generate Go files by processing source", + Long: ` +Generate runs commands described by directives within existing +files. Those commands can run any process but the intent is to +create or update Go source files, for instance by running yacc. + +Go generate is never run automatically by go build, go get, go test, +and so on. It must be run explicitly. + +Go generate scans the file for directives, which are lines of +the form, + + //go:generate command argument... + +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +that can be run locally. It must either be in the shell path +(gofmt), a fully qualified path (/usr/you/bin/mytool), or a +command alias, described below. + +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. + +Quoted strings use Go syntax and are evaluated before execution; a +quoted string appears as a single argument to the generator. + +Go generate sets several variables when it runs the generator: + + $GOARCH + The execution architecture (arm, amd64, etc.) + $GOOS + The execution operating system (linux, windows, etc.) + $GOFILE + The base name of the file. + $GOPACKAGE + The name of the package of the file containing the directive. + +Other than variable substitution and quoted-string evaluation, no +special processing such as "globbing" is performed on the command +line. + +As a last step before running the command, any invocations of any +environment variables with alphanumeric names, such as $GOFILE or +$HOME, are expanded throughout the command line. The syntax for +variable expansion is $NAME on all operating systems. Due to the +order of evaluation, variables are expanded even inside quoted +strings. If the variable NAME is not set, $NAME expands to the +empty string. + +A directive of the form, + + //go:generate -command xxx args... + +specifies, for the remainder of this source file only, that the +string xxx represents the command identified by the arguments. This +can be used to create aliases or to handle multiword generators. +For example, + + //go:generate -command yacc go tool yacc + +specifies that the command "yacc" represents the generator +"go tool yacc". + +Generate processes packages in the order given on the command line, +one at a time. If the command line lists .go files, they are treated +as a single package. Within a package, generate processes the +source files in a package in file name order, one at a time. Within +a source file, generate runs generators in the order they appear +in the file, one at a time. + +If any generator returns an error exit status, "go generate" skips +all further processing for that package. + +The generator is run in the package's source directory. + +Go generate accepts one specific flag: + + -run="" + if non-empty, specifies a regular expression to + select directives whose command matches the expression. + +It also accepts the standard build flags -v, -n, and -x. +The -v flag prints the names of packages and files as they are +processed. +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +For more about specifying packages, see 'go help packages'. + `, +} + +var generateRunFlag string // generate -run flag + +func init() { + addBuildFlags(cmdGenerate) + cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "") +} + +func runGenerate(cmd *Command, args []string) { + // Even if the arguments are .go files, this loop suffices. + for _, pkg := range packages(args) { + for _, file := range pkg.gofiles { + if !generate(pkg.Name, file) { + break + } + } + } +} + +// generate runs the generation directives for a single file. +func generate(pkg, absFile string) bool { + fd, err := os.Open(absFile) + if err != nil { + log.Fatalf("generate: %s", err) + } + defer fd.Close() + g := &Generator{ + r: fd, + path: absFile, + pkg: pkg, + commands: make(map[string][]string), + } + return g.run() +} + +// A Generator represents the state of a single Go source file +// being scanned for generator commands. +type Generator struct { + r io.Reader + path string // full rooted path name. + dir string // full rooted directory of file. + file string // base name of file. + pkg string + commands map[string][]string + lineNum int +} + +// run runs the generators in the current file. +func (g *Generator) run() (ok bool) { + // Processing below here calls g.errorf on failure, which does panic(stop). + // If we encounter an error, we abort the package. + defer func() { + e := recover() + if e != nil { + ok = false + if e != stop { + panic(e) + } + setExitStatus(1) + } + }() + g.dir, g.file = filepath.Split(g.path) + g.dir = filepath.Clean(g.dir) // No final separator please. + if buildV { + fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path)) + } + + // Scan for lines that start "//go:generate". + // Can't use bufio.Scanner because it can't handle long lines, + // which are likely to appear when using generate. + input := bufio.NewReader(g.r) + var err error + // One line per loop. + for { + g.lineNum++ // 1-indexed. + var buf []byte + buf, err = input.ReadSlice('\n') + if err == bufio.ErrBufferFull { + // Line too long - consume and ignore. + if isGoGenerate(buf) { + g.errorf("directive too long") + } + for err == bufio.ErrBufferFull { + _, err = input.ReadSlice('\n') + } + if err != nil { + break + } + continue + } + + if err != nil { + // Check for marker at EOF without final \n. + if err == io.EOF && isGoGenerate(buf) { + err = io.ErrUnexpectedEOF + } + break + } + + if !isGoGenerate(buf) { + continue + } + + words := g.split(string(buf)) + if len(words) == 0 { + g.errorf("no arguments to directive") + } + if words[0] == "-command" { + g.setShorthand(words) + continue + } + // Run the command line. + if buildN || buildX { + fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " ")) + } + if buildN { + continue + } + g.exec(words) + } + if err != nil && err != io.EOF { + g.errorf("error reading %s: %s", shortPath(g.path), err) + } + return true +} + +func isGoGenerate(buf []byte) bool { + return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t")) +} + +// split breaks the line into words, evaluating quoted +// strings and evaluating environment variables. +// The initial //go:generate element is present in line. +func (g *Generator) split(line string) []string { + // Parse line, obeying quoted strings. + var words []string + line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline. + // One (possibly quoted) word per iteration. +Words: + for { + line = strings.TrimLeft(line, " \t") + if len(line) == 0 { + break + } + if line[0] == '"' { + for i := 1; i < len(line); i++ { + c := line[i] // Only looking for ASCII so this is OK. + switch c { + case '\\': + if i+1 == len(line) { + g.errorf("bad backslash") + } + i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote). + case '"': + word, err := strconv.Unquote(line[0 : i+1]) + if err != nil { + g.errorf("bad quoted string") + } + words = append(words, word) + line = line[i+1:] + // Check the next character is space or end of line. + if len(line) > 0 && line[0] != ' ' && line[0] != '\t' { + g.errorf("expect space after quoted argument") + } + continue Words + } + } + g.errorf("mismatched quoted string") + } + i := strings.IndexAny(line, " \t") + if i < 0 { + i = len(line) + } + words = append(words, line[0:i]) + line = line[i:] + } + // Substitute command if required. + if len(words) > 0 && g.commands[words[0]] != nil { + // Replace 0th word by command substitution. + words = append(g.commands[words[0]], words[1:]...) + } + // Substitute environment variables. + for i, word := range words { + words[i] = g.expandEnv(word) + } + return words +} + +var stop = fmt.Errorf("error in generation") + +// errorf logs an error message prefixed with the file and line number. +// It then exits the program (with exit status 1) because generation stops +// at the first error. +func (g *Generator) errorf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum, + fmt.Sprintf(format, args...)) + panic(stop) +} + +// expandEnv expands any $XXX invocations in word. +func (g *Generator) expandEnv(word string) string { + if !strings.ContainsRune(word, '$') { + return word + } + var buf bytes.Buffer + var w int + var r rune + for i := 0; i < len(word); i += w { + r, w = utf8.DecodeRuneInString(word[i:]) + if r != '$' { + buf.WriteRune(r) + continue + } + w += g.identLength(word[i+w:]) + envVar := word[i+1 : i+w] + var sub string + switch envVar { + case "GOARCH": + sub = runtime.GOARCH + case "GOOS": + sub = runtime.GOOS + case "GOFILE": + sub = g.file + case "GOPACKAGE": + sub = g.pkg + default: + sub = os.Getenv(envVar) + } + buf.WriteString(sub) + } + return buf.String() +} + +// identLength returns the length of the identifier beginning the string. +func (g *Generator) identLength(word string) int { + for i, r := range word { + if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) { + continue + } + return i + } + return len(word) +} + +// setShorthand installs a new shorthand as defined by a -command directive. +func (g *Generator) setShorthand(words []string) { + // Create command shorthand. + if len(words) == 1 { + g.errorf("no command specified for -command") + } + command := words[1] + if g.commands[command] != nil { + g.errorf("command %q defined multiply defined", command) + } + g.commands[command] = words[2:len(words):len(words)] // force later append to make copy +} + +// exec runs the command specified by the argument. The first word is +// the command name itself. +func (g *Generator) exec(words []string) { + cmd := exec.Command(words[0], words[1:]...) + // Standard in and out of generator should be the usual. + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + // Run the command in the package directory. + cmd.Dir = g.dir + env := []string{ + "GOARCH=" + runtime.GOARCH, + "GOOS=" + runtime.GOOS, + "GOFILE=" + g.file, + "GOPACKAGE=" + g.pkg, + } + cmd.Env = mergeEnvLists(env, os.Environ()) + err := cmd.Run() + if err != nil { + g.errorf("running %q: %s", words[0], err) + } +} diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go new file mode 100644 index 000000000..660ebabbe --- /dev/null +++ b/src/cmd/go/generate_test.go @@ -0,0 +1,48 @@ +// Copyright 2011 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. + +package main + +import ( + "reflect" + "runtime" + "testing" +) + +type splitTest struct { + in string + out []string +} + +var splitTests = []splitTest{ + {"", nil}, + {"x", []string{"x"}}, + {" a b\tc ", []string{"a", "b", "c"}}, + {` " a " `, []string{" a "}}, + {"$GOARCH", []string{runtime.GOARCH}}, + {"$GOOS", []string{runtime.GOOS}}, + {"$GOFILE", []string{"proc.go"}}, + {"$GOPACKAGE", []string{"sys"}}, + {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}}, + {"/$XXNOTDEFINED/", []string{"//"}}, + {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}}, +} + +func TestGenerateCommandParse(t *testing.T) { + g := &Generator{ + r: nil, // Unused here. + path: "/usr/ken/sys/proc.go", + dir: "/usr/ken/sys", + file: "proc.go", + pkg: "sys", + commands: make(map[string][]string), + } + g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) + for _, test := range splitTests { + got := g.split("//go:generate " + test.in + "\n") + if !reflect.DeepEqual(got, test.out) { + t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) + } + } +} diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index e708fcf77..86e169761 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -16,7 +16,7 @@ import ( ) var cmdGet = &Command{ - UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]", + UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` Get downloads and installs the packages named by the import paths, @@ -25,6 +25,11 @@ along with their dependencies. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. @@ -53,6 +58,7 @@ See also: go build, go install, go clean. } var getD = cmdGet.Flag.Bool("d", false, "") +var getF = cmdGet.Flag.Bool("f", false, "") var getT = cmdGet.Flag.Bool("t", false, "") var getU = cmdGet.Flag.Bool("u", false, "") var getFix = cmdGet.Flag.Bool("fix", false, "") @@ -63,6 +69,10 @@ func init() { } func runGet(cmd *Command, args []string) { + if *getF && !*getU { + fatalf("go get: cannot use -f flag without -u") + } + // Phase 1. Download/update. var stk importStack for _, arg := range downloadPaths(args) { @@ -151,7 +161,9 @@ func download(arg string, stk *importStack, getTestDeps bool) { } // Only process each package once. - if downloadCache[arg] { + // (Unless we're fetching test dependencies for this package, + // in which case we want to process it again.) + if downloadCache[arg] && !getTestDeps { return } downloadCache[arg] = true @@ -264,6 +276,25 @@ func downloadPackage(p *Package) error { return err } repo = "" // should be unused; make distinctive + + // Double-check where it came from. + if *getU && vcs.remoteRepo != nil && !*getF { + dir := filepath.Join(p.build.SrcRoot, rootPath) + if remote, err := vcs.remoteRepo(vcs, dir); err == nil { + if rr, err := repoRootForImportPath(p.ImportPath); err == nil { + repo := rr.repo + if rr.vcs.resolveRepo != nil { + resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) + if err == nil { + repo = resolved + } + } + if remote != repo { + return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo) + } + } + } + } } else { // Analyze the import path to determine the version control system, // repository, and the import path for the root of the repository. diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go new file mode 100644 index 000000000..53d695ccc --- /dev/null +++ b/src/cmd/go/go_windows_test.go @@ -0,0 +1,55 @@ +// Copyright 2014 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. + +package main + +import ( + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +func TestAbsolutePath(t *testing.T) { + tmp, err := ioutil.TempDir("", "TestAbsolutePath") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + + file := filepath.Join(tmp, "a.go") + err = ioutil.WriteFile(file, []byte{}, 0644) + if err != nil { + t.Fatal(err) + } + dir := filepath.Join(tmp, "dir") + err = os.Mkdir(dir, 0777) + if err != nil { + t.Fatal(err) + } + + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(wd) + + // Chdir so current directory and a.go reside on the same drive. + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + noVolume := file[len(filepath.VolumeName(file)):] + wrongPath := filepath.Join(dir, noVolume) + output, err := exec.Command("go", "build", noVolume).CombinedOutput() + if err == nil { + t.Fatal("build should fail") + } + if strings.Contains(string(output), wrongPath) { + t.Fatalf("wrong output found: %v %v", err, string(output)) + } +} diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index 40da7e1f5..c590fdb37 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -81,7 +81,8 @@ single directory, the command is applied to a single synthesized package made up of exactly those files, ignoring any build constraints in those files and ignoring any other files in the directory. -File names that begin with "." or "_" are ignored by the go tool. +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". `, } @@ -154,6 +155,11 @@ A few common code hosting sites have special syntax: import "launchpad.net/~user/project/branch" import "launchpad.net/~user/project/branch/sub/directory" + IBM DevOps Services (Git) + + import "hub.jazz.net/git/user/project" + import "hub.jazz.net/git/user/project/sub/directory" + For code hosted on other servers, import paths may either be qualified with the version control type, or the go tool can dynamically fetch the import path over https/http and discover where the code resides @@ -229,7 +235,26 @@ listed in the GOPATH environment variable (see 'go help gopath'). The go command attempts to download the version of the package appropriate for the Go release being used. -Run 'go help install' for more. +Run 'go help get' for more. + +Import path checking + +When the custom import path feature described above redirects to a +known code hosting site, each of the resulting packages has two possible +import paths, using the custom domain or the known hosting site. + +A package statement is said to have an "import comment" if it is immediately +followed (before the next newline) by a comment of one of these two forms: + + package math // import "path" + package math /* import "path" */ + +The go command will refuse to install a package with an import comment +unless it is being referred to by that import path. In this way, import comments +let package authors make sure the custom import path is used and not a +direct path to the underlying code hosting site. + +See https://golang.org/s/go14customimport for details. `, } diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go index 0ead43502..fbf96167f 100644 --- a/src/cmd/go/list.go +++ b/src/cmd/go/list.go @@ -30,28 +30,29 @@ syntax of package template. The default output is equivalent to -f '{{.ImportPath}}'. The struct being passed to the template is: type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - Name string // package name - Doc string // package documentation string - Target string // install path - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - Root string // Go root or Go path dir containing this package + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + Root string // Go root or Go path dir containing this package // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go sources files that import "C" IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive // Cgo directives CgoCFLAGS []string // cgo: flags for C compiler diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 5b1194aaa..9691f39c7 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -79,6 +79,7 @@ var commands = []*Command{ cmdEnv, cmdFix, cmdFmt, + cmdGenerate, cmdGet, cmdInstall, cmdList, @@ -536,7 +537,7 @@ func matchPackages(pattern string) []string { }) for _, src := range buildContext.SrcDirs() { - if pattern == "std" && src != gorootSrcPkg { + if pattern == "std" && src != gorootSrc { continue } src = filepath.Clean(src) + string(filepath.Separator) @@ -618,7 +619,7 @@ func matchPackagesInFS(pattern string) []string { // The initial case is not Cleaned, though, so we do this explicitly. // // This converts a path like "./io/" to "io". Without this step, running - // "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io + // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io // package, because prepending the prefix "./" to the unclean path would // result in "././io", and match("././io") returns false. path = filepath.Clean(path) diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh index 12fd7ba3e..e15e8809c 100755 --- a/src/cmd/go/mkdoc.sh +++ b/src/cmd/go/mkdoc.sh @@ -4,6 +4,6 @@ # license that can be found in the LICENSE file. go install # So the next line will produce updated documentation. -go help documentation > doc.go +go help documentation | sed 's; \*/; * /;' >doc.go gofmt -w doc.go diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index d45df265b..b71feb7a6 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -14,6 +14,7 @@ import ( "os" pathpkg "path" "path/filepath" + "runtime" "sort" "strings" "time" @@ -25,16 +26,17 @@ type Package struct { // Note: These fields are part of the go command's public API. // See list.go. It is okay to add fields, but not to change or // remove existing ones. Keep in sync with list.go - Dir string `json:",omitempty"` // directory containing package sources - ImportPath string `json:",omitempty"` // import path of package in dir - Name string `json:",omitempty"` // package name - Doc string `json:",omitempty"` // package documentation string - Target string `json:",omitempty"` // install path - Goroot bool `json:",omitempty"` // is this package found in the Go root? - Standard bool `json:",omitempty"` // is this package part of the standard Go library? - Stale bool `json:",omitempty"` // would 'go install' do anything for this package? - Root string `json:",omitempty"` // Go root or Go path dir containing this package - ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory + Dir string `json:",omitempty"` // directory containing package sources + ImportPath string `json:",omitempty"` // import path of package in dir + ImportComment string `json:",omitempty"` // path in import comment on package statement + Name string `json:",omitempty"` // package name + Doc string `json:",omitempty"` // package documentation string + Target string `json:",omitempty"` // install path + Goroot bool `json:",omitempty"` // is this package found in the Go root? + Standard bool `json:",omitempty"` // is this package part of the standard Go library? + Stale bool `json:",omitempty"` // would 'go install' do anything for this package? + Root string `json:",omitempty"` // Go root or Go path dir containing this package + ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory // Source files GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -103,6 +105,7 @@ func (p *Package) copyBuild(pp *build.Package) { p.Dir = pp.Dir p.ImportPath = pp.ImportPath + p.ImportComment = pp.ImportComment p.Name = pp.Name p.Doc = pp.Doc p.Root = pp.Root @@ -218,7 +221,7 @@ func dirToImportPath(dir string) string { } func makeImportValid(r rune) rune { - // Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport. + // Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport. const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { return '_' @@ -244,6 +247,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. importPath = dirToImportPath(filepath.Join(srcDir, path)) } if p := packageCache[importPath]; p != nil { + if perr := disallowInternal(srcDir, p, stk); perr != p { + return perr + } return reusePackage(p, stk) } @@ -258,11 +264,14 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. // // TODO: After Go 1, decide when to pass build.AllowBinary here. // See issue 3268 for mistakes to avoid. - bp, err := buildContext.Import(path, srcDir, 0) + bp, err := buildContext.Import(path, srcDir, build.ImportComment) bp.ImportPath = importPath if gobin != "" { bp.BinDir = gobin } + if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path { + err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) + } p.load(stk, bp, err) if p.Error != nil && len(importPos) > 0 { pos := importPos[0] @@ -270,6 +279,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. p.Error.Pos = pos.String() } + if perr := disallowInternal(srcDir, p, stk); perr != p { + return perr + } + return p } @@ -298,12 +311,82 @@ func reusePackage(p *Package, stk *importStack) *Package { return p } +// disallowInternal checks that srcDir is allowed to import p. +// If the import is allowed, disallowInternal returns the original package p. +// If not, it returns a new package containing just an appropriate error. +func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { + // golang.org/s/go14internal: + // An import of a path containing the element “internal” + // is disallowed if the importing code is outside the tree + // rooted at the parent of the “internal” directory. + // + // ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH. + + // Only applies to $GOROOT. + if !p.Standard { + return p + } + + // The stack includes p.ImportPath. + // If that's the only thing on the stack, we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if len(*stk) == 1 { + return p + } + + // Check for "internal" element: four cases depending on begin of string and/or end of string. + i, ok := findInternal(p.ImportPath) + if !ok { + return p + } + + // Internal is present. + // Map import path back to directory corresponding to parent of internal. + if i > 0 { + i-- // rewind over slash in ".../internal" + } + parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)] + if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) { + return p + } + + // Internal is present, and srcDir is outside parent's tree. Not allowed. + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.copy(), + Err: "use of internal package not allowed", + } + perr.Incomplete = true + return &perr +} + +// findInternal looks for the final "internal" path element in the given import path. +// If there isn't one, findInternal returns ok=false. +// Otherwise, findInternal returns ok=true and the index of the "internal". +func findInternal(path string) (index int, ok bool) { + // Four cases, depending on internal at start/end of string or not. + // The order matters: we must return the index of the final element, + // because the final one produces the most restrictive requirement + // on the importer. + switch { + case strings.HasSuffix(path, "/internal"): + return len(path) - len("internal"), true + case strings.Contains(path, "/internal/"): + return strings.LastIndex(path, "/internal/") + 1, true + case path == "internal", strings.HasPrefix(path, "internal/"): + return 0, true + } + return 0, false +} + type targetDir int const ( - toRoot targetDir = iota // to bin dir inside package root (default) - toTool // GOROOT/pkg/tool - toBin // GOROOT/bin + toRoot targetDir = iota // to bin dir inside package root (default) + toTool // GOROOT/pkg/tool + toBin // GOROOT/bin + stalePath // the old import path; fail to build ) // goTools is a map of Go program import path to install target directory. @@ -316,10 +399,14 @@ var goTools = map[string]targetDir{ "cmd/nm": toTool, "cmd/objdump": toTool, "cmd/pack": toTool, + "cmd/pprof": toTool, "cmd/yacc": toTool, - "code.google.com/p/go.tools/cmd/cover": toTool, - "code.google.com/p/go.tools/cmd/godoc": toBin, - "code.google.com/p/go.tools/cmd/vet": toTool, + "golang.org/x/tools/cmd/cover": toTool, + "golang.org/x/tools/cmd/godoc": toBin, + "golang.org/x/tools/cmd/vet": toTool, + "code.google.com/p/go.tools/cmd/cover": stalePath, + "code.google.com/p/go.tools/cmd/godoc": stalePath, + "code.google.com/p/go.tools/cmd/vet": stalePath, } // expandScanner expands a scanner.List error into all the errors in the list. @@ -380,6 +467,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } if p.Name == "main" { + // Report an error when the old code.google.com/p/go.tools paths are used. + if goTools[p.ImportPath] == stalePath { + newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) + e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath) + p.Error = &PackageError{Err: e} + return p + } _, elem := filepath.Split(p.Dir) full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH { @@ -482,7 +576,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) - deps := make(map[string]bool) + deps := make(map[string]*Package) for i, path := range importPaths { if path == "C" { continue @@ -502,10 +596,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package path = p1.ImportPath importPaths[i] = path } - deps[path] = true + deps[path] = p1 imports = append(imports, p1) - for _, dep := range p1.Deps { - deps[dep] = true + for _, dep := range p1.deps { + deps[dep.ImportPath] = dep } if p1.Incomplete { p.Incomplete = true @@ -519,7 +613,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } sort.Strings(p.Deps) for _, dep := range p.Deps { - p1 := packageCache[dep] + p1 := deps[dep] if p1 == nil { panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) } @@ -535,6 +629,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } p.Target = p.target + // Check for C code compiled with Plan 9 C compiler. + // No longer allowed except in runtime and runtime/cgo, for now. + if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") { + p.Error = &PackageError{ + ImportStack: stk.copy(), + Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")), + } + return p + } + // In the absence of errors lower in the dependency tree, // check for case-insensitive collisions of import paths. if len(p.DepsErrors) == 0 { @@ -596,6 +700,12 @@ func computeStale(pkgs ...*Package) { } } +// The runtime version string takes one of two forms: +// "go1.X[.Y]" for Go releases, and "devel +hash" at tip. +// Determine whether we are in a released copy by +// inspecting the version. +var isGoRelease = strings.HasPrefix(runtime.Version(), "go1") + // isStale reports whether package p needs to be rebuilt. func isStale(p *Package, topRoot map[string]bool) bool { if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { @@ -616,7 +726,16 @@ func isStale(p *Package, topRoot map[string]bool) bool { return false } - if buildA || p.target == "" || p.Stale { + // If we are running a release copy of Go, do not rebuild the standard packages. + // They may not be writable anyway, but they are certainly not changing. + // This makes 'go build -a' skip the standard packages when using an official release. + // See issue 4106 and issue 8290. + pkgBuildA := buildA + if p.Standard && isGoRelease { + pkgBuildA = false + } + + if pkgBuildA || p.target == "" || p.Stale { return true } @@ -704,24 +823,13 @@ func loadPackage(arg string, stk *importStack) *Package { arg = sub } } - if strings.HasPrefix(arg, "cmd/") { + if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") { if p := cmdCache[arg]; p != nil { return p } stk.push(arg) defer stk.pop() - if strings.Contains(arg[4:], "/") { - p := &Package{ - Error: &PackageError{ - ImportStack: stk.copy(), - Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"), - hard: true, - }, - } - return p - } - bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0) bp.ImportPath = arg bp.Goroot = true diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 0060ce218..e0f066f18 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -4,18 +4,22 @@ # license that can be found in the LICENSE file. set -e -go build -o testgo +go build -tags testgo -o testgo go() { echo TEST ERROR: ran go, not testgo: go "$@" >&2 exit 2 } started=false +testdesc="" +nl=" +" TEST() { if $started; then stop fi echo TEST: "$@" + testdesc="$@" started=true ok=true } @@ -29,6 +33,7 @@ stop() { echo PASS else echo FAIL + testfail="$testfail $testdesc$nl" allok=false fi } @@ -55,12 +60,63 @@ if ! grep -q "^$fn:" $d/err.out; then fi rm -r $d +TEST 'program name in crash messages' +linker=$(./testgo env GOCHAR)l +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +./testgo build -ldflags -crash_for_testing $(./testgo env GOROOT)/test/helloworld.go 2>$d/err.out || true +if ! grep -q "/tool/.*/$linker" $d/err.out; then + echo "missing linker name in error message" + cat $d/err.out + ok=false +fi +rm -r $d + +TEST broken tests without Test functions all fail +d=$(mktemp -d -t testgoXXX) +./testgo test ./testdata/src/badtest/... >$d/err 2>&1 || true +if grep -q '^ok' $d/err; then + echo test passed unexpectedly: + grep '^ok' $d/err + ok=false +elif ! grep -q 'FAIL.*badtest/badexec' $d/err || ! grep -q 'FAIL.*badtest/badsyntax' $d/err || ! grep -q 'FAIL.*badtest/badvar' $d/err; then + echo test did not run everything + cat $d/err + ok=false +fi +rm -rf $d + +TEST 'go build -a in dev branch' +./testgo install math || ok=false # should be up to date already but just in case +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then + cat $d/err.out + ok=false +elif ! grep -q runtime $d/err.out; then + echo "testgo build -a math in dev branch DID NOT build runtime, but should have" + cat $d/err.out + ok=false +fi +rm -r $d + +TEST 'go build -a in release branch' +./testgo install math || ok=false # should be up to date already but just in case +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then + cat $d/err.out + ok=false +elif grep -q runtime $d/err.out; then + echo "testgo build -a math in dev branch DID build runtime, but should NOT have" + cat $d/err.out + ok=false +fi +rm -r $d + # Test local (./) imports. testlocal() { local="$1" TEST local imports $2 '(easy)' - ./testgo build -o hello "testdata/$local/easy.go" - ./hello >hello.out + ./testgo build -o hello "testdata/$local/easy.go" || ok=false + ./hello >hello.out || ok=false if ! grep -q '^easysub\.Hello' hello.out; then echo "testdata/$local/easy.go did not generate expected output" cat hello.out @@ -68,8 +124,8 @@ testlocal() { fi TEST local imports $2 '(easysub)' - ./testgo build -o hello "testdata/$local/easysub/main.go" - ./hello >hello.out + ./testgo build -o hello "testdata/$local/easysub/main.go" || ok=false + ./hello >hello.out || ok=false if ! grep -q '^easysub\.Hello' hello.out; then echo "testdata/$local/easysub/main.go did not generate expected output" cat hello.out @@ -77,8 +133,8 @@ testlocal() { fi TEST local imports $2 '(hard)' - ./testgo build -o hello "testdata/$local/hard.go" - ./hello >hello.out + ./testgo build -o hello "testdata/$local/hard.go" || ok=false + ./hello >hello.out || ok=false if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then echo "testdata/$local/hard.go did not generate expected output" cat hello.out @@ -105,6 +161,132 @@ cp -R testdata/local "testdata/$bad" testlocal "$bad" 'with bad characters in path' rm -rf "testdata/$bad" +TEST 'internal packages in $GOROOT are respected' +if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then + echo "go build ./testdata/testinternal succeeded incorrectly" + ok=false +elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then + echo "wrong error message for testdata/testinternal" + cat std.out + ok=false +fi + +TEST 'internal packages outside $GOROOT are not respected' +if ! ./testgo build -v ./testdata/testinternal2; then + echo "go build ./testdata/testinternal2 failed" + ok=false +fi + +# Test that 'go get -u' reports moved packages. +testmove() { + vcs=$1 + url=$2 + base=$3 + config=$4 + + TEST go get -u notices $vcs package that moved + d=$(mktemp -d -t testgoXXX) + mkdir -p $d/src + if ! GOPATH=$d ./testgo get -d $url; then + echo 'go get -d $url failed' + ok=false + elif ! GOPATH=$d ./testgo get -d -u $url; then + echo 'go get -d -u $url failed' + ok=false + else + set +e + case "$vcs" in + svn) + # SVN doesn't believe in text files so we can't just edit the config. + # Check out a different repo into the wrong place. + rm -rf $d/src/code.google.com/p/rsc-svn + GOPATH=$d ./testgo get -d -u code.google.com/p/rsc-svn2/trunk + mv $d/src/code.google.com/p/rsc-svn2 $d/src/code.google.com/p/rsc-svn + ;; + *) + echo '1,$s;'"$base"';'"$base"'XXX; +w +q' | ed $d/src/$config >/dev/null 2>&1 + esac + set -e + + if GOPATH=$d ./testgo get -d -u $url 2>$d/err; then + echo "go get -d -u $url succeeded with wrong remote repo" + cat $d/err + ok=false + elif ! grep 'should be from' $d/err >/dev/null; then + echo "go get -d -u $url failed for wrong reason" + cat $d/err + ok=false + fi + + if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then + echo "go get -d -u $url succeeded with wrong remote repo" + cat $d/err + ok=false + elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then + echo "go get -d -f -u $url failed for wrong reason" + cat $d/err + ok=false + fi + fi + rm -rf $d +} + +testmove hg rsc.io/x86/x86asm x86 rsc.io/x86/.hg/hgrc +testmove git rsc.io/pdf pdf rsc.io/pdf/.git/config +testmove svn code.google.com/p/rsc-svn/trunk - - + +export GOPATH=$(pwd)/testdata/importcom +TEST 'import comment - match' +if ! ./testgo build ./testdata/importcom/works.go; then + echo 'go build ./testdata/importcom/works.go failed' + ok=false +fi +TEST 'import comment - mismatch' +if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then + echo 'go build ./testdata/importcom/wrongplace.go suceeded' + ok=false +elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then + echo 'go build did not mention incorrect import:' + cat testdata/err + ok=false +fi +TEST 'import comment - syntax error' +if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then + echo 'go build ./testdata/importcom/bad.go suceeded' + ok=false +elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then + echo 'go build did not mention syntax error:' + cat testdata/err + ok=false +fi +TEST 'import comment - conflict' +if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then + echo 'go build ./testdata/importcom/conflict.go suceeded' + ok=false +elif ! grep 'found import comments' testdata/err >/dev/null; then + echo 'go build did not mention comment conflict:' + cat testdata/err + ok=false +fi +rm -f ./testdata/err +unset GOPATH + +export GOPATH=$(pwd)/testdata/src +TEST disallowed C source files +export GOPATH=$(pwd)/testdata +if ./testgo build badc 2>testdata/err; then + echo 'go build badc succeeded' + ok=false +elif ! grep 'C source files not allowed' testdata/err >/dev/null; then + echo 'go test did not say C source files not allowed:' + cat testdata/err + ok=false +fi +rm -f ./testdata/err +unset GOPATH + TEST error message for syntax error in test go file says FAIL export GOPATH=$(pwd)/testdata if ./testgo test syntaxerror 2>testdata/err; then @@ -251,20 +433,20 @@ TEST godoc installs into GOBIN d=$(mktemp -d -t testgoXXX) export GOPATH=$d mkdir $d/gobin -GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc +GOBIN=$d/gobin ./testgo get golang.org/x/tools/cmd/godoc || ok=false if [ ! -x $d/gobin/godoc ]; then echo did not install godoc to '$GOBIN' - GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc + GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true ok=false fi TEST godoc installs into GOROOT GOROOT=$(./testgo env GOROOT) rm -f $GOROOT/bin/godoc -./testgo install code.google.com/p/go.tools/cmd/godoc +./testgo install golang.org/x/tools/cmd/godoc || ok=false if [ ! -x $GOROOT/bin/godoc ]; then echo did not install godoc to '$GOROOT/bin' - ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc + ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true ok=false fi @@ -272,36 +454,36 @@ TEST cmd/fix installs into tool GOOS=$(./testgo env GOOS) GOARCH=$(./testgo env GOARCH) rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix -./testgo install cmd/fix +./testgo install cmd/fix || ok=false if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then echo 'did not install cmd/fix to $GOROOT/pkg/tool' - GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix + GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true ok=false fi rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix -GOBIN=$d/gobin ./testgo install cmd/fix +GOBIN=$d/gobin ./testgo install cmd/fix || ok=false if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set' - GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix + GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true ok=false fi TEST gopath program installs into GOBIN mkdir $d/src/progname echo 'package main; func main() {}' >$d/src/progname/p.go -GOBIN=$d/gobin ./testgo install progname +GOBIN=$d/gobin ./testgo install progname || ok=false if [ ! -x $d/gobin/progname ]; then echo 'did not install progname to $GOBIN/progname' - ./testgo list -f 'Target: {{.Target}}' cmd/api + ./testgo list -f 'Target: {{.Target}}' cmd/api || true ok=false fi rm -f $d/gobin/progname $d/bin/progname TEST gopath program installs into GOPATH/bin -./testgo install progname +./testgo install progname || ok=false if [ ! -x $d/bin/progname ]; then echo 'did not install progname to $GOPATH/bin/progname' - ./testgo list -f 'Target: {{.Target}}' progname + ./testgo list -f 'Target: {{.Target}}' progname || true ok=false fi @@ -330,7 +512,7 @@ fi # ensure that output of 'go list' is consistent between runs TEST go list is consistent -./testgo list std > test_std.list +./testgo list std > test_std.list || ok=false if ! ./testgo list std | cmp -s test_std.list - ; then echo "go list std ordering is inconsistent" ok=false @@ -378,9 +560,9 @@ fi # Test that without GOPATH set, go get should fail TEST without GOPATH, go get fails d=$(mktemp -d -t testgoXXX) -mkdir -p $d/src/pkg -if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then - echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset' +mkdir -p $d/src +if GOPATH= GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then + echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with $GOPATH unset' ok=false fi rm -rf $d @@ -388,9 +570,9 @@ rm -rf $d # Test that with GOPATH=$GOROOT, go get should fail TEST with GOPATH=GOROOT, go get fails d=$(mktemp -d -t testgoXXX) -mkdir -p $d/src/pkg -if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then - echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT' +mkdir -p $d/src +if GOPATH=$d GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then + echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT' ok=false fi rm -rf $d @@ -404,7 +586,7 @@ func main() { println(extern) } EOF -./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out +./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out || ok=false if ! grep -q '^hello world' hello.out; then echo "ldflags -X main.extern 'hello world' failed. Output:" cat hello.out @@ -420,6 +602,30 @@ if [ ! -x strings.test ]; then fi rm -f strings.prof strings.test +TEST go test -cpuprofile -o controls binary location +./testgo test -cpuprofile strings.prof -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -cpuprofile -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f strings.prof mystrings.test + +TEST go test -c -o controls binary location +./testgo test -c -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -c -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f mystrings.test + +TEST go test -o writes binary +./testgo test -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f mystrings.test + TEST symlinks do not confuse go list '(issue 4568)' old=$(pwd) tmp=$(cd /tmp && pwd -P) @@ -522,37 +728,56 @@ elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then fi TEST go get cover -./testgo get code.google.com/p/go.tools/cmd/cover || ok=false +./testgo get golang.org/x/tools/cmd/cover || ok=false unset GOPATH rm -rf $d +TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}" +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +export GOPATH=$d +if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then + ./testgo list ... | grep go.tools/godoc > /dev/null || ok=false +else + ok=false +fi +unset GOPATH +rm -rf $d + TEST shadowing logic export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2 # The math in root1 is not "math" because the standard math is. +set +e cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math) -if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/pkg/math)" ]; then +set -e +if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/math)" ]; then echo shadowed math is not shadowed: "$cdir" ok=false fi # The foo in root1 is "foo". +set +e cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo) +set -e if [ "$cdir" != "(foo) ()" ]; then echo unshadowed foo is shadowed: "$cdir" ok=false fi # The foo in root2 is not "foo" because the foo in root1 got there first. +set +e cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo) +set -e if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then echo shadowed foo is not shadowed: "$cdir" ok=false fi # The error for go install should mention the conflicting directory. -err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1) +set +e +err=$(./testgo install ./testdata/shadow/root2/src/foo 2>&1) +set -e if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then echo wrong shadowed install error: "$err" ok=false @@ -741,30 +966,46 @@ echo ' package foo func F() {} ' >$d/src/x/y/foo/foo.go +checkbar() { + desc="$1" + sleep 1 + touch $d/src/x/y/foo/foo.go + if ! ./testgo build -v -i x/y/bar &> $d/err; then + echo build -i "$1" failed + cat $d/err + ok=false + elif ! grep x/y/foo $d/err >/dev/null; then + echo first build -i "$1" did not build x/y/foo + cat $d/err + ok=false + fi + if ! ./testgo build -v -i x/y/bar &> $d/err; then + echo second build -i "$1" failed + cat $d/err + ok=false + elif grep x/y/foo $d/err >/dev/null; then + echo second build -i "$1" built x/y/foo + cat $d/err + ok=false + fi +} + echo ' package bar import "x/y/foo" func F() { foo.F() } ' >$d/src/x/y/bar/bar.go -if ! ./testgo build -v -i x/y/bar &> $d/err; then - echo build -i failed - cat $d/err - ok=false -elif ! grep x/y/foo $d/err >/dev/null; then - echo first build -i did not build x/y/foo - cat $d/err - ok=false -fi -if ! ./testgo build -v -i x/y/bar &> $d/err; then - echo second build -i failed - cat $d/err - ok=false -elif grep x/y/foo $d/err >/dev/null; then - echo second build -i built x/y/foo - cat $d/err - ok=false -fi -rm -rf $d +checkbar pkg + +TEST build -i installs dependencies for command +echo ' +package main +import "x/y/foo" +func main() { foo.F() } +' >$d/src/x/y/bar/bar.go +checkbar cmd + +rm -rf $d bar unset GOPATH TEST 'go build in test-only directory fails with a good error' @@ -799,13 +1040,74 @@ fi TEST 'go test xtestonly works' export GOPATH=$(pwd)/testdata -./testgo clean -i xtestonly +./testgo clean -i xtestonly || ok=false if ! ./testgo test xtestonly >/dev/null; then echo "go test xtestonly failed" ok=false fi unset GOPATH +TEST 'go test builds an xtest containing only non-runnable examples' +if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then + echo "go test ./testdata/norunexample failed" + ok=false +elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then + echo "file with non-runnable example was not built" + ok=false +fi + +TEST 'go generate handles simple command' +if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then + echo "go test ./testdata/generate/test1.go failed to run" + ok=false +elif ! grep 'Success' testdata/std.out > /dev/null; then + echo "go test ./testdata/generate/test1.go generated wrong output" + ok=false +fi + +TEST 'go generate handles command alias' +if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then + echo "go test ./testdata/generate/test2.go failed to run" + ok=false +elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then + echo "go test ./testdata/generate/test2.go generated wrong output" + ok=false +fi + +TEST 'go generate variable substitution' +if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then + echo "go test ./testdata/generate/test3.go failed to run" + ok=false +elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; then + echo "go test ./testdata/generate/test3.go generated wrong output" + ok=false +fi + +TEST go get works with vanity wildcards +d=$(mktemp -d -t testgoXXX) +export GOPATH=$d +if ! ./testgo get -u rsc.io/pdf/...; then + ok=false +elif [ ! -x $d/bin/pdfpasswd ]; then + echo did not build rsc.io/pdf/pdfpasswd + ok=false +fi +unset GOPATH +rm -rf $d + +TEST go vet with external tests +d=$(mktemp -d -t testgoXXX) +export GOPATH=$(pwd)/testdata +if ./testgo vet vetpkg >$d/err 2>&1; then + echo "go vet vetpkg passes incorrectly" + ok=false +elif ! grep -q 'missing argument for Printf' $d/err; then + echo "go vet vetpkg did not find missing argument for Printf" + cat $d/err + ok=false +fi +unset GOPATH +rm -rf $d # clean up if $started; then stop; fi @@ -815,6 +1117,7 @@ rm -f testgo if $allok; then echo PASS else - echo FAIL + echo FAIL: + echo "$testfail" exit 1 fi diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 5935c98db..c81e40639 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -6,6 +6,7 @@ package main import ( "bytes" + "errors" "fmt" "go/ast" "go/build" @@ -48,7 +49,7 @@ It prints a summary of the test results in the format: followed by detailed output for each failed package. 'Go test' recompiles each package along with any files with names matching -the file pattern "*_test.go". +the file pattern "*_test.go". Files whose names begin with "_" (including "_test.go") or "." are ignored. These additional files can contain test functions, benchmark functions, and example functions. See 'go help testfunc' for more. @@ -65,16 +66,23 @@ non-test installation. In addition to the build flags, the flags handled by 'go test' itself are: - -c Compile the test binary to pkg.test but do not run it. - (Where pkg is the last element of the package's import path.) + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. -i Install packages that are dependencies of the test. Do not run the test. - -exec xprog - Run the test binary using xprog. The behavior is the same as - in 'go run'. See 'go help run' for details. + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -122,6 +130,7 @@ control the execution of any test: -blockprofile block.out Write a goroutine blocking profile to the specified file when all tests are complete. + Writes test binary as -c would. -blockprofilerate n Control the detail provided in goroutine blocking profiles by @@ -153,8 +162,7 @@ control the execution of any test: Sets -cover. -coverprofile cover.out - Write a coverage profile to the specified file after all tests - have passed. + Write a coverage profile to the file after all tests have passed. Sets -cover. -cpu 1,2,4 @@ -164,10 +172,11 @@ control the execution of any test: -cpuprofile cpu.out Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. -memprofile mem.out - Write a memory profile to the specified file after all tests - have passed. + Write a memory profile to the file after all tests have passed. + Writes test binary as -c would. -memprofilerate n Enable more precise (and expensive) memory profiles by setting @@ -274,10 +283,10 @@ var ( testCoverMode string // -covermode flag testCoverPaths []string // -coverpkg flag testCoverPkgs []*Package // -coverpkg flag + testO string // -o flag testProfile bool // some profiling flag testNeedBinary bool // profile needs to keep binary around testV bool // -v flag - testFiles []string // -file flag(s) TODO: not respected testTimeout string // -timeout flag testArgs []string testBench bool @@ -291,6 +300,7 @@ var testMainDeps = map[string]bool{ // Dependencies for testmain. "testing": true, "regexp": true, + "os": true, } func runTest(cmd *Command, args []string) { @@ -308,6 +318,9 @@ func runTest(cmd *Command, args []string) { if testC && len(pkgs) != 1 { fatalf("cannot use -c flag with multiple packages") } + if testO != "" && len(pkgs) != 1 { + fatalf("cannot use -o flag with multiple packages") + } if testProfile && len(pkgs) != 1 { fatalf("cannot use test profile flag with multiple packages") } @@ -522,6 +535,13 @@ func contains(x []string, s string) bool { return false } +var windowsBadWords = []string{ + "install", + "patch", + "setup", + "update", +} + func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { build := b.action(modeBuild, modeBuild, p) @@ -687,7 +707,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, omitDWARF: !testC && !testNeedBinary, } - // The generated main also imports testing and regexp. + // The generated main also imports testing, regexp, and os. stk.push("testmain") for dep := range testMainDeps { if dep == ptest.ImportPath { @@ -723,11 +743,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if err != nil { return nil, nil, nil, err } - if t.NeedTest || ptest.coverMode != "" { + if len(ptest.GoFiles) > 0 { pmain.imports = append(pmain.imports, ptest) + t.ImportTest = true } - if t.NeedXtest { + if pxtest != nil { pmain.imports = append(pmain.imports, pxtest) + t.ImportXtest = true } if ptest != p && localCover { @@ -779,17 +801,54 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, a.objdir = testDir + string(filepath.Separator) a.objpkg = filepath.Join(testDir, "main.a") a.target = filepath.Join(testDir, testBinary) + exeSuffix - pmainAction := a + if goos == "windows" { + // There are many reserved words on Windows that, + // if used in the name of an executable, cause Windows + // to try to ask for extra permissions. + // The word list includes setup, install, update, and patch, + // but it does not appear to be defined anywhere. + // We have run into this trying to run the + // go.codereview/patch tests. + // For package names containing those words, use test.test.exe + // instead of pkgname.test.exe. + // Note that this file name is only used in the Go command's + // temporary directory. If the -c or other flags are + // given, the code below will still use pkgname.test.exe. + // There are two user-visible effects of this change. + // First, you can actually run 'go test' in directories that + // have names that Windows thinks are installer-like, + // without getting a dialog box asking for more permissions. + // Second, in the Windows process listing during go test, + // the test shows up as test.test.exe, not pkgname.test.exe. + // That second one is a drawback, but it seems a small + // price to pay for the test running at all. + // If maintaining the list of bad words is too onerous, + // we could just do this always on Windows. + for _, bad := range windowsBadWords { + if strings.Contains(testBinary, bad) { + a.target = filepath.Join(testDir, "test.test") + exeSuffix + break + } + } + } + buildAction = a if testC || testNeedBinary { // -c or profiling flag: create action to copy binary to ./test.out. - runAction = &action{ + target := filepath.Join(cwd, testBinary+exeSuffix) + if testO != "" { + target = testO + if !filepath.IsAbs(target) { + target = filepath.Join(cwd, target) + } + } + buildAction = &action{ f: (*builder).install, - deps: []*action{pmainAction}, + deps: []*action{buildAction}, p: pmain, - target: filepath.Join(cwd, testBinary+exeSuffix), + target: target, } - pmainAction = runAction // in case we are running the test + runAction = buildAction // make sure runAction != nil even if not running test } if testC { printAction = &action{p: p, deps: []*action{runAction}} // nop @@ -797,7 +856,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, // run test runAction = &action{ f: (*builder).runTest, - deps: []*action{pmainAction}, + deps: []*action{buildAction}, p: p, ignoreFail: true, } @@ -813,7 +872,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, } } - return pmainAction, runAction, printAction, nil + return buildAction, runAction, printAction, nil } func testImportStack(top string, p *Package, target string) []string { @@ -1057,6 +1116,31 @@ func (b *builder) notest(a *action) error { return nil } +// isTestMain tells whether fn is a TestMain(m *testing.M) function. +func isTestMain(fn *ast.FuncDecl) bool { + if fn.Name.String() != "TestMain" || + fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || + fn.Type.Params == nil || + len(fn.Type.Params.List) != 1 || + len(fn.Type.Params.List[0].Names) > 1 { + return false + } + ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr) + if !ok { + return false + } + // We can't easily check that the type is *testing.M + // because we don't know how testing has been imported, + // but at least check that it's *M or *something.M. + if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" { + return true + } + if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" { + return true + } + return false +} + // isTest tells whether name looks like a test (or benchmark, according to prefix). // It is a Test (say) if there is a character after Test that is not a lower-case letter. // We don't want TesticularCancer. @@ -1082,12 +1166,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) { Package: ptest, } for _, file := range ptest.TestGoFiles { - if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil { + if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil { return nil, err } } for _, file := range ptest.XTestGoFiles { - if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil { + if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil { return nil, err } } @@ -1110,13 +1194,16 @@ func writeTestmain(out string, t *testFuncs) error { } type testFuncs struct { - Tests []testFunc - Benchmarks []testFunc - Examples []testFunc - Package *Package - NeedTest bool - NeedXtest bool - Cover []coverInfo + Tests []testFunc + Benchmarks []testFunc + Examples []testFunc + TestMain *testFunc + Package *Package + ImportTest bool + NeedTest bool + ImportXtest bool + NeedXtest bool + Cover []coverInfo } func (t *testFuncs) CoverMode() string { @@ -1151,7 +1238,7 @@ type testFunc struct { var testFileSet = token.NewFileSet() -func (t *testFuncs) load(filename, pkg string, seen *bool) error { +func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments) if err != nil { return expandScanner(err) @@ -1166,17 +1253,24 @@ func (t *testFuncs) load(filename, pkg string, seen *bool) error { } name := n.Name.String() switch { + case isTestMain(n): + if t.TestMain != nil { + return errors.New("multiple definitions of TestMain") + } + t.TestMain = &testFunc{pkg, name, ""} + *doImport, *seen = true, true case isTest(name, "Test"): t.Tests = append(t.Tests, testFunc{pkg, name, ""}) - *seen = true + *doImport, *seen = true, true case isTest(name, "Benchmark"): t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""}) - *seen = true + *doImport, *seen = true, true } } ex := doc.Examples(f) sort.Sort(byOrder(ex)) for _, e := range ex { + *doImport = true // import test file whether executed or not if e.Output == "" && !e.EmptyOutput { // Don't run examples with no output. continue @@ -1197,14 +1291,17 @@ var testmainTmpl = template.Must(template.New("main").Parse(` package main import ( +{{if not .TestMain}} + "os" +{{end}} "regexp" "testing" -{{if .NeedTest}} - _test {{.Package.ImportPath | printf "%q"}} +{{if .ImportTest}} + {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} {{end}} -{{if .NeedXtest}} - _xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}} +{{if .ImportXtest}} + {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} {{end}} {{range $i, $p := .Cover}} _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} @@ -1291,7 +1388,12 @@ func main() { CoveredPackages: {{printf "%q" .Covered}}, }) {{end}} - testing.Main(matchString, tests, benchmarks, examples) + m := testing.MainStart(matchString, tests, benchmarks, examples) +{{with .TestMain}} + {{.Package}}.{{.Name}}(m) +{{else}} + os.Exit(m.Run()) +{{end}} } `)) diff --git a/src/cmd/go/testdata/generate/test1.go b/src/cmd/go/testdata/generate/test1.go new file mode 100644 index 000000000..1f05734f0 --- /dev/null +++ b/src/cmd/go/testdata/generate/test1.go @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +// Simple test for go generate. + +// We include a build tag that go generate should ignore. + +// +build ignore + +//go:generate echo Success + +package p diff --git a/src/cmd/go/testdata/generate/test2.go b/src/cmd/go/testdata/generate/test2.go new file mode 100644 index 000000000..ef1a3d951 --- /dev/null +++ b/src/cmd/go/testdata/generate/test2.go @@ -0,0 +1,10 @@ +// Copyright 2014 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. + +// Test that go generate handles command aliases. + +//go:generate -command run echo Now is the time +//go:generate run for all good men + +package p diff --git a/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go new file mode 100644 index 000000000..41ffb7ea8 --- /dev/null +++ b/src/cmd/go/testdata/generate/test3.go @@ -0,0 +1,9 @@ +// Copyright 2014 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. + +// Test go generate variable substitution. + +//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123 + +package p diff --git a/src/cmd/go/testdata/importcom/bad.go b/src/cmd/go/testdata/importcom/bad.go new file mode 100644 index 000000000..e104c2e99 --- /dev/null +++ b/src/cmd/go/testdata/importcom/bad.go @@ -0,0 +1,3 @@ +package p + +import "bad" diff --git a/src/cmd/go/testdata/importcom/conflict.go b/src/cmd/go/testdata/importcom/conflict.go new file mode 100644 index 000000000..995556c51 --- /dev/null +++ b/src/cmd/go/testdata/importcom/conflict.go @@ -0,0 +1,3 @@ +package p + +import "conflict" diff --git a/src/cmd/go/testdata/importcom/src/bad/bad.go b/src/cmd/go/testdata/importcom/src/bad/bad.go new file mode 100644 index 000000000..bc51fd3fd --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/bad/bad.go @@ -0,0 +1 @@ +package bad // import diff --git a/src/cmd/go/testdata/importcom/src/conflict/a.go b/src/cmd/go/testdata/importcom/src/conflict/a.go new file mode 100644 index 000000000..2d6770351 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/conflict/a.go @@ -0,0 +1 @@ +package conflict // import "a" diff --git a/src/cmd/go/testdata/importcom/src/conflict/b.go b/src/cmd/go/testdata/importcom/src/conflict/b.go new file mode 100644 index 000000000..8fcfb3c8b --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/conflict/b.go @@ -0,0 +1 @@ +package conflict /* import "b" */ diff --git a/src/cmd/go/testdata/importcom/src/works/x/x.go b/src/cmd/go/testdata/importcom/src/works/x/x.go new file mode 100644 index 000000000..044c6eca8 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/works/x/x.go @@ -0,0 +1 @@ +package x // import "works/x" diff --git a/src/cmd/go/testdata/importcom/src/works/x/x1.go b/src/cmd/go/testdata/importcom/src/works/x/x1.go new file mode 100644 index 000000000..2449b29df --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/works/x/x1.go @@ -0,0 +1 @@ +package x // important! not an import comment diff --git a/src/cmd/go/testdata/importcom/src/wrongplace/x.go b/src/cmd/go/testdata/importcom/src/wrongplace/x.go new file mode 100644 index 000000000..b89849da7 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/wrongplace/x.go @@ -0,0 +1 @@ +package x // import "my/x" diff --git a/src/cmd/go/testdata/importcom/works.go b/src/cmd/go/testdata/importcom/works.go new file mode 100644 index 000000000..31b55d08a --- /dev/null +++ b/src/cmd/go/testdata/importcom/works.go @@ -0,0 +1,3 @@ +package p + +import _ "works/x" diff --git a/src/cmd/go/testdata/importcom/wrongplace.go b/src/cmd/go/testdata/importcom/wrongplace.go new file mode 100644 index 000000000..e2535e01a --- /dev/null +++ b/src/cmd/go/testdata/importcom/wrongplace.go @@ -0,0 +1,3 @@ +package p + +import "wrongplace" diff --git a/src/cmd/go/testdata/norunexample/example_test.go b/src/cmd/go/testdata/norunexample/example_test.go new file mode 100644 index 000000000..e158305a6 --- /dev/null +++ b/src/cmd/go/testdata/norunexample/example_test.go @@ -0,0 +1,11 @@ +package pkg_test + +import "os" + +func init() { + os.Stdout.Write([]byte("File with non-runnable example was built.\n")) +} + +func Example_test() { + // This test will not be run, it has no "Output:" comment. +} diff --git a/src/cmd/go/testdata/norunexample/test_test.go b/src/cmd/go/testdata/norunexample/test_test.go new file mode 100644 index 000000000..d2e919838 --- /dev/null +++ b/src/cmd/go/testdata/norunexample/test_test.go @@ -0,0 +1,10 @@ +package pkg + +import ( + "os" + "testing" +) + +func TestBuilt(t *testing.T) { + os.Stdout.Write([]byte("A normal test was executed.\n")) +} diff --git a/src/cmd/go/testdata/src/badc/x.c b/src/cmd/go/testdata/src/badc/x.c new file mode 100644 index 000000000..f6cbf6924 --- /dev/null +++ b/src/cmd/go/testdata/src/badc/x.c @@ -0,0 +1 @@ +// C code! diff --git a/src/cmd/go/testdata/src/badc/x.go b/src/cmd/go/testdata/src/badc/x.go new file mode 100644 index 000000000..bfa1de28b --- /dev/null +++ b/src/cmd/go/testdata/src/badc/x.go @@ -0,0 +1 @@ +package badc diff --git a/src/cmd/go/testdata/src/badtest/badexec/x_test.go b/src/cmd/go/testdata/src/badtest/badexec/x_test.go new file mode 100644 index 000000000..12f505171 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badexec/x_test.go @@ -0,0 +1,5 @@ +package badexec + +func init() { + panic("badexec") +} diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x.go b/src/cmd/go/testdata/src/badtest/badsyntax/x.go new file mode 100644 index 000000000..c8a5407a5 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badsyntax/x.go @@ -0,0 +1 @@ +package badsyntax diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go b/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go new file mode 100644 index 000000000..5be10745d --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go @@ -0,0 +1,3 @@ +package badsyntax + +func func func func func! diff --git a/src/cmd/go/testdata/src/badtest/badvar/x.go b/src/cmd/go/testdata/src/badtest/badvar/x.go new file mode 100644 index 000000000..fdd46c4c7 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badvar/x.go @@ -0,0 +1 @@ +package badvar diff --git a/src/cmd/go/testdata/src/badtest/badvar/x_test.go b/src/cmd/go/testdata/src/badtest/badvar/x_test.go new file mode 100644 index 000000000..c67df01c5 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badvar/x_test.go @@ -0,0 +1,5 @@ +package badvar_test + +func f() { + _ = notdefined +} diff --git a/src/cmd/go/testdata/src/vetpkg/a_test.go b/src/cmd/go/testdata/src/vetpkg/a_test.go new file mode 100644 index 000000000..9b64e8e1a --- /dev/null +++ b/src/cmd/go/testdata/src/vetpkg/a_test.go @@ -0,0 +1 @@ +package p_test diff --git a/src/cmd/go/testdata/src/vetpkg/b.go b/src/cmd/go/testdata/src/vetpkg/b.go new file mode 100644 index 000000000..99e18f63d --- /dev/null +++ b/src/cmd/go/testdata/src/vetpkg/b.go @@ -0,0 +1,7 @@ +package p + +import "fmt" + +func f() { + fmt.Printf("%d") +} diff --git a/src/cmd/go/testdata/testinternal/p.go b/src/cmd/go/testdata/testinternal/p.go new file mode 100644 index 000000000..e3558a53b --- /dev/null +++ b/src/cmd/go/testdata/testinternal/p.go @@ -0,0 +1,3 @@ +package p + +import _ "net/http/internal" diff --git a/src/cmd/go/testdata/testinternal2/p.go b/src/cmd/go/testdata/testinternal2/p.go new file mode 100644 index 000000000..c594f5c5e --- /dev/null +++ b/src/cmd/go/testdata/testinternal2/p.go @@ -0,0 +1,3 @@ +package p + +import _ "./x/y/z/internal/w" diff --git a/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go new file mode 100644 index 000000000..a796c0b5f --- /dev/null +++ b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go @@ -0,0 +1 @@ +package w diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go index 73f311e5f..6da74b996 100644 --- a/src/cmd/go/testflag.go +++ b/src/cmd/go/testflag.go @@ -65,9 +65,9 @@ type testFlagSpec struct { var testFlagDefn = []*testFlagSpec{ // local. {name: "c", boolVar: &testC}, - {name: "file", multiOK: true}, {name: "cover", boolVar: &testCover}, {name: "coverpkg"}, + {name: "o"}, // build flags. {name: "a", boolVar: &buildA}, @@ -153,6 +153,9 @@ func testFlags(args []string) (packageNames, passToTest []string) { // bool flags. case "a", "c", "i", "n", "x", "v", "race", "cover", "work": setBoolFlag(f.boolVar, value) + case "o": + testO = value + testNeedBinary = true case "p": setIntFlag(&buildP, value) case "exec": @@ -184,8 +187,6 @@ func testFlags(args []string) (packageNames, passToTest []string) { buildContext.BuildTags = strings.Fields(value) case "compiler": buildCompiler{}.Set(value) - case "file": - testFiles = append(testFiles, value) case "bench": // record that we saw the flag; don't care about the value testBench = true diff --git a/src/cmd/go/testgo.go b/src/cmd/go/testgo.go new file mode 100644 index 000000000..01923f74b --- /dev/null +++ b/src/cmd/go/testgo.go @@ -0,0 +1,21 @@ +// Copyright 2014 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. + +// This file contains extra hooks for testing the go command. +// It is compiled into the Go binary only when building the +// test copy; it does not get compiled into the standard go +// command, so these testing hooks are not present in the +// go command that everyone uses. + +// +build testgo + +package main + +import "os" + +func init() { + if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" { + isGoRelease = v == "1" + } +} diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go index 6d26f7a4b..3f11c3e3d 100644 --- a/src/cmd/go/tool.go +++ b/src/cmd/go/tool.go @@ -47,13 +47,13 @@ const toolWindowsExtension = ".exe" func tool(toolName string) string { toolPath := filepath.Join(toolDir, toolName) - if toolIsWindows && toolName != "pprof" { + if toolIsWindows { toolPath += toolWindowsExtension } // Give a nice message if there is no tool with that name. if _, err := os.Stat(toolPath); err != nil { if isInGoToolsRepo(toolName) { - fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName) + fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName) } else { fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) } @@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) { if toolPath == "" { return } - if toolIsWindows && toolName == "pprof" { - args = append([]string{"perl", toolPath}, args[1:]...) - var err error - toolPath, err = exec.LookPath("perl") - if err != nil { - fmt.Fprintf(os.Stderr, "go tool: perl not found\n") - setExitStatus(3) - return - } - } if toolN { fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) return diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 8f0bae0b7..1cac61338 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -33,6 +33,9 @@ type vcsCmd struct { scheme []string pingCmd string + + remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) + resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) } // A tagCmd describes a command to list available tags @@ -81,8 +84,17 @@ var vcsHg = &vcsCmd{ tagSyncCmd: "update -r {tag}", tagSyncDefault: "update default", - scheme: []string{"https", "http", "ssh"}, - pingCmd: "identify {scheme}://{repo}", + scheme: []string{"https", "http", "ssh"}, + pingCmd: "identify {scheme}://{repo}", + remoteRepo: hgRemoteRepo, +} + +func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) { + out, err := vcsHg.runOutput(rootDir, "paths default") + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil } // vcsGit describes how to use Git. @@ -104,8 +116,38 @@ var vcsGit = &vcsCmd{ tagSyncCmd: "checkout {tag}", tagSyncDefault: "checkout master", - scheme: []string{"git", "https", "http", "git+ssh"}, - pingCmd: "ls-remote {scheme}://{repo}", + scheme: []string{"git", "https", "http", "git+ssh"}, + pingCmd: "ls-remote {scheme}://{repo}", + remoteRepo: gitRemoteRepo, +} + +func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsGit.runOutput(rootDir, "remote -v") + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // origin https://github.com/rsc/pdf (fetch) + // origin https://github.com/rsc/pdf (push) + // use first line only. + + if !strings.HasPrefix(out, "origin\t") { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = strings.TrimPrefix(out, "origin\t") + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = out[:i] + i = strings.LastIndex(out, " ") + if i < 0 { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } // vcsBzr describes how to use Bazaar. @@ -123,8 +165,51 @@ var vcsBzr = &vcsCmd{ tagSyncCmd: "update -r {tag}", tagSyncDefault: "update -r revno:-1", - scheme: []string{"https", "http", "bzr", "bzr+ssh"}, - pingCmd: "info {scheme}://{repo}", + scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + pingCmd: "info {scheme}://{repo}", + remoteRepo: bzrRemoteRepo, + resolveRepo: bzrResolveRepo, +} + +func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "config parent_location") + if err != nil { + return "", err + } + return strings.TrimSpace(string(outb)), nil +} + +func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // (branch root|repository branch): + // ... + + found := false + for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { + i := strings.Index(out, prefix) + if i >= 0 { + out = out[i+len(prefix):] + found = true + break + } + } + if !found { + return "", fmt.Errorf("unable to parse output of bzr info") + } + + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of bzr info") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } // vcsSvn describes how to use Subversion. @@ -138,8 +223,34 @@ var vcsSvn = &vcsCmd{ // There is no tag command in subversion. // The branch information is all in the path names. - scheme: []string{"https", "http", "svn", "svn+ssh"}, - pingCmd: "info {scheme}://{repo}", + scheme: []string{"https", "http", "svn", "svn+ssh"}, + pingCmd: "info {scheme}://{repo}", + remoteRepo: svnRemoteRepo, +} + +func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsSvn.runOutput(rootDir, "info") + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // Repository Root: + // ... + + i := strings.Index(out, "\nRepository Root: ") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[i+len("\nRepository Root: "):] + i = strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } func (v *vcsCmd) String() string { @@ -361,7 +472,14 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`) func repoRootForImportPath(importPath string) (*repoRoot, error) { rr, err := repoRootForImportPathStatic(importPath, "") if err == errUnknownSite { - rr, err = repoRootForImportDynamic(importPath) + // If there are wildcards, look up the thing before the wildcard, + // hoping it applies to the wildcarded parts too. + // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. + lookup := strings.TrimSuffix(importPath, "/...") + if i := strings.Index(lookup, "/.../"); i >= 0 { + lookup = lookup[:i] + } + rr, err = repoRootForImportDynamic(lookup) // repoRootForImportDynamic returns error detail // that is irrelevant if the user didn't intend to use a @@ -465,11 +583,11 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { func repoRootForImportDynamic(importPath string) (*repoRoot, error) { slash := strings.Index(importPath, "/") if slash < 0 { - return nil, errors.New("import path doesn't contain a slash") + return nil, errors.New("import path does not contain a slash") } host := importPath[:slash] if !strings.Contains(host, ".") { - return nil, errors.New("import path doesn't contain a hostname") + return nil, errors.New("import path does not begin with hostname") } urlStr, body, err := httpsOrHTTP(importPath) if err != nil { @@ -613,6 +731,15 @@ var vcsPaths = []*vcsPath{ check: launchpadVCS, }, + // IBM DevOps Services (JazzHub) + { + prefix: "hub.jazz.net/git", + re: `^(?Phub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + // General syntax for any server. { re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`, diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go new file mode 100644 index 000000000..14d681ba6 --- /dev/null +++ b/src/cmd/go/vcs_test.go @@ -0,0 +1,124 @@ +// Copyright 2014 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. + +package main + +import ( + "runtime" + "testing" +) + +// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath. +// TODO(cmang): Add tests for SVN and BZR. +func TestRepoRootForImportPath(t *testing.T) { + if testing.Short() { + t.Skip("skipping test to avoid external network") + } + switch runtime.GOOS { + case "nacl", "android": + t.Skipf("no networking available on %s", runtime.GOOS) + } + tests := []struct { + path string + want *repoRoot + }{ + { + "code.google.com/p/go", + &repoRoot{ + vcs: vcsHg, + repo: "https://code.google.com/p/go", + }, + }, + /*{ + "code.google.com/r/go", + &repoRoot{ + vcs: vcsHg, + repo: "https://code.google.com/r/go", + }, + },*/ + { + "github.com/golang/groupcache", + &repoRoot{ + vcs: vcsGit, + repo: "https://github.com/golang/groupcache", + }, + }, + // IBM DevOps Services tests + { + "hub.jazz.net/git/user1/pkgname", + &repoRoot{ + vcs: vcsGit, + repo: "https://hub.jazz.net/git/user1/pkgname", + }, + }, + { + "hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule", + &repoRoot{ + vcs: vcsGit, + repo: "https://hub.jazz.net/git/user1/pkgname", + }, + }, + { + "hub.jazz.net", + nil, + }, + { + "hub2.jazz.net", + nil, + }, + { + "hub.jazz.net/someotherprefix", + nil, + }, + { + "hub.jazz.net/someotherprefix/user1/pkgname", + nil, + }, + // Spaces are not valid in user names or package names + { + "hub.jazz.net/git/User 1/pkgname", + nil, + }, + { + "hub.jazz.net/git/user1/pkg name", + nil, + }, + // Dots are not valid in user names + { + "hub.jazz.net/git/user.1/pkgname", + nil, + }, + { + "hub.jazz.net/git/user/pkg.name", + &repoRoot{ + vcs: vcsGit, + repo: "https://hub.jazz.net/git/user/pkg.name", + }, + }, + // User names cannot have uppercase letters + { + "hub.jazz.net/git/USER/pkgname", + nil, + }, + } + + for _, test := range tests { + got, err := repoRootForImportPath(test.path) + want := test.want + + if want == nil { + if err == nil { + t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path) + } + continue + } + if err != nil { + t.Errorf("RepoRootForImport(%q): %v", test.path, err) + continue + } + if got.vcs.name != want.vcs.name || got.repo != want.repo { + t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo) + } + } +} diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go index ffb431837..02ff54b2a 100644 --- a/src/cmd/go/vet.go +++ b/src/cmd/go/vet.go @@ -4,6 +4,8 @@ package main +import "path/filepath" + func init() { addBuildFlagsNX(cmdVet) } @@ -15,7 +17,7 @@ var cmdVet = &Command{ Long: ` Vet runs the Go vet command on the packages named by the import paths. -For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'. +For more about vet, see 'godoc golang.org/x/tools/cmd/vet'. For more about specifying packages, see 'go help packages'. To run the vet tool with specific options, run 'go tool vet'. @@ -28,10 +30,21 @@ See also: go fmt, go fix. } func runVet(cmd *Command, args []string) { - for _, pkg := range packages(args) { - // Use pkg.gofiles instead of pkg.Dir so that - // the command only applies to this package, - // not to packages in subdirectories. - run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles))) + for _, p := range packages(args) { + // Vet expects to be given a set of files all from the same package. + // Run once for package p and once for package p_test. + if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 { + runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles)) + } + if len(p.XTestGoFiles) > 0 { + runVetFiles(p, stringList(p.XTestGoFiles)) + } + } +} + +func runVetFiles(p *Package, files []string) { + for i := range files { + files[i] = filepath.Join(p.Dir, files[i]) } + run(tool("vet"), relPaths(files)) } diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go index 8f73ef5b9..3fc043954 100644 --- a/src/cmd/gofmt/doc.go +++ b/src/cmd/gofmt/doc.go @@ -67,7 +67,7 @@ To remove the parentheses: To convert the package tree from explicit slice upper bounds to implicit ones: - gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg + gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src The simplify command diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 576cae522..81da21ff1 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -87,13 +87,13 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error return err } - file, adjust, err := parse(fileSet, filename, src, stdin) + file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) if err != nil { return err } if rewrite != nil { - if adjust == nil { + if sourceAdj == nil { file = rewrite(file) } else { fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n") @@ -106,15 +106,10 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error simplify(file) } - var buf bytes.Buffer - err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file) + res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) if err != nil { return err } - res := buf.Bytes() - if adjust != nil { - res = adjust(src, res) - } if !bytes.Equal(src, res) { // formatting has changed @@ -122,7 +117,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error fmt.Fprintln(out, filename) } if *write { - err = ioutil.WriteFile(filename, res, 0) + err = ioutil.WriteFile(filename, res, 0644) if err != nil { return err } @@ -186,6 +181,11 @@ func gofmtMain() { initRewrite() if flag.NArg() == 0 { + if *write { + fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") + exitCode = 2 + return + } if err := processFile("", os.Stdin, os.Stdout, true); err != nil { report(err) } @@ -235,19 +235,29 @@ func diff(b1, b2 []byte) (data []byte, err error) { } -// parse parses src, which was read from filename, -// as a Go source file or statement list. -func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) { +// ---------------------------------------------------------------------------- +// Support functions +// +// The functions parse, format, and isSpace below are identical to the +// respective functions in src/go/format/format.go - keep them in sync! +// +// TODO(gri) Factor out this functionality, eventually. + +// parse parses src, which was read from the named file, +// as a Go source file, declaration, or statement list. +func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + err error, +) { // Try as whole source file. - file, err := parser.ParseFile(fset, filename, src, parserMode) - if err == nil { - return file, nil, nil - } - // If the error is that the source file didn't begin with a - // package line and this is standard input, fall through to + file, err = parser.ParseFile(fset, filename, src, parserMode) + // If there's no error, return. If the error is that the source file didn't begin with a + // package line and source fragments are ok, fall through to // try as a source fragment. Stop and return on any other error. - if !stdin || !strings.Contains(err.Error(), "expected 'package'") { - return nil, nil, err + if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { + return } // If this is a declaration list, make it a source file @@ -257,19 +267,19 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F psrc := append([]byte("package p;"), src...) file, err = parser.ParseFile(fset, filename, psrc, parserMode) if err == nil { - adjust := func(orig, src []byte) []byte { + sourceAdj = func(src []byte, indent int) []byte { // Remove the package clause. // Gofmt has turned the ; into a \n. - src = src[len("package p\n"):] - return matchSpace(orig, src) + src = src[indent+len("package p\n"):] + return bytes.TrimSpace(src) } - return file, adjust, nil + return } // If the error is that the source file didn't begin with a // declaration, fall through to try as a statement list. // Stop and return on any other error. if !strings.Contains(err.Error(), "expected declaration") { - return nil, nil, err + return } // If this is a statement list, make it a source file @@ -277,68 +287,101 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F // into a function body. This handles expressions too. // Insert using a ;, not a newline, so that the line numbers // in fsrc match the ones in src. - fsrc := append(append([]byte("package p; func _() {"), src...), '}') + fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}') file, err = parser.ParseFile(fset, filename, fsrc, parserMode) if err == nil { - adjust := func(orig, src []byte) []byte { + sourceAdj = func(src []byte, indent int) []byte { + // Cap adjusted indent to zero. + if indent < 0 { + indent = 0 + } // Remove the wrapping. // Gofmt has turned the ; into a \n\n. - src = src[len("package p\n\nfunc _() {"):] - src = src[:len(src)-len("}\n")] - // Gofmt has also indented the function body one level. - // Remove that indent. - src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) - return matchSpace(orig, src) + // There will be two non-blank lines with indent, hence 2*indent. + src = src[2*indent+len("package p\n\nfunc _() {"):] + src = src[:len(src)-(indent+len("\n}\n"))] + return bytes.TrimSpace(src) } - return file, adjust, nil + // Gofmt has also indented the function body one level. + // Adjust that with indentAdj. + indentAdj = -1 } - // Failed, and out of options. - return nil, nil, err + // Succeeded, or out of options. + return } -func cutSpace(b []byte) (before, middle, after []byte) { - i := 0 - for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { - i++ - } - j := len(b) - for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { - j-- - } - if i <= j { - return b[:i], b[i:j], b[j:] +// format formats the given package file originally obtained from src +// and adjusts the result based on the original source via sourceAdj +// and indentAdj. +func format( + fset *token.FileSet, + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + src []byte, + cfg printer.Config, +) ([]byte, error) { + if sourceAdj == nil { + // Complete source file. + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + return buf.Bytes(), nil } - return nil, nil, b[j:] -} -// matchSpace reformats src to use the same space context as orig. -// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src. -// 2) matchSpace copies the indentation of the first non-blank line in orig -// to every non-blank line in src. -// 3) matchSpace copies the trailing space from orig and uses it in place -// of src's trailing space. -func matchSpace(orig []byte, src []byte) []byte { - before, _, after := cutSpace(orig) - i := bytes.LastIndex(before, []byte{'\n'}) - before, indent := before[:i+1], before[i+1:] - - _, src, _ = cutSpace(src) - - var b bytes.Buffer - b.Write(before) - for len(src) > 0 { - line := src - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, src = line[:i+1], line[i+1:] - } else { - src = nil + // Partial source file. + // Determine and prepend leading space. + i, j := 0, 0 + for j < len(src) && isSpace(src[j]) { + if src[j] == '\n' { + i = j + 1 // byte offset of last line in leading space } - if len(line) > 0 && line[0] != '\n' { // not blank - b.Write(indent) + j++ + } + var res []byte + res = append(res, src[:i]...) + + // Determine and prepend indentation of first code line. + // Spaces are ignored unless there are no tabs, + // in which case spaces count as one tab. + indent := 0 + hasSpace := false + for _, b := range src[i:j] { + switch b { + case ' ': + hasSpace = true + case '\t': + indent++ } - b.Write(line) } - b.Write(after) - return b.Bytes() + if indent == 0 && hasSpace { + indent = 1 + } + for i := 0; i < indent; i++ { + res = append(res, '\t') + } + + // Format the source. + // Write it without any leading and trailing space. + cfg.Indent = indent + indentAdj + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) + + // Determine and append trailing space. + i = len(src) + for i > 0 && isSpace(src[i-1]) { + i-- + } + return append(res, src[i:]...), nil +} + +func isSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' } diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index b9335b8f3..d1edb7bcc 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -6,18 +6,60 @@ package main import ( "bytes" + "flag" "io/ioutil" + "os" "path/filepath" "strings" "testing" + "text/scanner" ) -func runTest(t *testing.T, in, out, flags string) { +var update = flag.Bool("update", false, "update .golden files") + +// gofmtFlags looks for a comment of the form +// +// //gofmt flags +// +// within the first maxLines lines of the given file, +// and returns the flags string, if any. Otherwise it +// returns the empty string. +func gofmtFlags(filename string, maxLines int) string { + f, err := os.Open(filename) + if err != nil { + return "" // ignore errors - they will be found later + } + defer f.Close() + + // initialize scanner + var s scanner.Scanner + s.Init(f) + s.Error = func(*scanner.Scanner, string) {} // ignore errors + s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments + + // look for //gofmt comment + for s.Line <= maxLines { + switch s.Scan() { + case scanner.Comment: + const prefix = "//gofmt " + if t := s.TokenText(); strings.HasPrefix(t, prefix) { + return strings.TrimSpace(t[len(prefix):]) + } + case scanner.EOF: + return "" + } + + } + + return "" +} + +func runTest(t *testing.T, in, out string) { // process flags *simplifyAST = false *rewriteRule = "" stdin := false - for _, flag := range strings.Split(flags, " ") { + for _, flag := range strings.Split(gofmtFlags(in, 20), " ") { elts := strings.SplitN(flag, "=", 2) name := elts[0] value := "" @@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) { } if got := buf.Bytes(); !bytes.Equal(got, expected) { + if *update { + if in != out { + if err := ioutil.WriteFile(out, got, 0666); err != nil { + t.Error(err) + } + return + } + // in == out: don't accidentally destroy input + t.Errorf("WARNING: -update did not rewrite input file %s", in) + } + t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in) d, err := diff(expected, got) if err == nil { @@ -67,51 +120,37 @@ func runTest(t *testing.T, in, out, flags string) { } } -var tests = []struct { - in, flags string -}{ - {"gofmt.go", ""}, - {"gofmt_test.go", ""}, - {"testdata/composites.input", "-s"}, - {"testdata/slices1.input", "-s"}, - {"testdata/slices2.input", "-s"}, - {"testdata/old.input", ""}, - {"testdata/rewrite1.input", "-r=Foo->Bar"}, - {"testdata/rewrite2.input", "-r=int->bool"}, - {"testdata/rewrite3.input", "-r=x->x"}, - {"testdata/rewrite4.input", "-r=(x)->x"}, - {"testdata/rewrite5.input", "-r=x+x->2*x"}, - {"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"}, - {"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"}, - {"testdata/rewrite8.input", "-r=interface{}->int"}, - {"testdata/stdin*.input", "-stdin"}, - {"testdata/comments.input", ""}, - {"testdata/import.input", ""}, - {"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF - {"testdata/typeswitch.input", ""}, // test case for issue 4470 -} - +// TestRewrite processes testdata/*.input files and compares them to the +// corresponding testdata/*.golden files. The gofmt flags used to process +// a file must be provided via a comment of the form +// +// //gofmt flags +// +// in the processed file within the first 20 lines, if any. func TestRewrite(t *testing.T) { - for _, test := range tests { - match, err := filepath.Glob(test.in) - if err != nil { - t.Error(err) - continue + // determine input files + match, err := filepath.Glob("testdata/*.input") + if err != nil { + t.Fatal(err) + } + + // add larger examples + match = append(match, "gofmt.go", "gofmt_test.go") + + for _, in := range match { + out := in // for files where input and output are identical + if strings.HasSuffix(in, ".input") { + out = in[:len(in)-len(".input")] + ".golden" } - for _, in := range match { - out := in - if strings.HasSuffix(in, ".input") { - out = in[:len(in)-len(".input")] + ".golden" - } - runTest(t, in, out, test.flags) - if in != out { - // Check idempotence. - runTest(t, out, out, test.flags) - } + runTest(t, in, out) + if in != out { + // Check idempotence. + runTest(t, out, out) } } } +// Test case for issue 3961. func TestCRLF(t *testing.T) { const input = "testdata/crlf.input" // must contain CR/LF's const golden = "testdata/crlf.golden" // must not contain any CR's diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 108278b33..237b86021 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -32,7 +32,7 @@ var ( ) func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error { - f, _, err := parse(fset, filename, src.Bytes(), false) + f, _, _, err := parse(fset, filename, src.Bytes(), false) if err != nil { return err } @@ -60,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { // exclude files w/ syntax errors (typically test cases) fset := token.NewFileSet() - if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { + if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { if *verbose { fmt.Fprintf(os.Stderr, "ignoring %s\n", err) } diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go index fb6c6fc81..d267cfcc1 100644 --- a/src/cmd/gofmt/rewrite.go +++ b/src/cmd/gofmt/rewrite.go @@ -226,9 +226,6 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { return true case reflect.Struct: - if p.NumField() != v.NumField() { - return false - } for i := 0; i < p.NumField(); i++ { if !match(m, p.Field(i), v.Field(i)) { return false diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go index 45d000d67..69f7bf23c 100644 --- a/src/cmd/gofmt/simplify.go +++ b/src/cmd/gofmt/simplify.go @@ -68,9 +68,10 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { // a slice expression of the form: s[a:len(s)] // can be simplified to: s[a:] // if s is "simple enough" (for now we only accept identifiers) - if s.hasDotImport { - // if dot imports are present, we cannot be certain that an - // unresolved "len" identifier refers to the predefined len() + if n.Max != nil || s.hasDotImport { + // - 3-index slices always require the 2nd and 3rd index + // - if dot imports are present, we cannot be certain that an + // unresolved "len" identifier refers to the predefined len() break } if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil { @@ -96,16 +97,26 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor { // x, y := b[:n], b[n:] case *ast.RangeStmt: - // a range of the form: for x, _ = range v {...} + // - a range of the form: for x, _ = range v {...} // can be simplified to: for x = range v {...} - if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" { + // - a range of the form: for _ = range v {...} + // can be simplified to: for range v {...} + if isBlank(n.Value) { n.Value = nil } + if isBlank(n.Key) && n.Value == nil { + n.Key = nil + } } return s } +func isBlank(x ast.Expr) bool { + ident, ok := x.(*ast.Ident) + return ok && ident.Name == "_" +} + func simplify(f *ast.File) { var s simplifier @@ -117,5 +128,34 @@ func simplify(f *ast.File) { } } + // remove empty declarations such as "const ()", etc + removeEmptyDeclGroups(f) + ast.Walk(&s, f) } + +func removeEmptyDeclGroups(f *ast.File) { + i := 0 + for _, d := range f.Decls { + if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) { + f.Decls[i] = d + i++ + } + } + f.Decls = f.Decls[:i] +} + +func isEmpty(f *ast.File, g *ast.GenDecl) bool { + if g.Doc != nil || g.Specs != nil { + return false + } + + for _, c := range f.Comments { + // if there is a comment in the declaration, it is not considered empty + if g.Pos() <= c.Pos() && c.End() <= g.End() { + return false + } + } + + return true +} diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden index b2825e732..fc9c98e62 100644 --- a/src/cmd/gofmt/testdata/composites.golden +++ b/src/cmd/gofmt/testdata/composites.golden @@ -1,3 +1,5 @@ +//gofmt -s + package P type T struct { diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input index 7210dafc9..fc7598af9 100644 --- a/src/cmd/gofmt/testdata/composites.input +++ b/src/cmd/gofmt/testdata/composites.input @@ -1,3 +1,5 @@ +//gofmt -s + package P type T struct { diff --git a/src/cmd/gofmt/testdata/crlf.golden b/src/cmd/gofmt/testdata/crlf.golden index 57679f770..193dbacc7 100644 --- a/src/cmd/gofmt/testdata/crlf.golden +++ b/src/cmd/gofmt/testdata/crlf.golden @@ -2,6 +2,7 @@ Source containing CR/LF line endings. The gofmt'ed output must only have LF line endings. + Test case for issue 3961. */ package main diff --git a/src/cmd/gofmt/testdata/crlf.input b/src/cmd/gofmt/testdata/crlf.input index 61a1aa0b4..ae7e14dbf 100644 --- a/src/cmd/gofmt/testdata/crlf.input +++ b/src/cmd/gofmt/testdata/crlf.input @@ -2,6 +2,7 @@ Source containing CR/LF line endings. The gofmt'ed output must only have LF line endings. + Test case for issue 3961. */ package main diff --git a/src/cmd/gofmt/testdata/emptydecl.golden b/src/cmd/gofmt/testdata/emptydecl.golden new file mode 100644 index 000000000..33d6435e0 --- /dev/null +++ b/src/cmd/gofmt/testdata/emptydecl.golden @@ -0,0 +1,14 @@ +//gofmt -s + +// Test case for issue 7631. + +package main + +// Keep this declaration +var () + +const ( +// Keep this declaration +) + +func main() {} diff --git a/src/cmd/gofmt/testdata/emptydecl.input b/src/cmd/gofmt/testdata/emptydecl.input new file mode 100644 index 000000000..4948a61f0 --- /dev/null +++ b/src/cmd/gofmt/testdata/emptydecl.input @@ -0,0 +1,16 @@ +//gofmt -s + +// Test case for issue 7631. + +package main + +// Keep this declaration +var () + +const ( +// Keep this declaration +) + +type () + +func main() {} \ No newline at end of file diff --git a/src/cmd/gofmt/testdata/ranges.golden b/src/cmd/gofmt/testdata/ranges.golden new file mode 100644 index 000000000..506b3a035 --- /dev/null +++ b/src/cmd/gofmt/testdata/ranges.golden @@ -0,0 +1,30 @@ +//gofmt -s + +// Test cases for range simplification. +package p + +func _() { + for a, b = range x { + } + for a = range x { + } + for _, b = range x { + } + for range x { + } + + for a = range x { + } + for range x { + } + + for a, b := range x { + } + for a := range x { + } + for _, b := range x { + } + + for a := range x { + } +} diff --git a/src/cmd/gofmt/testdata/ranges.input b/src/cmd/gofmt/testdata/ranges.input new file mode 100644 index 000000000..df5f8333c --- /dev/null +++ b/src/cmd/gofmt/testdata/ranges.input @@ -0,0 +1,20 @@ +//gofmt -s + +// Test cases for range simplification. +package p + +func _() { + for a, b = range x {} + for a, _ = range x {} + for _, b = range x {} + for _, _ = range x {} + + for a = range x {} + for _ = range x {} + + for a, b := range x {} + for a, _ := range x {} + for _, b := range x {} + + for a := range x {} +} diff --git a/src/cmd/gofmt/testdata/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden index d9beb3705..3ee5373a7 100644 --- a/src/cmd/gofmt/testdata/rewrite1.golden +++ b/src/cmd/gofmt/testdata/rewrite1.golden @@ -1,3 +1,5 @@ +//gofmt -r=Foo->Bar + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input index bdb894320..a84c8f781 100644 --- a/src/cmd/gofmt/testdata/rewrite1.input +++ b/src/cmd/gofmt/testdata/rewrite1.input @@ -1,3 +1,5 @@ +//gofmt -r=Foo->Bar + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden index 64c67ffa6..f980e0353 100644 --- a/src/cmd/gofmt/testdata/rewrite2.golden +++ b/src/cmd/gofmt/testdata/rewrite2.golden @@ -1,3 +1,5 @@ +//gofmt -r=int->bool + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input index 21171447a..489be4e07 100644 --- a/src/cmd/gofmt/testdata/rewrite2.input +++ b/src/cmd/gofmt/testdata/rewrite2.input @@ -1,3 +1,5 @@ +//gofmt -r=int->bool + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite3.golden b/src/cmd/gofmt/testdata/rewrite3.golden index 0d16d1601..261a220c6 100644 --- a/src/cmd/gofmt/testdata/rewrite3.golden +++ b/src/cmd/gofmt/testdata/rewrite3.golden @@ -1,3 +1,5 @@ +//gofmt -r=x->x + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite3.input b/src/cmd/gofmt/testdata/rewrite3.input index 0d16d1601..261a220c6 100644 --- a/src/cmd/gofmt/testdata/rewrite3.input +++ b/src/cmd/gofmt/testdata/rewrite3.input @@ -1,3 +1,5 @@ +//gofmt -r=x->x + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite4.golden b/src/cmd/gofmt/testdata/rewrite4.golden index 8dfc81a07..b05547b4b 100644 --- a/src/cmd/gofmt/testdata/rewrite4.golden +++ b/src/cmd/gofmt/testdata/rewrite4.golden @@ -1,3 +1,5 @@ +//gofmt -r=(x)->x + // Copyright 2012 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. diff --git a/src/cmd/gofmt/testdata/rewrite4.input b/src/cmd/gofmt/testdata/rewrite4.input index 164cc0451..081709920 100644 --- a/src/cmd/gofmt/testdata/rewrite4.input +++ b/src/cmd/gofmt/testdata/rewrite4.input @@ -1,3 +1,5 @@ +//gofmt -r=(x)->x + // Copyright 2012 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. diff --git a/src/cmd/gofmt/testdata/rewrite5.golden b/src/cmd/gofmt/testdata/rewrite5.golden index 5a448a63d..9beb34aee 100644 --- a/src/cmd/gofmt/testdata/rewrite5.golden +++ b/src/cmd/gofmt/testdata/rewrite5.golden @@ -1,3 +1,5 @@ +//gofmt -r=x+x->2*x + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite5.input b/src/cmd/gofmt/testdata/rewrite5.input index 0d759e69b..d7a6122d0 100644 --- a/src/cmd/gofmt/testdata/rewrite5.input +++ b/src/cmd/gofmt/testdata/rewrite5.input @@ -1,3 +1,5 @@ +//gofmt -r=x+x->2*x + // Copyright 2011 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. diff --git a/src/cmd/gofmt/testdata/rewrite6.golden b/src/cmd/gofmt/testdata/rewrite6.golden index e565dbdd9..48ec9aa0d 100644 --- a/src/cmd/gofmt/testdata/rewrite6.golden +++ b/src/cmd/gofmt/testdata/rewrite6.golden @@ -1,3 +1,5 @@ +//gofmt -r=fun(x)->Fun(x) + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/rewrite6.input b/src/cmd/gofmt/testdata/rewrite6.input index 8c088b3e8..b085a84fe 100644 --- a/src/cmd/gofmt/testdata/rewrite6.input +++ b/src/cmd/gofmt/testdata/rewrite6.input @@ -1,3 +1,5 @@ +//gofmt -r=fun(x)->Fun(x) + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/rewrite7.golden b/src/cmd/gofmt/testdata/rewrite7.golden index 29babad9f..8386a0b2a 100644 --- a/src/cmd/gofmt/testdata/rewrite7.golden +++ b/src/cmd/gofmt/testdata/rewrite7.golden @@ -1,3 +1,5 @@ +//gofmt -r=fun(x...)->Fun(x) + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/rewrite7.input b/src/cmd/gofmt/testdata/rewrite7.input index 073e2a3e6..c1984708e 100644 --- a/src/cmd/gofmt/testdata/rewrite7.input +++ b/src/cmd/gofmt/testdata/rewrite7.input @@ -1,3 +1,5 @@ +//gofmt -r=fun(x...)->Fun(x) + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/rewrite8.golden b/src/cmd/gofmt/testdata/rewrite8.golden index cfc452b03..62f0419df 100644 --- a/src/cmd/gofmt/testdata/rewrite8.golden +++ b/src/cmd/gofmt/testdata/rewrite8.golden @@ -1,3 +1,5 @@ +//gofmt -r=interface{}->int + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/rewrite8.input b/src/cmd/gofmt/testdata/rewrite8.input index 235efa91c..7964c5c75 100644 --- a/src/cmd/gofmt/testdata/rewrite8.input +++ b/src/cmd/gofmt/testdata/rewrite8.input @@ -1,3 +1,5 @@ +//gofmt -r=interface{}->int + // Copyright 2013 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. diff --git a/src/cmd/gofmt/testdata/slices1.golden b/src/cmd/gofmt/testdata/slices1.golden index 61e074f68..04bc16f21 100644 --- a/src/cmd/gofmt/testdata/slices1.golden +++ b/src/cmd/gofmt/testdata/slices1.golden @@ -1,3 +1,5 @@ +//gofmt -s + // Test cases for slice expression simplification. package p @@ -15,6 +17,7 @@ var ( _ = a[3:(len(a))] _ = a[len(a) : len(a)-1] _ = a[0:len(b)] + _ = a[2:len(a):len(a)] _ = a[:] _ = a[:10] @@ -22,6 +25,7 @@ var ( _ = a[:(len(a))] _ = a[:len(a)-1] _ = a[:len(b)] + _ = a[:len(a):len(a)] _ = s[0:] _ = s[1:10] @@ -29,6 +33,7 @@ var ( _ = s[3:(len(s))] _ = s[len(a) : len(s)-1] _ = s[0:len(b)] + _ = s[2:len(s):len(s)] _ = s[:] _ = s[:10] @@ -36,6 +41,7 @@ var ( _ = s[:(len(s))] _ = s[:len(s)-1] _ = s[:len(b)] + _ = s[:len(s):len(s)] _ = t.s[0:] _ = t.s[1:10] @@ -43,6 +49,7 @@ var ( _ = t.s[3:(len(t.s))] _ = t.s[len(a) : len(t.s)-1] _ = t.s[0:len(b)] + _ = t.s[2:len(t.s):len(t.s)] _ = t.s[:] _ = t.s[:10] @@ -50,6 +57,7 @@ var ( _ = t.s[:(len(t.s))] _ = t.s[:len(t.s)-1] _ = t.s[:len(b)] + _ = t.s[:len(t.s):len(t.s)] ) func _() { diff --git a/src/cmd/gofmt/testdata/slices1.input b/src/cmd/gofmt/testdata/slices1.input index 4d2cbfff4..1f25c43cc 100644 --- a/src/cmd/gofmt/testdata/slices1.input +++ b/src/cmd/gofmt/testdata/slices1.input @@ -1,3 +1,5 @@ +//gofmt -s + // Test cases for slice expression simplification. package p @@ -15,6 +17,7 @@ var ( _ = a[3:(len(a))] _ = a[len(a) : len(a)-1] _ = a[0:len(b)] + _ = a[2:len(a):len(a)] _ = a[:] _ = a[:10] @@ -22,6 +25,7 @@ var ( _ = a[:(len(a))] _ = a[:len(a)-1] _ = a[:len(b)] + _ = a[:len(a):len(a)] _ = s[0:] _ = s[1:10] @@ -29,6 +33,7 @@ var ( _ = s[3:(len(s))] _ = s[len(a) : len(s)-1] _ = s[0:len(b)] + _ = s[2:len(s):len(s)] _ = s[:] _ = s[:10] @@ -36,6 +41,7 @@ var ( _ = s[:(len(s))] _ = s[:len(s)-1] _ = s[:len(b)] + _ = s[:len(s):len(s)] _ = t.s[0:] _ = t.s[1:10] @@ -43,6 +49,7 @@ var ( _ = t.s[3:(len(t.s))] _ = t.s[len(a) : len(t.s)-1] _ = t.s[0:len(b)] + _ = t.s[2:len(t.s):len(t.s)] _ = t.s[:] _ = t.s[:10] @@ -50,6 +57,7 @@ var ( _ = t.s[:(len(t.s))] _ = t.s[:len(t.s)-1] _ = t.s[:len(b)] + _ = t.s[:len(t.s):len(t.s)] ) func _() { diff --git a/src/cmd/gofmt/testdata/slices2.golden b/src/cmd/gofmt/testdata/slices2.golden index 433788e1e..ab657004e 100644 --- a/src/cmd/gofmt/testdata/slices2.golden +++ b/src/cmd/gofmt/testdata/slices2.golden @@ -1,3 +1,5 @@ +//gofmt -s + // Test cases for slice expression simplification. // Because of a dot import, these slices must remain untouched. package p diff --git a/src/cmd/gofmt/testdata/slices2.input b/src/cmd/gofmt/testdata/slices2.input index 433788e1e..ab657004e 100644 --- a/src/cmd/gofmt/testdata/slices2.input +++ b/src/cmd/gofmt/testdata/slices2.input @@ -1,3 +1,5 @@ +//gofmt -s + // Test cases for slice expression simplification. // Because of a dot import, these slices must remain untouched. package p diff --git a/src/cmd/gofmt/testdata/stdin1.golden b/src/cmd/gofmt/testdata/stdin1.golden index ff8b0b7ab..9e4dcd20f 100644 --- a/src/cmd/gofmt/testdata/stdin1.golden +++ b/src/cmd/gofmt/testdata/stdin1.golden @@ -1,3 +1,5 @@ + //gofmt -stdin + if x { y } diff --git a/src/cmd/gofmt/testdata/stdin1.golden.gofmt b/src/cmd/gofmt/testdata/stdin1.golden.gofmt deleted file mode 100644 index 1f888877d..000000000 --- a/src/cmd/gofmt/testdata/stdin1.golden.gofmt +++ /dev/null @@ -1,3 +0,0 @@ - if x { - y -} diff --git a/src/cmd/gofmt/testdata/stdin1.input b/src/cmd/gofmt/testdata/stdin1.input index ff8b0b7ab..9e4dcd20f 100644 --- a/src/cmd/gofmt/testdata/stdin1.input +++ b/src/cmd/gofmt/testdata/stdin1.input @@ -1,3 +1,5 @@ + //gofmt -stdin + if x { y } diff --git a/src/cmd/gofmt/testdata/stdin1.input.gofmt b/src/cmd/gofmt/testdata/stdin1.input.gofmt deleted file mode 100644 index 1f888877d..000000000 --- a/src/cmd/gofmt/testdata/stdin1.input.gofmt +++ /dev/null @@ -1,3 +0,0 @@ - if x { - y -} diff --git a/src/cmd/gofmt/testdata/stdin2.golden b/src/cmd/gofmt/testdata/stdin2.golden index 7eb1b54fe..57df35540 100644 --- a/src/cmd/gofmt/testdata/stdin2.golden +++ b/src/cmd/gofmt/testdata/stdin2.golden @@ -1,4 +1,4 @@ - +//gofmt -stdin var x int diff --git a/src/cmd/gofmt/testdata/stdin2.golden.gofmt b/src/cmd/gofmt/testdata/stdin2.golden.gofmt deleted file mode 100644 index 85e800300..000000000 --- a/src/cmd/gofmt/testdata/stdin2.golden.gofmt +++ /dev/null @@ -1,10 +0,0 @@ - - - -var x int - -func f() { - y := z -} - - diff --git a/src/cmd/gofmt/testdata/stdin2.input b/src/cmd/gofmt/testdata/stdin2.input index 99defd2d1..69d6bdd68 100644 --- a/src/cmd/gofmt/testdata/stdin2.input +++ b/src/cmd/gofmt/testdata/stdin2.input @@ -1,4 +1,4 @@ - +//gofmt -stdin var x int diff --git a/src/cmd/gofmt/testdata/stdin2.input.gofmt b/src/cmd/gofmt/testdata/stdin2.input.gofmt deleted file mode 100644 index 7eb1b54fe..000000000 --- a/src/cmd/gofmt/testdata/stdin2.input.gofmt +++ /dev/null @@ -1,11 +0,0 @@ - - -var x int - -func f() { - y := z - /* this is a comment */ - // this is a comment too -} - - diff --git a/src/cmd/gofmt/testdata/stdin3.golden b/src/cmd/gofmt/testdata/stdin3.golden index 1bf2f5a48..d6da0e417 100644 --- a/src/cmd/gofmt/testdata/stdin3.golden +++ b/src/cmd/gofmt/testdata/stdin3.golden @@ -1,3 +1,4 @@ + //gofmt -stdin /* note: no newline at end of file */ for i := 0; i < 10; i++ { diff --git a/src/cmd/gofmt/testdata/stdin3.golden.gofmt b/src/cmd/gofmt/testdata/stdin3.golden.gofmt deleted file mode 100644 index b4d1d4663..000000000 --- a/src/cmd/gofmt/testdata/stdin3.golden.gofmt +++ /dev/null @@ -1,7 +0,0 @@ - - - /* note: no newline at end of file */ - for i := 0; i < 10; i++ { - s += i - } - \ No newline at end of file diff --git a/src/cmd/gofmt/testdata/stdin3.input b/src/cmd/gofmt/testdata/stdin3.input index d963bd0d2..ab46c1063 100644 --- a/src/cmd/gofmt/testdata/stdin3.input +++ b/src/cmd/gofmt/testdata/stdin3.input @@ -1,3 +1,4 @@ + //gofmt -stdin /* note: no newline at end of file */ for i := 0; i < 10; i++ { s += i } diff --git a/src/cmd/gofmt/testdata/stdin3.input.gofmt b/src/cmd/gofmt/testdata/stdin3.input.gofmt deleted file mode 100644 index b4d1d4663..000000000 --- a/src/cmd/gofmt/testdata/stdin3.input.gofmt +++ /dev/null @@ -1,7 +0,0 @@ - - - /* note: no newline at end of file */ - for i := 0; i < 10; i++ { - s += i - } - \ No newline at end of file diff --git a/src/cmd/gofmt/testdata/stdin4.golden b/src/cmd/gofmt/testdata/stdin4.golden index 5f7343551..0c7acace5 100644 --- a/src/cmd/gofmt/testdata/stdin4.golden +++ b/src/cmd/gofmt/testdata/stdin4.golden @@ -1,3 +1,5 @@ + //gofmt -stdin + // comment i := 0 diff --git a/src/cmd/gofmt/testdata/stdin4.golden.gofmt b/src/cmd/gofmt/testdata/stdin4.golden.gofmt deleted file mode 100644 index 5f7343551..000000000 --- a/src/cmd/gofmt/testdata/stdin4.golden.gofmt +++ /dev/null @@ -1,3 +0,0 @@ - // comment - - i := 0 diff --git a/src/cmd/gofmt/testdata/stdin4.input b/src/cmd/gofmt/testdata/stdin4.input index f02a54fb1..1fc73f31e 100644 --- a/src/cmd/gofmt/testdata/stdin4.input +++ b/src/cmd/gofmt/testdata/stdin4.input @@ -1,3 +1,5 @@ + //gofmt -stdin + // comment i := 0 diff --git a/src/cmd/gofmt/testdata/stdin4.input.gofmt b/src/cmd/gofmt/testdata/stdin4.input.gofmt deleted file mode 100644 index 5f7343551..000000000 --- a/src/cmd/gofmt/testdata/stdin4.input.gofmt +++ /dev/null @@ -1,3 +0,0 @@ - // comment - - i := 0 diff --git a/src/cmd/gofmt/testdata/stdin5.golden b/src/cmd/gofmt/testdata/stdin5.golden new file mode 100644 index 000000000..31ce6b248 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin5.golden @@ -0,0 +1,3 @@ +//gofmt -stdin + +i := 5 // Line comment without newline. \ No newline at end of file diff --git a/src/cmd/gofmt/testdata/stdin5.input b/src/cmd/gofmt/testdata/stdin5.input new file mode 100644 index 000000000..0a7c97d18 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin5.input @@ -0,0 +1,3 @@ +//gofmt -stdin + +i :=5// Line comment without newline. \ No newline at end of file diff --git a/src/cmd/gofmt/testdata/stdin6.golden b/src/cmd/gofmt/testdata/stdin6.golden new file mode 100644 index 000000000..ffcea8011 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin6.golden @@ -0,0 +1,19 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f := func(hat, tail string) { + + fmt.Println(hat+` +foo + + +`+tail, + "more", + "and more") + } diff --git a/src/cmd/gofmt/testdata/stdin6.input b/src/cmd/gofmt/testdata/stdin6.input new file mode 100644 index 000000000..78330020c --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin6.input @@ -0,0 +1,21 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f:=func( hat, tail string){ + + + + fmt. Println ( hat+ ` +foo + + +`+ tail , + "more" , + "and more" ) + } diff --git a/src/cmd/gofmt/testdata/stdin7.golden b/src/cmd/gofmt/testdata/stdin7.golden new file mode 100644 index 000000000..bbac7133c --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin7.golden @@ -0,0 +1,19 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f := func(hat, tail string) { + + fmt.Println(hat+` + foo + + + `+tail, + "more", + "and more") + } diff --git a/src/cmd/gofmt/testdata/stdin7.input b/src/cmd/gofmt/testdata/stdin7.input new file mode 100644 index 000000000..fd772a3c4 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin7.input @@ -0,0 +1,21 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f:=func( hat, tail string){ + + + + fmt. Println ( hat+ ` + foo + + + `+ tail , + "more" , + "and more" ) + } diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go new file mode 100644 index 000000000..79a83e59a --- /dev/null +++ b/src/cmd/internal/goobj/read.go @@ -0,0 +1,666 @@ +// Copyright 2013 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. + +// Package goobj implements reading of Go object files and archives. +// +// TODO(rsc): Decide where this package should live. (golang.org/issue/6932) +// TODO(rsc): Decide the appropriate integer types for various fields. +// TODO(rsc): Write tests. (File format still up in the air a little.) +package goobj + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +// A SymKind describes the kind of memory represented by a symbol. +type SymKind int + +// This list is taken from include/link.h. + +// Defined SymKind values. +// TODO(rsc): Give idiomatic Go names. +// TODO(rsc): Reduce the number of symbol types in the object files. +const ( + _ SymKind = iota + + // readonly, executable + STEXT + SELFRXSECT + + // readonly, non-executable + STYPE + SSTRING + SGOSTRING + SGOFUNC + SRODATA + SFUNCTAB + STYPELINK + SSYMTAB // TODO: move to unmapped section + SPCLNTAB + SELFROSECT + + // writable, non-executable + SMACHOPLT + SELFSECT + SMACHO // Mach-O __nl_symbol_ptr + SMACHOGOT + SNOPTRDATA + SINITARR + SDATA + SWINDOWS + SBSS + SNOPTRBSS + STLSBSS + + // not mapped + SXREF + SMACHOSYMSTR + SMACHOSYMTAB + SMACHOINDIRECTPLT + SMACHOINDIRECTGOT + SFILE + SFILEPATH + SCONST + SDYNIMPORT + SHOSTOBJ +) + +var symKindStrings = []string{ + SBSS: "SBSS", + SCONST: "SCONST", + SDATA: "SDATA", + SDYNIMPORT: "SDYNIMPORT", + SELFROSECT: "SELFROSECT", + SELFRXSECT: "SELFRXSECT", + SELFSECT: "SELFSECT", + SFILE: "SFILE", + SFILEPATH: "SFILEPATH", + SFUNCTAB: "SFUNCTAB", + SGOFUNC: "SGOFUNC", + SGOSTRING: "SGOSTRING", + SHOSTOBJ: "SHOSTOBJ", + SINITARR: "SINITARR", + SMACHO: "SMACHO", + SMACHOGOT: "SMACHOGOT", + SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT", + SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT", + SMACHOPLT: "SMACHOPLT", + SMACHOSYMSTR: "SMACHOSYMSTR", + SMACHOSYMTAB: "SMACHOSYMTAB", + SNOPTRBSS: "SNOPTRBSS", + SNOPTRDATA: "SNOPTRDATA", + SPCLNTAB: "SPCLNTAB", + SRODATA: "SRODATA", + SSTRING: "SSTRING", + SSYMTAB: "SSYMTAB", + STEXT: "STEXT", + STLSBSS: "STLSBSS", + STYPE: "STYPE", + STYPELINK: "STYPELINK", + SWINDOWS: "SWINDOWS", + SXREF: "SXREF", +} + +func (k SymKind) String() string { + if k < 0 || int(k) >= len(symKindStrings) { + return fmt.Sprintf("SymKind(%d)", k) + } + return symKindStrings[k] +} + +// A Sym is a named symbol in an object file. +type Sym struct { + SymID // symbol identifier (name and version) + Kind SymKind // kind of symbol + DupOK bool // are duplicate definitions okay? + Size int // size of corresponding data + Type SymID // symbol for Go type information + Data Data // memory image of symbol + Reloc []Reloc // relocations to apply to Data + Func *Func // additional data for functions +} + +// A SymID - the combination of Name and Version - uniquely identifies +// a symbol within a package. +type SymID struct { + // Name is the name of a symbol. + Name string + + // Version is zero for symbols with global visibility. + // Symbols with only file visibility (such as file-level static + // declarations in C) have a non-zero version distinguishing + // a symbol in one file from a symbol of the same name + // in another file + Version int +} + +func (s SymID) String() string { + if s.Version == 0 { + return s.Name + } + return fmt.Sprintf("%s<%d>", s.Name, s.Version) +} + +// A Data is a reference to data stored in an object file. +// It records the offset and size of the data, so that a client can +// read the data only if necessary. +type Data struct { + Offset int64 + Size int64 +} + +// A Reloc describes a relocation applied to a memory image to refer +// to an address within a particular symbol. +type Reloc struct { + // The bytes at [Offset, Offset+Size) within the memory image + // should be updated to refer to the address Add bytes after the start + // of the symbol Sym. + Offset int + Size int + Sym SymID + Add int + + // The Type records the form of address expected in the bytes + // described by the previous fields: absolute, PC-relative, and so on. + // TODO(rsc): The interpretation of Type is not exposed by this package. + Type int +} + +// A Var describes a variable in a function stack frame: a declared +// local variable, an input argument, or an output result. +type Var struct { + // The combination of Name, Kind, and Offset uniquely + // identifies a variable in a function stack frame. + // Using fewer of these - in particular, using only Name - does not. + Name string // Name of variable. + Kind int // TODO(rsc): Define meaning. + Offset int // Frame offset. TODO(rsc): Define meaning. + + Type SymID // Go type for variable. +} + +// Func contains additional per-symbol information specific to functions. +type Func struct { + Args int // size in bytes of argument frame: inputs and outputs + Frame int // size in bytes of local variable frame + Leaf bool // function omits save of link register (ARM) + NoSplit bool // function omits stack split prologue + Var []Var // detail about local variables + PCSP Data // PC → SP offset map + PCFile Data // PC → file number map (index into File) + PCLine Data // PC → line number map + PCData []Data // PC → runtime support data map + FuncData []FuncData // non-PC-specific runtime support data + File []string // paths indexed by PCFile +} + +// TODO: Add PCData []byte and PCDataIter (similar to liblink). + +// A FuncData is a single function-specific data value. +type FuncData struct { + Sym SymID // symbol holding data + Offset int64 // offset into symbol for funcdata pointer +} + +// A Package is a parsed Go object file or archive defining a Go package. +type Package struct { + ImportPath string // import path denoting this package + Imports []string // packages imported by this package + Syms []*Sym // symbols defined by this package + MaxVersion int // maximum Version in any SymID in Syms +} + +var ( + archiveHeader = []byte("!\n") + archiveMagic = []byte("`\n") + goobjHeader = []byte("go objec") // truncated to size of archiveHeader + + errCorruptArchive = errors.New("corrupt archive") + errTruncatedArchive = errors.New("truncated archive") + errNotArchive = errors.New("unrecognized archive format") + + errCorruptObject = errors.New("corrupt object file") + errTruncatedObject = errors.New("truncated object file") + errNotObject = errors.New("unrecognized object file format") +) + +// An objReader is an object file reader. +type objReader struct { + p *Package + b *bufio.Reader + f io.ReadSeeker + err error + offset int64 + limit int64 + tmp [256]byte + pkg string + pkgprefix string +} + +// importPathToPrefix returns the prefix that will be used in the +// final symbol table for the given import path. +// We escape '%', '"', all control characters and non-ASCII bytes, +// and any '.' after the final slash. +// +// See ../../../cmd/ld/lib.c:/^pathtoprefix and +// ../../../cmd/gc/subr.c:/^pathtoprefix. +func importPathToPrefix(s string) string { + // find index of last slash, if any, or else -1. + // used for determining whether an index is after the last slash. + slash := strings.LastIndex(s, "/") + + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) +} + +// init initializes r to read package p from f. +func (r *objReader) init(f io.ReadSeeker, p *Package) { + r.f = f + r.p = p + r.offset, _ = f.Seek(0, 1) + r.limit, _ = f.Seek(0, 2) + f.Seek(r.offset, 0) + r.b = bufio.NewReader(f) + r.pkgprefix = importPathToPrefix(p.ImportPath) + "." +} + +// error records that an error occurred. +// It returns only the first error, so that an error +// caused by an earlier error does not discard information +// about the earlier error. +func (r *objReader) error(err error) error { + if r.err == nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + r.err = err + } + // panic("corrupt") // useful for debugging + return r.err +} + +// readByte reads and returns a byte from the input file. +// On I/O error or EOF, it records the error but returns byte 0. +// A sequence of 0 bytes will eventually terminate any +// parsing state in the object file. In particular, it ends the +// reading of a varint. +func (r *objReader) readByte() byte { + if r.err != nil { + return 0 + } + if r.offset >= r.limit { + r.error(io.ErrUnexpectedEOF) + return 0 + } + b, err := r.b.ReadByte() + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + r.error(err) + b = 0 + } else { + r.offset++ + } + return b +} + +// read reads exactly len(b) bytes from the input file. +// If an error occurs, read returns the error but also +// records it, so it is safe for callers to ignore the result +// as long as delaying the report is not a problem. +func (r *objReader) readFull(b []byte) error { + if r.err != nil { + return r.err + } + if r.offset+int64(len(b)) > r.limit { + return r.error(io.ErrUnexpectedEOF) + } + n, err := io.ReadFull(r.b, b) + r.offset += int64(n) + if err != nil { + return r.error(err) + } + return nil +} + +// readInt reads a zigzag varint from the input file. +func (r *objReader) readInt() int { + var u uint64 + + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + r.error(errCorruptObject) + return 0 + } + c := r.readByte() + u |= uint64(c&0x7F) << shift + if c&0x80 == 0 { + break + } + } + + v := int64(u>>1) ^ (int64(u) << 63 >> 63) + if int64(int(v)) != v { + r.error(errCorruptObject) // TODO + return 0 + } + return int(v) +} + +// readString reads a length-delimited string from the input file. +func (r *objReader) readString() string { + n := r.readInt() + buf := make([]byte, n) + r.readFull(buf) + return string(buf) +} + +// readSymID reads a SymID from the input file. +func (r *objReader) readSymID() SymID { + name, vers := r.readString(), r.readInt() + + // In a symbol name in an object file, "". denotes the + // prefix for the package in which the object file has been found. + // Expand it. + name = strings.Replace(name, `"".`, r.pkgprefix, -1) + + // An individual object file only records version 0 (extern) or 1 (static). + // To make static symbols unique across all files being read, we + // replace version 1 with the version corresponding to the current + // file number. The number is incremented on each call to parseObject. + if vers != 0 { + vers = r.p.MaxVersion + } + + return SymID{name, vers} +} + +// readData reads a data reference from the input file. +func (r *objReader) readData() Data { + n := r.readInt() + d := Data{Offset: r.offset, Size: int64(n)} + r.skip(int64(n)) + return d +} + +// skip skips n bytes in the input. +func (r *objReader) skip(n int64) { + if n < 0 { + r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip")) + } + if n < int64(len(r.tmp)) { + // Since the data is so small, a just reading from the buffered + // reader is better than flushing the buffer and seeking. + r.readFull(r.tmp[:n]) + } else if n <= int64(r.b.Buffered()) { + // Even though the data is not small, it has already been read. + // Advance the buffer instead of seeking. + for n > int64(len(r.tmp)) { + r.readFull(r.tmp[:]) + n -= int64(len(r.tmp)) + } + r.readFull(r.tmp[:n]) + } else { + // Seek, giving up buffered data. + _, err := r.f.Seek(r.offset+n, 0) + if err != nil { + r.error(err) + } + r.offset += n + r.b.Reset(r.f) + } +} + +// Parse parses an object file or archive from r, +// assuming that its import path is pkgpath. +func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) { + if pkgpath == "" { + pkgpath = `""` + } + p := new(Package) + p.ImportPath = pkgpath + + var rd objReader + rd.init(r, p) + err := rd.readFull(rd.tmp[:8]) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return nil, err + } + + switch { + default: + return nil, errNotObject + + case bytes.Equal(rd.tmp[:8], archiveHeader): + if err := rd.parseArchive(); err != nil { + return nil, err + } + case bytes.Equal(rd.tmp[:8], goobjHeader): + if err := rd.parseObject(goobjHeader); err != nil { + return nil, err + } + } + + return p, nil +} + +// trimSpace removes trailing spaces from b and returns the corresponding string. +// This effectively parses the form used in archive headers. +func trimSpace(b []byte) string { + return string(bytes.TrimRight(b, " ")) +} + +// parseArchive parses a Unix archive of Go object files. +// TODO(rsc): Need to skip non-Go object files. +// TODO(rsc): Maybe record table of contents in r.p so that +// linker can avoid having code to parse archives too. +func (r *objReader) parseArchive() error { + for r.offset < r.limit { + if err := r.readFull(r.tmp[:60]); err != nil { + return err + } + data := r.tmp[:60] + + // Each file is preceded by this text header (slice indices in first column): + // 0:16 name + // 16:28 date + // 28:34 uid + // 34:40 gid + // 40:48 mode + // 48:58 size + // 58:60 magic - `\n + // We only care about name, size, and magic. + // The fields are space-padded on the right. + // The size is in decimal. + // The file data - size bytes - follows the header. + // Headers are 2-byte aligned, so if size is odd, an extra padding + // byte sits between the file data and the next header. + // The file data that follows is padded to an even number of bytes: + // if size is odd, an extra padding byte is inserted betw the next header. + if len(data) < 60 { + return errTruncatedArchive + } + if !bytes.Equal(data[58:60], archiveMagic) { + return errCorruptArchive + } + name := trimSpace(data[0:16]) + size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64) + if err != nil { + return errCorruptArchive + } + data = data[60:] + fsize := size + size&1 + if fsize < 0 || fsize < size { + return errCorruptArchive + } + switch name { + case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF": + r.skip(size) + default: + oldLimit := r.limit + r.limit = r.offset + size + if err := r.parseObject(nil); err != nil { + return fmt.Errorf("parsing archive member %q: %v", name, err) + } + r.skip(r.limit - r.offset) + r.limit = oldLimit + } + if size&1 != 0 { + r.skip(1) + } + } + return nil +} + +// parseObject parses a single Go object file. +// The prefix is the bytes already read from the file, +// typically in order to detect that this is an object file. +// The object file consists of a textual header ending in "\n!\n" +// and then the part we want to parse begins. +// The format of that part is defined in a comment at the top +// of src/liblink/objfile.c. +func (r *objReader) parseObject(prefix []byte) error { + // TODO(rsc): Maybe use prefix and the initial input to + // record the header line from the file, which would + // give the architecture and other version information. + + r.p.MaxVersion++ + var c1, c2, c3 byte + for { + c1, c2, c3 = c2, c3, r.readByte() + if c3 == 0 { // NUL or EOF, either is bad + return errCorruptObject + } + if c1 == '\n' && c2 == '!' && c3 == '\n' { + break + } + } + + r.readFull(r.tmp[:8]) + if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) { + return r.error(errCorruptObject) + } + + b := r.readByte() + if b != 1 { + return r.error(errCorruptObject) + } + + // Direct package dependencies. + for { + s := r.readString() + if s == "" { + break + } + r.p.Imports = append(r.p.Imports, s) + } + + // Symbols. + for { + if b := r.readByte(); b != 0xfe { + if b != 0xff { + return r.error(errCorruptObject) + } + break + } + + typ := r.readInt() + s := &Sym{SymID: r.readSymID()} + r.p.Syms = append(r.p.Syms, s) + s.Kind = SymKind(typ) + flags := r.readInt() + s.DupOK = flags&1 != 0 + s.Size = r.readInt() + s.Type = r.readSymID() + s.Data = r.readData() + s.Reloc = make([]Reloc, r.readInt()) + for i := range s.Reloc { + rel := &s.Reloc[i] + rel.Offset = r.readInt() + rel.Size = r.readInt() + rel.Type = r.readInt() + rel.Add = r.readInt() + r.readInt() // Xadd - ignored + rel.Sym = r.readSymID() + r.readSymID() // Xsym - ignored + } + + if s.Kind == STEXT { + f := new(Func) + s.Func = f + f.Args = r.readInt() + f.Frame = r.readInt() + flags := r.readInt() + f.Leaf = flags&1 != 0 + f.NoSplit = r.readInt() != 0 + f.Var = make([]Var, r.readInt()) + for i := range f.Var { + v := &f.Var[i] + v.Name = r.readSymID().Name + v.Offset = r.readInt() + v.Kind = r.readInt() + v.Type = r.readSymID() + } + + f.PCSP = r.readData() + f.PCFile = r.readData() + f.PCLine = r.readData() + f.PCData = make([]Data, r.readInt()) + for i := range f.PCData { + f.PCData[i] = r.readData() + } + f.FuncData = make([]FuncData, r.readInt()) + for i := range f.FuncData { + f.FuncData[i].Sym = r.readSymID() + } + for i := range f.FuncData { + f.FuncData[i].Offset = int64(r.readInt()) // TODO + } + f.File = make([]string, r.readInt()) + for i := range f.File { + f.File[i] = r.readSymID().Name + } + } + } + + r.readFull(r.tmp[:7]) + if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) { + return r.error(errCorruptObject) + } + + return nil +} diff --git a/src/cmd/internal/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go new file mode 100644 index 000000000..cc991e5d9 --- /dev/null +++ b/src/cmd/internal/goobj/read_test.go @@ -0,0 +1,28 @@ +// Copyright 2013 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. + +package goobj + +import "testing" + +var importPathToPrefixTests = []struct { + in string + out string +}{ + {"runtime", "runtime"}, + {"sync/atomic", "sync/atomic"}, + {"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"}, + {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, + {"", ""}, + {"%foo%bar", "%25foo%25bar"}, + {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, +} + +func TestImportPathToPrefix(t *testing.T) { + for _, tt := range importPathToPrefixTests { + if out := importPathToPrefix(tt.in); out != tt.out { + t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out) + } + } +} diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go new file mode 100644 index 000000000..1a339c321 --- /dev/null +++ b/src/cmd/internal/objfile/disasm.go @@ -0,0 +1,248 @@ +// Copyright 2014 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. + +package objfile + +import ( + "bufio" + "debug/gosym" + "encoding/binary" + "fmt" + "io" + "regexp" + "sort" + "strings" + "text/tabwriter" + + "cmd/internal/rsc.io/arm/armasm" + "cmd/internal/rsc.io/x86/x86asm" +) + +// Disasm is a disassembler for a given File. +type Disasm struct { + syms []Sym //symbols in file, sorted by address + pcln *gosym.Table // pcln table + text []byte // bytes of text segment (actual instructions) + textStart uint64 // start PC of text + textEnd uint64 // end PC of text + goarch string // GOARCH string + disasm disasmFunc // disassembler function for goarch + byteOrder binary.ByteOrder // byte order for goarch +} + +// Disasm returns a disassembler for the file f. +func (f *File) Disasm() (*Disasm, error) { + syms, err := f.Symbols() + if err != nil { + return nil, err + } + + pcln, err := f.PCLineTable() + if err != nil { + return nil, err + } + + textStart, textBytes, err := f.Text() + if err != nil { + return nil, err + } + + goarch := f.GOARCH() + disasm := disasms[goarch] + byteOrder := byteOrders[goarch] + if disasm == nil || byteOrder == nil { + return nil, fmt.Errorf("unsupported architecture") + } + + // Filter out section symbols, overwriting syms in place. + keep := syms[:0] + for _, sym := range syms { + switch sym.Name { + case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext": + // drop + default: + keep = append(keep, sym) + } + } + syms = keep + d := &Disasm{ + syms: syms, + pcln: pcln, + text: textBytes, + textStart: textStart, + textEnd: textStart + uint64(len(textBytes)), + goarch: goarch, + disasm: disasm, + byteOrder: byteOrder, + } + + return d, nil +} + +// lookup finds the symbol name containing addr. +func (d *Disasm) lookup(addr uint64) (name string, base uint64) { + i := sort.Search(len(d.syms), func(i int) bool { return addr < d.syms[i].Addr }) + if i > 0 { + s := d.syms[i-1] + if s.Addr != 0 && s.Addr <= addr && addr < s.Addr+uint64(s.Size) { + return s.Name, s.Addr + } + } + return "", 0 +} + +// base returns the final element in the path. +// It works on both Windows and Unix paths, +// regardless of host operating system. +func base(path string) string { + path = path[strings.LastIndex(path, "/")+1:] + path = path[strings.LastIndex(path, `\`)+1:] + return path +} + +// Print prints a disassembly of the file to w. +// If filter is non-nil, the disassembly only includes functions with names matching filter. +// The disassembly only includes functions that overlap the range [start, end). +func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) { + if start < d.textStart { + start = d.textStart + } + if end > d.textEnd { + end = d.textEnd + } + printed := false + bw := bufio.NewWriter(w) + for _, sym := range d.syms { + symStart := sym.Addr + symEnd := sym.Addr + uint64(sym.Size) + if sym.Code != 'T' && sym.Code != 't' || + symStart < d.textStart || + symEnd <= start || end <= symStart || + filter != nil && !filter.MatchString(sym.Name) { + continue + } + if printed { + fmt.Fprintf(bw, "\n") + } + printed = true + + file, _, _ := d.pcln.PCToLine(sym.Addr) + fmt.Fprintf(bw, "TEXT %s(SB) %s\n", sym.Name, file) + + tw := tabwriter.NewWriter(bw, 1, 8, 1, '\t', 0) + if symEnd > end { + symEnd = end + } + code := d.text[:end-d.textStart] + d.Decode(symStart, symEnd, func(pc, size uint64, file string, line int, text string) { + i := pc - d.textStart + fmt.Fprintf(tw, "\t%s:%d\t%#x\t", base(file), line, pc) + if size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" { + // Print instruction as bytes. + fmt.Fprintf(tw, "%x", code[i:i+size]) + } else { + // Print instruction as 32-bit words. + for j := uint64(0); j < size; j += 4 { + if j > 0 { + fmt.Fprintf(tw, " ") + } + fmt.Fprintf(tw, "%08x", d.byteOrder.Uint32(code[i+j:])) + } + } + fmt.Fprintf(tw, "\t%s\n", text) + }) + tw.Flush() + } + bw.Flush() +} + +// Decode disassembles the text segment range [start, end), calling f for each instruction. +func (d *Disasm) Decode(start, end uint64, f func(pc, size uint64, file string, line int, text string)) { + if start < d.textStart { + start = d.textStart + } + if end > d.textEnd { + end = d.textEnd + } + code := d.text[:end-d.textStart] + lookup := d.lookup + for pc := start; pc < end; { + i := pc - d.textStart + text, size := d.disasm(code[i:], pc, lookup) + file, line, _ := d.pcln.PCToLine(pc) + f(pc, uint64(size), file, line, text) + pc += uint64(size) + } +} + +type lookupFunc func(addr uint64) (sym string, base uint64) +type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int) + +func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) { + return disasm_x86(code, pc, lookup, 32) +} + +func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) { + return disasm_x86(code, pc, lookup, 64) +} + +func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) { + inst, err := x86asm.Decode(code, 64) + var text string + size := inst.Len + if err != nil || size == 0 || inst.Op == 0 { + size = 1 + text = "?" + } else { + text = x86asm.Plan9Syntax(inst, pc, lookup) + } + return text, size +} + +type textReader struct { + code []byte + pc uint64 +} + +func (r textReader) ReadAt(data []byte, off int64) (n int, err error) { + if off < 0 || uint64(off) < r.pc { + return 0, io.EOF + } + d := uint64(off) - r.pc + if d >= uint64(len(r.code)) { + return 0, io.EOF + } + n = copy(data, r.code[d:]) + if n < len(data) { + err = io.ErrUnexpectedEOF + } + return +} + +func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) { + inst, err := armasm.Decode(code, armasm.ModeARM) + var text string + size := inst.Len + if err != nil || size == 0 || inst.Op == 0 { + size = 4 + text = "?" + } else { + text = armasm.Plan9Syntax(inst, pc, lookup, textReader{code, pc}) + } + return text, size +} + +var disasms = map[string]disasmFunc{ + "386": disasm_386, + "amd64": disasm_amd64, + "arm": disasm_arm, +} + +var byteOrders = map[string]binary.ByteOrder{ + "386": binary.LittleEndian, + "amd64": binary.LittleEndian, + "arm": binary.LittleEndian, + "power64": binary.BigEndian, + "power64le": binary.LittleEndian, +} diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go new file mode 100644 index 000000000..17755b84d --- /dev/null +++ b/src/cmd/internal/objfile/elf.go @@ -0,0 +1,104 @@ +// Copyright 2013 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. + +// Parsing of ELF executables (Linux, FreeBSD, and so on). + +package objfile + +import ( + "debug/elf" + "fmt" + "os" +) + +type elfFile struct { + elf *elf.File +} + +func openElf(r *os.File) (rawFile, error) { + f, err := elf.NewFile(r) + if err != nil { + return nil, err + } + return &elfFile{f}, nil +} + +func (f *elfFile) symbols() ([]Sym, error) { + elfSyms, err := f.elf.Symbols() + if err != nil { + return nil, err + } + + var syms []Sym + for _, s := range elfSyms { + sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} + switch s.Section { + case elf.SHN_UNDEF: + sym.Code = 'U' + case elf.SHN_COMMON: + sym.Code = 'B' + default: + i := int(s.Section) + if i < 0 || i >= len(f.elf.Sections) { + break + } + sect := f.elf.Sections[i] + switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { + case elf.SHF_ALLOC | elf.SHF_EXECINSTR: + sym.Code = 'T' + case elf.SHF_ALLOC: + sym.Code = 'R' + case elf.SHF_ALLOC | elf.SHF_WRITE: + sym.Code = 'D' + } + } + if elf.ST_BIND(s.Info) == elf.STB_LOCAL { + sym.Code += 'a' - 'A' + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + if sect := f.elf.Section(".text"); sect != nil { + textStart = sect.Addr + } + if sect := f.elf.Section(".gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := f.elf.Section(".gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (f *elfFile) text() (textStart uint64, text []byte, err error) { + sect := f.elf.Section(".text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *elfFile) goarch() string { + switch f.elf.Machine { + case elf.EM_386: + return "386" + case elf.EM_X86_64: + return "amd64" + case elf.EM_ARM: + return "arm" + case elf.EM_PPC64: + return "power64" + } + return "" +} diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go new file mode 100644 index 000000000..6b1607a17 --- /dev/null +++ b/src/cmd/internal/objfile/goobj.go @@ -0,0 +1,93 @@ +// Copyright 2013 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. + +// Parsing of Go intermediate object files and archives. + +package objfile + +import ( + "cmd/internal/goobj" + "fmt" + "os" +) + +type goobjFile struct { + goobj *goobj.Package +} + +func openGoobj(r *os.File) (rawFile, error) { + f, err := goobj.Parse(r, `""`) + if err != nil { + return nil, err + } + return &goobjFile{f}, nil +} + +func goobjName(id goobj.SymID) string { + if id.Version == 0 { + return id.Name + } + return fmt.Sprintf("%s<%d>", id.Name, id.Version) +} + +func (f *goobjFile) symbols() ([]Sym, error) { + seen := make(map[goobj.SymID]bool) + + var syms []Sym + for _, s := range f.goobj.Syms { + seen[s.SymID] = true + sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'} + switch s.Kind { + case goobj.STEXT, goobj.SELFRXSECT: + sym.Code = 'T' + case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT: + sym.Code = 'R' + case goobj.SMACHOPLT, goobj.SELFSECT, goobj.SMACHO, goobj.SMACHOGOT, goobj.SNOPTRDATA, goobj.SINITARR, goobj.SDATA, goobj.SWINDOWS: + sym.Code = 'D' + case goobj.SBSS, goobj.SNOPTRBSS, goobj.STLSBSS: + sym.Code = 'B' + case goobj.SXREF, goobj.SMACHOSYMSTR, goobj.SMACHOSYMTAB, goobj.SMACHOINDIRECTPLT, goobj.SMACHOINDIRECTGOT, goobj.SFILE, goobj.SFILEPATH, goobj.SCONST, goobj.SDYNIMPORT, goobj.SHOSTOBJ: + sym.Code = 'X' // should not see + } + if s.Version != 0 { + sym.Code += 'a' - 'A' + } + syms = append(syms, sym) + } + + for _, s := range f.goobj.Syms { + for _, r := range s.Reloc { + if !seen[r.Sym] { + seen[r.Sym] = true + sym := Sym{Name: goobjName(r.Sym), Code: 'U'} + if s.Version != 0 { + // should not happen but handle anyway + sym.Code = 'u' + } + syms = append(syms, sym) + } + } + } + + return syms, nil +} + +// pcln does not make sense for Go object files, because each +// symbol has its own individual pcln table, so there is no global +// space of addresses to map. +func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + return 0, nil, nil, fmt.Errorf("pcln not available in go object file") +} + +// text does not make sense for Go object files, because +// each function has a separate section. +func (f *goobjFile) text() (textStart uint64, text []byte, err error) { + return 0, nil, fmt.Errorf("text not available in go object file") +} + +// goarch makes sense but is not exposed in debug/goobj's API, +// and we don't need it yet for any users of internal/objfile. +func (f *goobjFile) goarch() string { + return "GOARCH unimplemented for debug/goobj files" +} diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go new file mode 100644 index 000000000..7dd84a339 --- /dev/null +++ b/src/cmd/internal/objfile/macho.go @@ -0,0 +1,116 @@ +// Copyright 2013 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. + +// Parsing of Mach-O executables (OS X). + +package objfile + +import ( + "debug/macho" + "fmt" + "os" + "sort" +) + +type machoFile struct { + macho *macho.File +} + +func openMacho(r *os.File) (rawFile, error) { + f, err := macho.NewFile(r) + if err != nil { + return nil, err + } + return &machoFile{f}, nil +} + +func (f *machoFile) symbols() ([]Sym, error) { + if f.macho.Symtab == nil { + return nil, fmt.Errorf("missing symbol table") + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range f.macho.Symtab.Syms { + addrs = append(addrs, s.Value) + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + for _, s := range f.macho.Symtab.Syms { + sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + if s.Sect == 0 { + sym.Code = 'U' + } else if int(s.Sect) <= len(f.macho.Sections) { + sect := f.macho.Sections[s.Sect-1] + switch sect.Seg { + case "__TEXT": + sym.Code = 'R' + case "__DATA": + sym.Code = 'D' + } + switch sect.Seg + " " + sect.Name { + case "__TEXT __text": + sym.Code = 'T' + case "__DATA __bss", "__DATA __noptrbss": + sym.Code = 'B' + } + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + if sect := f.macho.Section("__text"); sect != nil { + textStart = sect.Addr + } + if sect := f.macho.Section("__gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := f.macho.Section("__gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (f *machoFile) text() (textStart uint64, text []byte, err error) { + sect := f.macho.Section("__text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *machoFile) goarch() string { + switch f.macho.Cpu { + case macho.Cpu386: + return "386" + case macho.CpuAmd64: + return "amd64" + case macho.CpuArm: + return "arm" + case macho.CpuPpc64: + return "power64" + } + return "" +} + +type uint64s []uint64 + +func (x uint64s) Len() int { return len(x) } +func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go new file mode 100644 index 000000000..9227ef387 --- /dev/null +++ b/src/cmd/internal/objfile/objfile.go @@ -0,0 +1,94 @@ +// Copyright 2014 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. + +// Package objfile implements portable access to OS-specific executable files. +package objfile + +import ( + "debug/gosym" + "fmt" + "os" + "sort" +) + +type rawFile interface { + symbols() (syms []Sym, err error) + pcln() (textStart uint64, symtab, pclntab []byte, err error) + text() (textStart uint64, text []byte, err error) + goarch() string +} + +// A File is an opened executable file. +type File struct { + r *os.File + raw rawFile +} + +// A Sym is a symbol defined in an executable file. +type Sym struct { + Name string // symbol name + Addr uint64 // virtual address of symbol + Size int64 // size in bytes + Code rune // nm code (T for text, D for data, and so on) + Type string // XXX? +} + +var openers = []func(*os.File) (rawFile, error){ + openElf, + openGoobj, + openMacho, + openPE, + openPlan9, +} + +// Open opens the named file. +// The caller must call f.Close when the file is no longer needed. +func Open(name string) (*File, error) { + r, err := os.Open(name) + if err != nil { + return nil, err + } + for _, try := range openers { + if raw, err := try(r); err == nil { + return &File{r, raw}, nil + } + } + r.Close() + return nil, fmt.Errorf("open %s: unrecognized object file", name) +} + +func (f *File) Close() error { + return f.r.Close() +} + +func (f *File) Symbols() ([]Sym, error) { + syms, err := f.raw.symbols() + if err != nil { + return nil, err + } + sort.Sort(byAddr(syms)) + return syms, nil +} + +type byAddr []Sym + +func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } +func (x byAddr) Len() int { return len(x) } +func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (f *File) PCLineTable() (*gosym.Table, error) { + textStart, symtab, pclntab, err := f.raw.pcln() + if err != nil { + return nil, err + } + return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) +} + +func (f *File) Text() (uint64, []byte, error) { + return f.raw.text() +} + +func (f *File) GOARCH() string { + return f.raw.goarch() +} diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go new file mode 100644 index 000000000..67e59c226 --- /dev/null +++ b/src/cmd/internal/objfile/pe.go @@ -0,0 +1,201 @@ +// Copyright 2013 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. + +// Parsing of PE executables (Microsoft Windows). + +package objfile + +import ( + "debug/pe" + "fmt" + "os" + "sort" +) + +type peFile struct { + pe *pe.File +} + +func openPE(r *os.File) (rawFile, error) { + f, err := pe.NewFile(r) + if err != nil { + return nil, err + } + switch f.OptionalHeader.(type) { + case *pe.OptionalHeader32, *pe.OptionalHeader64: + // ok + default: + return nil, fmt.Errorf("unrecognized PE format") + } + return &peFile{f}, nil +} + +func (f *peFile) symbols() ([]Sym, error) { + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + } + + var syms []Sym + for _, s := range f.pe.Symbols { + const ( + N_UNDEF = 0 // An undefined (extern) symbol + N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) + N_DEBUG = -2 // A debugging symbol + ) + sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} + switch s.SectionNumber { + case N_UNDEF: + sym.Code = 'U' + case N_ABS: + sym.Code = 'C' + case N_DEBUG: + sym.Code = '?' + default: + if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("invalid section number in symbol table") + } + sect := f.pe.Sections[s.SectionNumber-1] + const ( + text = 0x20 + data = 0x40 + bss = 0x80 + permX = 0x20000000 + permR = 0x40000000 + permW = 0x80000000 + ) + ch := sect.Characteristics + switch { + case ch&text != 0: + sym.Code = 'T' + case ch&data != 0: + if ch&permW == 0 { + sym.Code = 'R' + } else { + sym.Code = 'D' + } + case ch&bss != 0: + sym.Code = 'B' + } + sym.Addr += imageBase + uint64(sect.VirtualAddress) + } + syms = append(syms, sym) + addrs = append(addrs, sym.Addr) + } + + sort.Sort(uint64s(addrs)) + for i := range syms { + j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) + if j < len(addrs) { + syms[i].Size = int64(addrs[j] - syms[i].Addr) + } + } + + return syms, nil +} + +func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, nil, fmt.Errorf("pe file format not recognized") + } + if sect := f.pe.Section(".text"); sect != nil { + textStart = imageBase + uint64(sect.VirtualAddress) + } + if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil { + // We didn't find the symbols, so look for the names used in 1.3 and earlier. + // TODO: Remove code looking for the old symbols when we no longer care about 1.3. + var err2 error + if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil { + return 0, nil, nil, err + } + } + if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil { + // Same as above. + var err2 error + if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (f *peFile) text() (textStart uint64, text []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, fmt.Errorf("pe file format not recognized") + } + sect := f.pe.Section(".text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = imageBase + uint64(sect.VirtualAddress) + text, err = sect.Data() + return +} + +func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { + for _, s := range f.Symbols { + if s.Name != name { + continue + } + if s.SectionNumber <= 0 { + return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) + } + if len(f.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) + } + return s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { + ssym, err := findPESymbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPESymbol(f, ename) + if err != nil { + return nil, err + } + if ssym.SectionNumber != esym.SectionNumber { + return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) + } + sect := f.Sections[ssym.SectionNumber-1] + data, err := sect.Data() + if err != nil { + return nil, err + } + return data[ssym.Value:esym.Value], nil +} + +func (f *peFile) goarch() string { + // Not sure how to get the info we want from PE header. + // Look in symbol table for telltale rt0 symbol. + if _, err := findPESymbol(f.pe, "_rt0_386_windows"); err == nil { + return "386" + } + if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil { + return "amd64" + } + return "" +} diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go new file mode 100644 index 000000000..eb6cba5eb --- /dev/null +++ b/src/cmd/internal/objfile/plan9obj.go @@ -0,0 +1,146 @@ +// Copyright 2014 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. + +// Parsing of Plan 9 a.out executables. + +package objfile + +import ( + "debug/plan9obj" + "fmt" + "os" + "sort" +) + +var validSymType = map[rune]bool{ + 'T': true, + 't': true, + 'D': true, + 'd': true, + 'B': true, + 'b': true, +} + +type plan9File struct { + plan9 *plan9obj.File +} + +func openPlan9(r *os.File) (rawFile, error) { + f, err := plan9obj.NewFile(r) + if err != nil { + return nil, err + } + return &plan9File{f}, nil +} + +func (f *plan9File) symbols() ([]Sym, error) { + plan9Syms, err := f.plan9.Symbols() + if err != nil { + return nil, err + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range plan9Syms { + if !validSymType[s.Type] { + continue + } + addrs = append(addrs, s.Value) + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + + for _, s := range plan9Syms { + if !validSymType[s.Type] { + continue + } + sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + textStart = f.plan9.LoadAddress + f.plan9.HdrSize + if pclntab, err = loadPlan9Table(f.plan9, "runtime.pclntab", "runtime.epclntab"); err != nil { + // We didn't find the symbols, so look for the names used in 1.3 and earlier. + // TODO: Remove code looking for the old symbols when we no longer care about 1.3. + var err2 error + if pclntab, err2 = loadPlan9Table(f.plan9, "pclntab", "epclntab"); err2 != nil { + return 0, nil, nil, err + } + } + if symtab, err = loadPlan9Table(f.plan9, "runtime.symtab", "runtime.esymtab"); err != nil { + // Same as above. + var err2 error + if symtab, err2 = loadPlan9Table(f.plan9, "symtab", "esymtab"); err2 != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil +} + +func (f *plan9File) text() (textStart uint64, text []byte, err error) { + sect := f.plan9.Section("text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = f.plan9.LoadAddress + f.plan9.HdrSize + text, err = sect.Data() + return +} + +func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { + syms, err := f.Symbols() + if err != nil { + return nil, err + } + for _, s := range syms { + if s.Name != name { + continue + } + return &s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { + ssym, err := findPlan9Symbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPlan9Symbol(f, ename) + if err != nil { + return nil, err + } + sect := f.Section("text") + if sect == nil { + return nil, err + } + data, err := sect.Data() + if err != nil { + return nil, err + } + textStart := f.LoadAddress + f.HdrSize + return data[ssym.Value-textStart : esym.Value-textStart], nil +} + +func (f *plan9File) goarch() string { + switch f.plan9.Magic { + case plan9obj.Magic386: + return "386" + case plan9obj.MagicAMD64: + return "amd64" + case plan9obj.MagicARM: + return "arm" + } + return "" +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/Makefile b/src/cmd/internal/rsc.io/arm/armasm/Makefile new file mode 100644 index 000000000..a3f57001f --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/Makefile @@ -0,0 +1,2 @@ +tables.go: ../armmap/map.go ../arm.csv + go run ../armmap/map.go -fmt=decoder ../arm.csv >_tables.go && gofmt _tables.go >tables.go && rm _tables.go diff --git a/src/cmd/internal/rsc.io/arm/armasm/decode.go b/src/cmd/internal/rsc.io/arm/armasm/decode.go new file mode 100644 index 000000000..6b4d73841 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/decode.go @@ -0,0 +1,567 @@ +// Copyright 2014 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. + +package armasm + +import ( + "encoding/binary" + "fmt" +) + +// An instFormat describes the format of an instruction encoding. +// An instruction with 32-bit value x matches the format if x&mask == value +// and the condition matches. +// The condition matches if x>>28 == 0xF && value>>28==0xF +// or if x>>28 != 0xF and value>>28 == 0. +// If x matches the format, then the rest of the fields describe how to interpret x. +// The opBits describe bits that should be extracted from x and added to the opcode. +// For example opBits = 0x1234 means that the value +// (2 bits at offset 1) followed by (4 bits at offset 3) +// should be added to op. +// Finally the args describe how to decode the instruction arguments. +// args is stored as a fixed-size array; if there are fewer than len(args) arguments, +// args[i] == 0 marks the end of the argument list. +type instFormat struct { + mask uint32 + value uint32 + priority int8 + op Op + opBits uint64 + args instArgs +} + +type instArgs [4]instArg + +var ( + errMode = fmt.Errorf("unsupported execution mode") + errShort = fmt.Errorf("truncated instruction") + errUnknown = fmt.Errorf("unknown instruction") +) + +var decoderCover []bool + +// Decode decodes the leading bytes in src as a single instruction. +func Decode(src []byte, mode Mode) (inst Inst, err error) { + if mode != ModeARM { + return Inst{}, errMode + } + if len(src) < 4 { + return Inst{}, errShort + } + + if decoderCover == nil { + decoderCover = make([]bool, len(instFormats)) + } + + x := binary.LittleEndian.Uint32(src) + + // The instFormat table contains both conditional and unconditional instructions. + // Considering only the top 4 bits, the conditional instructions use mask=0, value=0, + // while the unconditional instructions use mask=f, value=f. + // Prepare a version of x with the condition cleared to 0 in conditional instructions + // and then assume mask=f during matching. + const condMask = 0xf0000000 + xNoCond := x + if x&condMask != condMask { + xNoCond &^= condMask + } + var priority int8 +Search: + for i := range instFormats { + f := &instFormats[i] + if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority { + continue + } + delta := uint32(0) + deltaShift := uint(0) + for opBits := f.opBits; opBits != 0; opBits >>= 16 { + n := uint(opBits & 0xFF) + off := uint((opBits >> 8) & 0xFF) + delta |= (x >> off) & (1<> 8) & (1<<4 - 1)) + case arg_R_12: + return Reg((x >> 12) & (1<<4 - 1)) + case arg_R_16: + return Reg((x >> 16) & (1<<4 - 1)) + + case arg_R_12_nzcv: + r := Reg((x >> 12) & (1<<4 - 1)) + if r == R15 { + return APSR_nzcv + } + return r + + case arg_R_16_WB: + mode := AddrLDM + if (x>>21)&1 != 0 { + mode = AddrLDM_WB + } + return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode} + + case arg_R_rotate: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1. + if typ == RotateRightExt { + return Reg(Rm) + } + return RegShift{Rm, typ, uint8(count)} + + case arg_R_shift_R: + Rm := Reg(x & (1<<4 - 1)) + Rs := Reg((x >> 8) & (1<<4 - 1)) + typ := Shift((x >> 5) & (1<<2 - 1)) + return RegShiftReg{Rm, typ, Rs} + + case arg_R_shift_imm: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + if typ == ShiftLeft && count == 0 { + return Reg(Rm) + } + return RegShift{Rm, typ, uint8(count)} + + case arg_R1_0: + return Reg((x & (1<<4 - 1))) + case arg_R1_12: + return Reg(((x >> 12) & (1<<4 - 1))) + case arg_R2_0: + return Reg((x & (1<<4 - 1)) | 1) + case arg_R2_12: + return Reg(((x >> 12) & (1<<4 - 1)) | 1) + + case arg_SP: + return SP + + case arg_Sd_Dd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Dd_Sd: + return decodeArg(arg_Sd_Dd, x^(1<<8)) + + case arg_Sd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Sm_Dm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Dn_half: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)} + + case arg_Sn_Dn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return S0 + Reg(v<<1+vx) + + case arg_const: + v := x & (1<<8 - 1) + rot := (x >> 8) & (1<<4 - 1) * 2 + if rot > 0 && v&3 == 0 { + // could rotate less + return ImmAlt{uint8(v), uint8(rot)} + } + if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v { + // could wrap around to rot==0. + return ImmAlt{uint8(v), uint8(rot)} + } + return Imm(v>>rot | v<<(32-rot)) + + case arg_endian: + return Endian((x >> 9) & 1) + + case arg_fbits: + return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1)) + + case arg_fp_0: + return Imm(0) + + case arg_imm24: + return Imm(x & (1<<24 - 1)) + + case arg_imm5: + return Imm((x >> 7) & (1<<5 - 1)) + + case arg_imm5_32: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + x = 32 + } + return Imm(x) + + case arg_imm5_nz: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + return nil + } + return Imm(x) + + case arg_imm_4at16_12at0: + return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1)) + + case arg_imm_12at8_4at0: + return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1)) + + case arg_imm_vfp: + x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1) + return Imm(x) + + case arg_label24: + imm := (x & (1<<24 - 1)) << 2 + return PCRel(int32(imm<<6) >> 6) + + case arg_label24H: + h := (x >> 24) & 1 + imm := (x&(1<<24-1))<<2 | h<<1 + return PCRel(int32(imm<<6) >> 6) + + case arg_label_m_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)} + + case arg_label_p_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_12: + d := int32(x & (1<<12 - 1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_4_4: + d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return PCRel(d) + + case arg_lsb_width: + lsb := (x >> 7) & (1<<5 - 1) + msb := (x >> 16) & (1<<5 - 1) + if msb < lsb || msb >= 32 { + return nil + } + return Imm(msb + 1 - lsb) + + case arg_mem_R: + Rn := Reg((x >> 16) & (1<<4 - 1)) + return Mem{Base: Rn, Mode: AddrOffset} + + case arg_mem_R_pm_R_postindex: + // Treat [],+/- like [,+/-{,}]{!} + // by forcing shift bits to <<0 and P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21)) + + case arg_mem_R_pm_R_W: + // Treat [,+/-]{!} like [,+/-{,}]{!} + // by forcing shift bits to <<0. + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5)) + + case arg_mem_R_pm_R_shift_imm_offset: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_R_shift_imm_postindex: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_R_shift_imm_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count} + + case arg_mem_R_pm_imm12_offset: + // Treat [,#+/-] like [{,#+/-}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_imm12_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm12_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x & (1<<12 - 1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm8_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8at0_offset: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x&(1<<8-1)) << 2 + return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm} + + case arg_option: + return Imm(x & (1<<4 - 1)) + + case arg_registers: + return RegList(x & (1<<16 - 1)) + + case arg_registers2: + x &= 1<<16 - 1 + n := 0 + for i := 0; i < 16; i++ { + if x>>uint(i)&1 != 0 { + n++ + } + } + if n < 2 { + return nil + } + return RegList(x) + + case arg_registers1: + Rt := (x >> 12) & (1<<4 - 1) + return RegList(1 << Rt) + + case arg_satimm4: + return Imm((x >> 16) & (1<<4 - 1)) + + case arg_satimm5: + return Imm((x >> 16) & (1<<5 - 1)) + + case arg_satimm4m1: + return Imm((x>>16)&(1<<4-1) + 1) + + case arg_satimm5m1: + return Imm((x>>16)&(1<<5-1) + 1) + + case arg_widthm1: + return Imm((x>>16)&(1<<5-1) + 1) + + } +} + +// decodeShift decodes the shift-by-immediate encoded in x. +func decodeShift(x uint32) (Shift, uint8) { + count := (x >> 7) & (1<<5 - 1) + typ := Shift((x >> 5) & (1<<2 - 1)) + switch typ { + case ShiftRight, ShiftRightSigned: + if count == 0 { + count = 32 + } + case RotateRight: + if count == 0 { + typ = RotateRightExt + count = 1 + } + } + return typ, uint8(count) +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/decode_test.go b/src/cmd/internal/rsc.io/arm/armasm/decode_test.go new file mode 100644 index 000000000..25a345a88 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/decode_test.go @@ -0,0 +1,69 @@ +// Copyright 2014 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. + +package armasm + +import ( + "encoding/hex" + "io/ioutil" + "strconv" + "strings" + "testing" +) + +func TestDecode(t *testing.T) { + data, err := ioutil.ReadFile("testdata/decode.txt") + if err != nil { + t.Fatal(err) + } + all := string(data) + for strings.Contains(all, "\t\t") { + all = strings.Replace(all, "\t\t", "\t", -1) + } + for _, line := range strings.Split(all, "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.SplitN(line, "\t", 4) + i := strings.Index(f[0], "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f[0]) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f[0]) + } + size := i / 2 + code, err := hex.DecodeString(f[0][:i] + f[0][i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f[0], err) + continue + } + mode, err := strconv.Atoi(f[1]) + if err != nil { + t.Errorf("invalid mode %q in: %s", f[1], line) + continue + } + syntax, asm := f[2], f[3] + inst, err := Decode(code, Mode(mode)) + var out string + if err != nil { + out = "error: " + err.Error() + } else { + switch syntax { + case "gnu": + out = GNUSyntax(inst) + case "plan9": + out = Plan9Syntax(inst, 0, nil, nil) + default: + t.Errorf("unknown syntax %q", syntax) + continue + } + } + if out != asm || inst.Len != size { + t.Errorf("Decode(%s) [%s] = %s, %d, want %s, %d", f[0], syntax, out, inst.Len, asm, size) + } + } +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go new file mode 100644 index 000000000..b0bd85597 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go @@ -0,0 +1,614 @@ +// Copyright 2014 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. + +// Support for testing against external disassembler program. +// Copied and simplified from rsc.io/x86/x86asm/ext_test.go. + +package armasm + +import ( + "bufio" + "bytes" + "encoding/hex" + "flag" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "os/exec" + "regexp" + "runtime" + "strings" + "testing" + "time" +) + +var ( + printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths") + dumpTest = flag.Bool("dump", false, "dump all encodings") + mismatch = flag.Bool("mismatch", false, "log allowed mismatches") + longTest = flag.Bool("long", false, "long test") + keep = flag.Bool("keep", false, "keep object files around") + debug = false +) + +// A ExtInst represents a single decoded instruction parsed +// from an external disassembler's output. +type ExtInst struct { + addr uint32 + enc [4]byte + nenc int + text string +} + +func (r ExtInst) String() string { + return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text) +} + +// An ExtDis is a connection between an external disassembler and a test. +type ExtDis struct { + Arch Mode + Dec chan ExtInst + File *os.File + Size int + KeepFile bool + Cmd *exec.Cmd +} + +// Run runs the given command - the external disassembler - and returns +// a buffered reader of its standard output. +func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) { + if *keep { + log.Printf("%s\n", strings.Join(cmd, " ")) + } + ext.Cmd = exec.Command(cmd[0], cmd[1:]...) + out, err := ext.Cmd.StdoutPipe() + if err != nil { + return nil, fmt.Errorf("stdoutpipe: %v", err) + } + if err := ext.Cmd.Start(); err != nil { + return nil, fmt.Errorf("exec: %v", err) + } + + b := bufio.NewReaderSize(out, 1<<20) + return b, nil +} + +// Wait waits for the command started with Run to exit. +func (ext *ExtDis) Wait() error { + return ext.Cmd.Wait() +} + +// testExtDis tests a set of byte sequences against an external disassembler. +// The disassembler is expected to produce the given syntax and be run +// in the given architecture mode (16, 32, or 64-bit). +// The extdis function must start the external disassembler +// and then parse its output, sending the parsed instructions on ext.Dec. +// The generate function calls its argument f once for each byte sequence +// to be tested. The generate function itself will be called twice, and it must +// make the same sequence of calls to f each time. +// When a disassembly does not match the internal decoding, +// allowedMismatch determines whether this mismatch should be +// allowed, or else considered an error. +func testExtDis( + t *testing.T, + syntax string, + arch Mode, + extdis func(ext *ExtDis) error, + generate func(f func([]byte)), + allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool, +) { + start := time.Now() + ext := &ExtDis{ + Dec: make(chan ExtInst), + Arch: arch, + } + errc := make(chan error) + + // First pass: write instructions to input file for external disassembler. + file, f, size, err := writeInst(generate) + if err != nil { + t.Fatal(err) + } + ext.Size = size + ext.File = f + defer func() { + f.Close() + if !*keep { + os.Remove(file) + } + }() + + // Second pass: compare disassembly against our decodings. + var ( + totalTests = 0 + totalSkips = 0 + totalErrors = 0 + + errors = make([]string, 0, 100) // sampled errors, at most cap + ) + go func() { + errc <- extdis(ext) + }() + generate(func(enc []byte) { + dec, ok := <-ext.Dec + if !ok { + t.Errorf("decoding stream ended early") + return + } + inst, text := disasm(syntax, arch, pad(enc)) + totalTests++ + if *dumpTest { + fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc) + } + if text != dec.text || inst.Len != dec.nenc { + suffix := "" + if allowedMismatch(text, size, &inst, dec) { + totalSkips++ + if !*mismatch { + return + } + suffix += " (allowed mismatch)" + } + totalErrors++ + if len(errors) >= cap(errors) { + j := rand.Intn(totalErrors) + if j >= cap(errors) { + return + } + errors = append(errors[:j], errors[j+1:]...) + } + errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix)) + } + }) + + if *mismatch { + totalErrors -= totalSkips + } + + for _, b := range errors { + t.Log(b) + } + + if totalErrors > 0 { + t.Fail() + } + t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds()) + + if err := <-errc; err != nil { + t.Fatal("external disassembler: %v", err) + } + +} + +const start = 0x8000 // start address of text + +// writeInst writes the generated byte sequences to a new file +// starting at offset start. That file is intended to be the input to +// the external disassembler. +func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) { + f, err = ioutil.TempFile("", "armasm") + if err != nil { + return + } + + file = f.Name() + + f.Seek(start, 0) + w := bufio.NewWriter(f) + defer w.Flush() + size = 0 + generate(func(x []byte) { + if len(x) > 4 { + x = x[:4] + } + if debug { + fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):]) + } + w.Write(x) + w.Write(zeros[len(x):]) + size += len(zeros) + }) + return file, f, size, nil +} + +var zeros = []byte{0, 0, 0, 0} + +// pad pads the code sequenc with pops. +func pad(enc []byte) []byte { + if len(enc) < 4 { + enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...) + } + return enc +} + +// disasm returns the decoded instruction and text +// for the given source bytes, using the given syntax and mode. +func disasm(syntax string, mode Mode, src []byte) (inst Inst, text string) { + // If printTests is set, we record the coverage value + // before and after, and we write out the inputs for which + // coverage went up, in the format expected in testdata/decode.text. + // This produces a fairly small set of test cases that exercise nearly + // all the code. + var cover float64 + if *printTests { + cover -= coverage() + } + + inst, err := Decode(src, mode) + if err != nil { + text = "error: " + err.Error() + } else { + text = inst.String() + switch syntax { + //case "arm": + // text = ARMSyntax(inst) + case "gnu": + text = GNUSyntax(inst) + //case "plan9": + // text = Plan9Syntax(inst, 0, nil) + default: + text = "error: unknown syntax " + syntax + } + } + + if *printTests { + cover += coverage() + if cover > 0 { + max := len(src) + if max > 4 && inst.Len <= 4 { + max = 4 + } + fmt.Printf("%x|%x\t%d\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], mode, syntax, text) + } + } + + return +} + +// coverage returns a floating point number denoting the +// test coverage until now. The number increases when new code paths are exercised, +// both in the Go program and in the decoder byte code. +func coverage() float64 { + /* + testing.Coverage is not in the main distribution. + The implementation, which must go in package testing, is: + + // Coverage reports the current code coverage as a fraction in the range [0, 1]. + func Coverage() float64 { + var n, d int64 + for _, counters := range cover.Counters { + for _, c := range counters { + if c > 0 { + n++ + } + d++ + } + } + if d == 0 { + return 0 + } + return float64(n) / float64(d) + } + */ + + var f float64 + f += testing.Coverage() + f += decodeCoverage() + return f +} + +func decodeCoverage() float64 { + n := 0 + for _, t := range decoderCover { + if t { + n++ + } + } + return float64(1+n) / float64(1+len(decoderCover)) +} + +// Helpers for writing disassembler output parsers. + +// hasPrefix reports whether any of the space-separated words in the text s +// begins with any of the given prefixes. +func hasPrefix(s string, prefixes ...string) bool { + for _, prefix := range prefixes { + for s := s; s != ""; { + if strings.HasPrefix(s, prefix) { + return true + } + i := strings.Index(s, " ") + if i < 0 { + break + } + s = s[i+1:] + } + } + return false +} + +// contains reports whether the text s contains any of the given substrings. +func contains(s string, substrings ...string) bool { + for _, sub := range substrings { + if strings.Contains(s, sub) { + return true + } + } + return false +} + +// isHex reports whether b is a hexadecimal character (0-9A-Fa-f). +func isHex(b byte) bool { return b == '0' || unhex[b] > 0 } + +// parseHex parses the hexadecimal byte dump in hex, +// appending the parsed bytes to raw and returning the updated slice. +// The returned bool signals whether any invalid hex was found. +// Spaces and tabs between bytes are okay but any other non-hex is not. +func parseHex(hex []byte, raw []byte) ([]byte, bool) { + hex = trimSpace(hex) + for j := 0; j < len(hex); { + for hex[j] == ' ' || hex[j] == '\t' { + j++ + } + if j >= len(hex) { + break + } + if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) { + return nil, false + } + raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]]) + j += 2 + } + return raw, true +} + +var unhex = [256]byte{ + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + 'A': 10, + 'B': 11, + 'C': 12, + 'D': 13, + 'E': 14, + 'F': 15, + 'a': 10, + 'b': 11, + 'c': 12, + 'd': 13, + 'e': 14, + 'f': 15, +} + +// index is like bytes.Index(s, []byte(t)) but avoids the allocation. +func index(s []byte, t string) int { + i := 0 + for { + j := bytes.IndexByte(s[i:], t[0]) + if j < 0 { + return -1 + } + i = i + j + if i+len(t) > len(s) { + return -1 + } + for k := 1; k < len(t); k++ { + if s[i+k] != t[k] { + goto nomatch + } + } + return i + nomatch: + i++ + } +} + +// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s. +// If s must be rewritten, it is rewritten in place. +func fixSpace(s []byte) []byte { + s = trimSpace(s) + for i := 0; i < len(s); i++ { + if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' { + goto Fix + } + } + return s + +Fix: + b := s + w := 0 + for i := 0; i < len(s); i++ { + c := s[i] + if c == '\t' || c == '\n' { + c = ' ' + } + if c == ' ' && w > 0 && b[w-1] == ' ' { + continue + } + b[w] = c + w++ + } + if w > 0 && b[w-1] == ' ' { + w-- + } + return b[:w] +} + +// trimSpace trims leading and trailing space from s, returning a subslice of s. +func trimSpace(s []byte) []byte { + j := len(s) + for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') { + j-- + } + i := 0 + for i < j && (s[i] == ' ' || s[i] == '\t') { + i++ + } + return s[i:j] +} + +// pcrel matches instructions using relative addressing mode. +var ( + pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bl)x?(?:eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le)?) 0x([0-9a-f]+)$`) +) + +// Generators. +// +// The test cases are described as functions that invoke a callback repeatedly, +// with a new input sequence each time. These helpers make writing those +// a little easier. + +// condCases generates conditional instructions. +func condCases(t *testing.T) func(func([]byte)) { + return func(try func([]byte)) { + // All the strides are relatively prime to 2 and therefore to 2²⁸, + // so we will not repeat any instructions until we have tried all 2²⁸. + // Using a stride other than 1 is meant to visit the instructions in a + // pseudorandom order, which gives better variety in the set of + // test cases chosen by -printtests. + stride := uint32(10007) + n := 1 << 28 / 7 + if testing.Short() { + stride = 100003 + n = 1 << 28 / 1001 + } else if *longTest { + stride = 200000033 + n = 1 << 28 + } + x := uint32(0) + for i := 0; i < n; i++ { + enc := (x%15)<<28 | x&(1<<28-1) + try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)}) + x += stride + } + } +} + +// uncondCases generates unconditional instructions. +func uncondCases(t *testing.T) func(func([]byte)) { + return func(try func([]byte)) { + condCases(t)(func(enc []byte) { + enc[3] |= 0xF0 + try(enc) + }) + } +} + +func countBits(x uint32) int { + n := 0 + for ; x != 0; x >>= 1 { + n += int(x & 1) + } + return n +} + +func expandBits(x, m uint32) uint32 { + var out uint32 + for i := uint(0); i < 32; i++ { + out >>= 1 + if m&1 != 0 { + out |= (x & 1) << 31 + x >>= 1 + } + m >>= 1 + } + return out +} + +func tryCondMask(mask, val uint32, try func([]byte)) { + n := countBits(^mask) + bits := uint32(0) + for i := 0; i < 1<> 8), byte(x >> 16), byte(x >> 24)}) + } +} + +// vfpCases generates VFP instructions. +func vfpCases(t *testing.T) func(func([]byte)) { + const ( + vfpmask uint32 = 0xFF00FE10 + vfp uint32 = 0x0E009A00 + ) + return func(try func([]byte)) { + tryCondMask(0xff00fe10, 0x0e009a00, try) // standard VFP instruction space + tryCondMask(0xffc00f7f, 0x0e000b10, try) // VFP MOV core reg to/from float64 half + tryCondMask(0xffe00f7f, 0x0e000a10, try) // VFP MOV core reg to/from float32 + tryCondMask(0xffef0fff, 0x0ee10a10, try) // VFP MOV core reg to/from cond codes + } +} + +// hexCases generates the cases written in hexadecimal in the encoded string. +// Spaces in 'encoded' separate entire test cases, not individual bytes. +func hexCases(t *testing.T, encoded string) func(func([]byte)) { + return func(try func([]byte)) { + for _, x := range strings.Fields(encoded) { + src, err := hex.DecodeString(x) + if err != nil { + t.Errorf("parsing %q: %v", x, err) + } + try(src) + } + } +} + +// testdataCases generates the test cases recorded in testdata/decode.txt. +// It only uses the inputs; it ignores the answers recorded in that file. +func testdataCases(t *testing.T) func(func([]byte)) { + var codes [][]byte + data, err := ioutil.ReadFile("testdata/decode.txt") + if err != nil { + t.Fatal(err) + } + for _, line := range strings.Split(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.Fields(line)[0] + i := strings.Index(f, "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f) + } + code, err := hex.DecodeString(f[:i] + f[i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f, err) + continue + } + codes = append(codes, code) + } + + return func(try func([]byte)) { + for _, code := range codes { + try(code) + } + } +} + +func caller(skip int) string { + pc, _, _, _ := runtime.Caller(skip) + f := runtime.FuncForPC(pc) + name := "?" + if f != nil { + name = f.Name() + if i := strings.LastIndex(name, "."); i >= 0 { + name = name[i+1:] + } + } + return name +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/gnu.go b/src/cmd/internal/rsc.io/arm/armasm/gnu.go new file mode 100644 index 000000000..1a97a5a84 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/gnu.go @@ -0,0 +1,164 @@ +// Copyright 2014 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. + +package armasm + +import ( + "bytes" + "fmt" + "strings" +) + +var saveDot = strings.NewReplacer( + ".F16", "_dot_F16", + ".F32", "_dot_F32", + ".F64", "_dot_F64", + ".S32", "_dot_S32", + ".U32", "_dot_U32", + ".FXS", "_dot_S", + ".FXU", "_dot_U", + ".32", "_dot_32", +) + +// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. +// This form typically matches the syntax defined in the ARM Reference Manual. +func GNUSyntax(inst Inst) string { + var buf bytes.Buffer + op := inst.Op.String() + op = saveDot.Replace(op) + op = strings.Replace(op, ".", "", -1) + op = strings.Replace(op, "_dot_", ".", -1) + op = strings.ToLower(op) + buf.WriteString(op) + sep := " " + for i, arg := range inst.Args { + if arg == nil { + break + } + text := gnuArg(&inst, i, arg) + if text == "" { + continue + } + buf.WriteString(sep) + sep = ", " + buf.WriteString(text) + } + return buf.String() +} + +func gnuArg(inst *Inst, argIndex int, arg Arg) string { + switch inst.Op &^ 15 { + case LDRD_EQ, LDREXD_EQ, STRD_EQ: + if argIndex == 1 { + // second argument in consecutive pair not printed + return "" + } + case STREXD_EQ: + if argIndex == 2 { + // second argument in consecutive pair not printed + return "" + } + } + + switch arg := arg.(type) { + case Imm: + switch inst.Op &^ 15 { + case BKPT_EQ: + return fmt.Sprintf("%#04x", uint32(arg)) + case SVC_EQ: + return fmt.Sprintf("%#08x", uint32(arg)) + } + return fmt.Sprintf("#%d", int32(arg)) + + case ImmAlt: + return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot) + + case Mem: + R := gnuArg(inst, -1, arg.Base) + X := "" + if arg.Sign != 0 { + X = "" + if arg.Sign < 0 { + X = "-" + } + X += gnuArg(inst, -1, arg.Index) + if arg.Shift == ShiftLeft && arg.Count == 0 { + // nothing + } else if arg.Shift == RotateRightExt { + X += ", rrx" + } else { + X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count) + } + } else { + X = fmt.Sprintf("#%d", arg.Offset) + } + + switch arg.Mode { + case AddrOffset: + if X == "#0" { + return fmt.Sprintf("[%s]", R) + } + return fmt.Sprintf("[%s, %s]", R, X) + case AddrPreIndex: + return fmt.Sprintf("[%s, %s]!", R, X) + case AddrPostIndex: + return fmt.Sprintf("[%s], %s", R, X) + case AddrLDM: + if X == "#0" { + return R + } + case AddrLDM_WB: + if X == "#0" { + return R + "!" + } + } + return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X) + + case PCRel: + return fmt.Sprintf(".%+#x", int32(arg)+4) + + case Reg: + switch inst.Op &^ 15 { + case LDREX_EQ: + if argIndex == 0 { + return fmt.Sprintf("r%d", int32(arg)) + } + } + switch arg { + case R10: + return "sl" + case R11: + return "fp" + case R12: + return "ip" + } + + case RegList: + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if arg&(1<= Op(len(opstr)) || opstr[op] == "" { + return fmt.Sprintf("Op(%d)", int(op)) + } + return opstr[op] +} + +// An Inst is a single instruction. +type Inst struct { + Op Op // Opcode mnemonic + Enc uint32 // Raw encoding bits. + Len int // Length of encoding in bytes. + Args Args // Instruction arguments, in ARM manual order. +} + +func (i Inst) String() string { + var buf bytes.Buffer + buf.WriteString(i.Op.String()) + for j, arg := range i.Args { + if arg == nil { + break + } + if j == 0 { + buf.WriteString(" ") + } else { + buf.WriteString(", ") + } + buf.WriteString(arg.String()) + } + return buf.String() +} + +// An Args holds the instruction arguments. +// If an instruction has fewer than 4 arguments, +// the final elements in the array are nil. +type Args [4]Arg + +// An Arg is a single instruction argument, one of these types: +// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg. +type Arg interface { + IsArg() + String() string +} + +type Float32Imm float32 + +func (Float32Imm) IsArg() {} + +func (f Float32Imm) String() string { + return fmt.Sprintf("#%v", float32(f)) +} + +type Float64Imm float32 + +func (Float64Imm) IsArg() {} + +func (f Float64Imm) String() string { + return fmt.Sprintf("#%v", float64(f)) +} + +// An Imm is an integer constant. +type Imm uint32 + +func (Imm) IsArg() {} + +func (i Imm) String() string { + return fmt.Sprintf("#%#x", uint32(i)) +} + +// A ImmAlt is an alternate encoding of an integer constant. +type ImmAlt struct { + Val uint8 + Rot uint8 +} + +func (ImmAlt) IsArg() {} + +func (i ImmAlt) Imm() Imm { + v := uint32(i.Val) + r := uint(i.Rot) + return Imm(v>>r | v<<(32-r)) +} + +func (i ImmAlt) String() string { + return fmt.Sprintf("#%#x, %d", i.Val, i.Rot) +} + +// A Label is a text (code) address. +type Label uint32 + +func (Label) IsArg() {} + +func (i Label) String() string { + return fmt.Sprintf("%#x", uint32(i)) +} + +// A Reg is a single register. +// The zero value denotes R0, not the absence of a register. +type Reg uint8 + +const ( + R0 Reg = iota + R1 + R2 + R3 + R4 + R5 + R6 + R7 + R8 + R9 + R10 + R11 + R12 + R13 + R14 + R15 + + S0 + S1 + S2 + S3 + S4 + S5 + S6 + S7 + S8 + S9 + S10 + S11 + S12 + S13 + S14 + S15 + S16 + S17 + S18 + S19 + S20 + S21 + S22 + S23 + S24 + S25 + S26 + S27 + S28 + S29 + S30 + S31 + + D0 + D1 + D2 + D3 + D4 + D5 + D6 + D7 + D8 + D9 + D10 + D11 + D12 + D13 + D14 + D15 + D16 + D17 + D18 + D19 + D20 + D21 + D22 + D23 + D24 + D25 + D26 + D27 + D28 + D29 + D30 + D31 + + APSR + APSR_nzcv + FPSCR + + SP = R13 + LR = R14 + PC = R15 +) + +func (Reg) IsArg() {} + +func (r Reg) String() string { + switch r { + case APSR: + return "APSR" + case APSR_nzcv: + return "APSR_nzcv" + case FPSCR: + return "FPSCR" + case SP: + return "SP" + case PC: + return "PC" + case LR: + return "LR" + } + if R0 <= r && r <= R15 { + return fmt.Sprintf("R%d", int(r-R0)) + } + if S0 <= r && r <= S31 { + return fmt.Sprintf("S%d", int(r-S0)) + } + if D0 <= r && r <= D31 { + return fmt.Sprintf("D%d", int(r-D0)) + } + return fmt.Sprintf("Reg(%d)", int(r)) +} + +// A RegX represents a fraction of a multi-value register. +// The Index field specifies the index number, +// but the size of the fraction is not specified. +// It must be inferred from the instruction and the register type. +// For example, in a VMOV instruction, RegX{D5, 1} represents +// the top 32 bits of the 64-bit D5 register. +type RegX struct { + Reg Reg + Index int +} + +func (RegX) IsArg() {} + +func (r RegX) String() string { + return fmt.Sprintf("%s[%d]", r.Reg, r.Index) +} + +// A RegList is a register list. +// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list. +type RegList uint16 + +func (RegList) IsArg() {} + +func (r RegList) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if r&(1<= 4 { + raw := binary.LittleEndian.Uint32(dec.enc[:4]) + + // word 21FFF0B5. + // the manual is clear that this is pre-indexed mode (with !) but libopcodes generates post-index (without !). + if raw&0x01200000 == 0x01200000 && strings.Replace(text, "!", "", -1) == dec.text { + return true + } + + // word C100543E: libopcodes says tst, but no evidence for that. + if strings.HasPrefix(dec.text, "tst") && raw&0x0ff00000 != 0x03100000 && raw&0x0ff00000 != 0x01100000 { + return true + } + + // word C3203CE8: libopcodes says teq, but no evidence for that. + if strings.HasPrefix(dec.text, "teq") && raw&0x0ff00000 != 0x03300000 && raw&0x0ff00000 != 0x01300000 { + return true + } + + // word D14C552E: libopcodes says cmp but no evidence for that. + if strings.HasPrefix(dec.text, "cmp") && raw&0x0ff00000 != 0x03500000 && raw&0x0ff00000 != 0x01500000 { + return true + } + + // word 2166AA4A: libopcodes says cmn but no evidence for that. + if strings.HasPrefix(dec.text, "cmn") && raw&0x0ff00000 != 0x03700000 && raw&0x0ff00000 != 0x01700000 { + return true + } + + // word E70AEEEF: libopcodes says str but no evidence for that. + if strings.HasPrefix(dec.text, "str") && len(dec.text) >= 5 && (dec.text[3] == ' ' || dec.text[5] == ' ') && raw&0x0e500018 != 0x06000000 && raw&0x0e500000 != 0x0400000 { + return true + } + + // word B0AF48F4: libopcodes says strd but P=0,W=1 which is unpredictable. + if hasPrefix(dec.text, "ldr", "str") && raw&0x01200000 == 0x00200000 { + return true + } + + // word B6CC1C76: libopcodes inexplicably says 'uxtab16lt r1, ip, r6, ROR #24' instead of 'uxtab16lt r1, ip, r6, ror #24' + if strings.ToLower(dec.text) == text { + return true + } + + // word F410FDA1: libopcodes says PLDW but the manual is clear that PLDW is F5/F7, not F4. + // word F7D0FB17: libopcodes says PLDW but the manual is clear that PLDW has 0x10 clear + if hasPrefix(dec.text, "pld") && raw&0xfd000010 != 0xf5000000 { + return true + } + + // word F650FE14: libopcodes says PLI but the manual is clear that PLI has 0x10 clear + if hasPrefix(dec.text, "pli") && raw&0xff000010 != 0xf6000000 { + return true + } + } + + return false +} + +// Instructions known to libopcodes (or xed) but not to us. +// Most of these are floating point coprocessor instructions. +var unsupported = strings.Fields(` + abs + acs + adf + aes + asn + atn + cdp + cf + cmf + cnf + cos + cps + crc32 + dvf + eret + exp + fadd + fcmp + fcpy + fcvt + fdiv + fdv + fix + fld + flt + fmac + fmd + fml + fmr + fms + fmul + fmx + fneg + fnm + frd + fsit + fsq + fst + fsu + fto + fui + hlt + hvc + lda + ldc + ldf + lfm + lgn + log + mar + mcr + mcrr + mia + mnf + mra + mrc + mrrc + mrs + msr + msr + muf + mvf + nrm + pol + pow + rdf + rfc + rfe + rfs + rmf + rnd + rpw + rsf + sdiv + sev + sfm + sha1 + sha256 + sin + smc + sqt + srs + stc + stf + stl + suf + tan + udf + udiv + urd + vfma + vfms + vfnma + vfnms + vrint + wfc + wfs +`) diff --git a/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go b/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go new file mode 100644 index 000000000..d88c67fc0 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go @@ -0,0 +1,260 @@ +// Copyright 2014 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. + +// Copied and simplified from rsc.io/x86/x86asm/objdumpext_test.go. + +package armasm + +import ( + "bytes" + "debug/elf" + "encoding/binary" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + "testing" +) + +const objdumpPath = "/usr/local/bin/arm-linux-elf-objdump" + +func testObjdumpARM(t *testing.T, generate func(func([]byte))) { + testObjdumpArch(t, generate, ModeARM) +} + +func testObjdumpArch(t *testing.T, generate func(func([]byte)), arch Mode) { + if testing.Short() { + t.Skip("skipping objdump test in short mode") + } + + if _, err := os.Stat(objdumpPath); err != nil { + t.Fatal(err) + } + + testExtDis(t, "gnu", arch, objdump, generate, allowedMismatchObjdump) +} + +func objdump(ext *ExtDis) error { + // File already written with instructions; add ELF header. + if ext.Arch == ModeARM { + if err := writeELF32(ext.File, ext.Size); err != nil { + return err + } + } else { + panic("unknown arch") + } + + b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name()) + if err != nil { + return err + } + + var ( + nmatch int + reading bool + next uint32 = start + addr uint32 + encbuf [4]byte + enc []byte + text string + ) + flush := func() { + if addr == next { + if m := pcrel.FindStringSubmatch(text); m != nil { + targ, _ := strconv.ParseUint(m[2], 16, 64) + text = fmt.Sprintf("%s .%+#x", m[1], int32(uint32(targ)-addr-uint32(len(enc)))) + } + if strings.HasPrefix(text, "stmia") { + text = "stm" + text[5:] + } + if strings.HasPrefix(text, "stmfd") { + text = "stmdb" + text[5:] + } + if strings.HasPrefix(text, "ldmfd") { + text = "ldm" + text[5:] + } + text = strings.Replace(text, "#0.0", "#0", -1) + if text == "undefined" && len(enc) == 4 { + text = "error: unknown instruction" + enc = nil + } + if len(enc) == 4 { + // prints as word but we want to record bytes + enc[0], enc[3] = enc[3], enc[0] + enc[1], enc[2] = enc[2], enc[1] + } + ext.Dec <- ExtInst{addr, encbuf, len(enc), text} + encbuf = [4]byte{} + enc = nil + next += 4 + } + } + var textangle = []byte("<.text>:") + for { + line, err := b.ReadSlice('\n') + if err != nil { + if err == io.EOF { + break + } + return fmt.Errorf("reading objdump output: %v", err) + } + if bytes.Contains(line, textangle) { + reading = true + continue + } + if !reading { + continue + } + if debug { + os.Stdout.Write(line) + } + if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil { + enc = enc1 + continue + } + flush() + nmatch++ + addr, enc, text = parseLine(line, encbuf[:0]) + if addr > next { + return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line) + } + } + flush() + if next != start+uint32(ext.Size) { + return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size) + } + if err := ext.Wait(); err != nil { + return fmt.Errorf("exec: %v", err) + } + + return nil +} + +var ( + undefined = []byte("") + unpredictable = []byte("") + illegalShifter = []byte("") +) + +func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) { + oline := line + i := index(line, ":\t") + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32) + if err != nil { + log.Fatalf("cannot parse disassembly: %q", oline) + } + addr = uint32(x) + line = line[i+2:] + i = bytes.IndexByte(line, '\t') + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + enc, ok := parseHex(line[:i], encstart) + if !ok { + log.Fatalf("cannot parse disassembly: %q", oline) + } + line = trimSpace(line[i:]) + if bytes.Contains(line, undefined) { + text = "undefined" + return + } + if bytes.Contains(line, illegalShifter) { + text = "undefined" + return + } + if false && bytes.Contains(line, unpredictable) { + text = "unpredictable" + return + } + if i := bytes.IndexByte(line, ';'); i >= 0 { + line = trimSpace(line[:i]) + } + text = string(fixSpace(line)) + return +} + +func parseContinuation(line []byte, enc []byte) []byte { + i := index(line, ":\t") + if i < 0 { + return nil + } + line = line[i+1:] + enc, _ = parseHex(line, enc) + return enc +} + +// writeELF32 writes an ELF32 header to the file, +// describing a text segment that starts at start +// and extends for size bytes. +func writeELF32(f *os.File, size int) error { + f.Seek(0, 0) + var hdr elf.Header32 + var prog elf.Prog32 + var sect elf.Section32 + var buf bytes.Buffer + binary.Write(&buf, binary.LittleEndian, &hdr) + off1 := buf.Len() + binary.Write(&buf, binary.LittleEndian, &prog) + off2 := buf.Len() + binary.Write(&buf, binary.LittleEndian, §) + off3 := buf.Len() + buf.Reset() + data := byte(elf.ELFDATA2LSB) + hdr = elf.Header32{ + Ident: [16]byte{0x7F, 'E', 'L', 'F', 1, data, 1}, + Type: 2, + Machine: uint16(elf.EM_ARM), + Version: 1, + Entry: start, + Phoff: uint32(off1), + Shoff: uint32(off2), + Flags: 0x05000002, + Ehsize: uint16(off1), + Phentsize: uint16(off2 - off1), + Phnum: 1, + Shentsize: uint16(off3 - off2), + Shnum: 3, + Shstrndx: 2, + } + binary.Write(&buf, binary.LittleEndian, &hdr) + prog = elf.Prog32{ + Type: 1, + Off: start, + Vaddr: start, + Paddr: start, + Filesz: uint32(size), + Memsz: uint32(size), + Flags: 5, + Align: start, + } + binary.Write(&buf, binary.LittleEndian, &prog) + binary.Write(&buf, binary.LittleEndian, §) // NULL section + sect = elf.Section32{ + Name: 1, + Type: uint32(elf.SHT_PROGBITS), + Addr: start, + Off: start, + Size: uint32(size), + Flags: uint32(elf.SHF_ALLOC | elf.SHF_EXECINSTR), + Addralign: 4, + } + binary.Write(&buf, binary.LittleEndian, §) // .text + sect = elf.Section32{ + Name: uint32(len("\x00.text\x00")), + Type: uint32(elf.SHT_STRTAB), + Addr: 0, + Off: uint32(off2 + (off3-off2)*3), + Size: uint32(len("\x00.text\x00.shstrtab\x00")), + Addralign: 1, + } + binary.Write(&buf, binary.LittleEndian, §) + buf.WriteString("\x00.text\x00.shstrtab\x00") + f.Write(buf.Bytes()) + return nil +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/plan9x.go b/src/cmd/internal/rsc.io/arm/armasm/plan9x.go new file mode 100644 index 000000000..952c5190b --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/plan9x.go @@ -0,0 +1,211 @@ +// Copyright 2014 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. + +package armasm + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "strings" +) + +// Plan9Syntax returns the Go assembler syntax for the instruction. +// The syntax was originally defined by Plan 9. +// The pc is the program counter of the instruction, used for expanding +// PC-relative addresses into absolute ones. +// The symname function queries the symbol table for the program +// being disassembled. Given a target address it returns the name and base +// address of the symbol containing the target, if any; otherwise it returns "", 0. +// The reader r should read from the text segment using text addresses +// as offsets; it is used to display pc-relative loads as constant loads. +func Plan9Syntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string { + if symname == nil { + symname = func(uint64) (string, uint64) { return "", 0 } + } + + var args []string + for _, a := range inst.Args { + if a == nil { + break + } + args = append(args, plan9Arg(&inst, pc, symname, a)) + } + + op := inst.Op.String() + + switch inst.Op &^ 15 { + case LDR_EQ, LDRB_EQ, LDRH_EQ: + // Check for RET + reg, _ := inst.Args[0].(Reg) + mem, _ := inst.Args[1].(Mem) + if inst.Op&^15 == LDR_EQ && reg == R15 && mem.Base == SP && mem.Sign == 0 && mem.Mode == AddrPostIndex { + return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset) + } + + // Check for PC-relative load. + if mem.Base == PC && mem.Sign == 0 && mem.Mode == AddrOffset && text != nil { + addr := uint32(pc) + 8 + uint32(mem.Offset) + buf := make([]byte, 4) + switch inst.Op &^ 15 { + case LDRB_EQ: + if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil { + break + } + args[1] = fmt.Sprintf("$%#x", buf[0]) + + case LDRH_EQ: + if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil { + break + } + args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf)) + + case LDR_EQ: + if _, err := text.ReadAt(buf, int64(addr)); err != nil { + break + } + x := binary.LittleEndian.Uint32(buf) + if s, base := symname(uint64(x)); s != "" && uint64(x) == base { + args[1] = fmt.Sprintf("$%s(SB)", s) + } else { + args[1] = fmt.Sprintf("$%#x", x) + } + } + } + } + + // Move addressing mode into opcode suffix. + suffix := "" + switch inst.Op &^ 15 { + case LDR_EQ, LDRB_EQ, LDRH_EQ, STR_EQ, STRB_EQ, STRH_EQ: + mem, _ := inst.Args[1].(Mem) + switch mem.Mode { + case AddrOffset, AddrLDM: + // no suffix + case AddrPreIndex, AddrLDM_WB: + suffix = ".W" + case AddrPostIndex: + suffix = ".P" + } + off := "" + if mem.Offset != 0 { + off = fmt.Sprintf("%#x", mem.Offset) + } + base := fmt.Sprintf("(R%d)", int(mem.Base)) + index := "" + if mem.Sign != 0 { + sign := "" + if mem.Sign < 0 { + sign = "" + } + shift := "" + if mem.Count != 0 { + shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count) + } + index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift) + } + args[1] = off + base + index + } + + // Reverse args, placing dest last. + for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { + args[i], args[j] = args[j], args[i] + } + + switch inst.Op &^ 15 { + case MOV_EQ: + op = "MOVW" + op[3:] + + case LDR_EQ: + op = "MOVW" + op[3:] + suffix + case LDRB_EQ: + op = "MOVB" + op[4:] + suffix + case LDRH_EQ: + op = "MOVH" + op[4:] + suffix + + case STR_EQ: + op = "MOVW" + op[3:] + suffix + args[0], args[1] = args[1], args[0] + case STRB_EQ: + op = "MOVB" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + case STRH_EQ: + op = "MOVH" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + } + + if args != nil { + op += " " + strings.Join(args, ", ") + } + + return op +} + +// assembler syntax for the various shifts. +// @x> is a lie; the assembler uses @> 0 +// instead of @x> 1, but i wanted to be clear that it +// was a different operation (rotate right extended, not rotate right). +var plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"} + +func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { + switch a := arg.(type) { + case Endian: + + case Imm: + return fmt.Sprintf("$%d", int(a)) + + case Mem: + + case PCRel: + addr := uint32(pc) + 8 + uint32(a) + if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { + return fmt.Sprintf("%s(SB)", s) + } + return fmt.Sprintf("%#x", addr) + + case Reg: + if a < 16 { + return fmt.Sprintf("R%d", int(a)) + } + + case RegList: + var buf bytes.Buffer + start := -2 + end := -2 + fmt.Fprintf(&buf, "[") + flush := func() { + if start >= 0 { + if buf.Len() > 1 { + fmt.Fprintf(&buf, ",") + } + if start == end { + fmt.Fprintf(&buf, "R%d", start) + } else { + fmt.Fprintf(&buf, "R%d-R%d", start, end) + } + } + } + for i := 0; i < 16; i++ { + if a&(1< ,,# cond:4|0|0|1|0|1|0|1|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00a00010, 4, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADC{S} ,,, cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00a00000, 2, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADC{S} ,,{,} cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // ADD{S} ,,# cond:4|0|0|1|0|1|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00800010, 4, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADD{S} ,,, cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADD{S} ,,{,} cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0000, 0x028d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_const}}, // ADD{S} ,SP,# cond:4|0|0|1|0|1|0|0|S|1|1|0|1|Rd:4|imm12:12 + {0x0fef0010, 0x008d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_R_shift_imm}}, // ADD{S} ,SP,{,} cond:4|0|0|0|0|1|0|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // AND{S} ,,# cond:4|0|0|1|0|0|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00000010, 4, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // AND{S} ,,, cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // AND{S} ,,{,} cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0070, 0x01a00040, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_imm5_32}}, // ASR{S} ,,# cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|0|0|Rm:4 + {0x0fef00f0, 0x01a00050, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_R_8}}, // ASR{S} ,, cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|0|1|Rn:4 + {0x0f000000, 0x0a000000, 4, B_EQ, 0x1c04, instArgs{arg_label24}}, // B cond:4|1|0|1|0|imm24:24 + {0x0fe0007f, 0x07c0001f, 4, BFC_EQ, 0x1c04, instArgs{arg_R_12, arg_imm5, arg_lsb_width}}, // BFC ,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|1|1|1|1 + {0x0fe00070, 0x07c00010, 2, BFI_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0, arg_imm5, arg_lsb_width}}, // BFI ,,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|Rn:4 + {0x0fe00000, 0x03c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // BIC{S} ,,# cond:4|0|0|1|1|1|1|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x01c00010, 4, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // BIC{S} ,,, cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x01c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // BIC{S} ,,{,} cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0ff000f0, 0x01200070, 4, BKPT_EQ, 0x1c04, instArgs{arg_imm_12at8_4at0}}, // BKPT # cond:4|0|0|0|1|0|0|1|0|imm12:12|0|1|1|1|imm4:4 + {0x0f000000, 0x0b000000, 4, BL_EQ, 0x1c04, instArgs{arg_label24}}, // BL cond:4|1|0|1|1|imm24:24 + {0xfe000000, 0xfa000000, 4, BLX, 0x0, instArgs{arg_label24H}}, // BLX 1|1|1|1|1|0|1|H|imm24:24 + {0x0ffffff0, 0x012fff30, 4, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ff000f0, 0x012fff30, 3, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ffffff0, 0x012fff10, 4, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x012fff10, 3, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ffffff0, 0x012fff20, 4, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0x0ff000f0, 0x012fff20, 3, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0xffffffff, 0xf57ff01f, 4, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0xfff000f0, 0xf57ff01f, 3, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0x0fff0ff0, 0x016f0f10, 4, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x016f0f10, 3, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff0f000, 0x03700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01700010, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01700010, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff0f000, 0x03500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01500010, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01500010, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ffffff0, 0x0320f0f0, 4, DBG_EQ, 0x1c04, instArgs{arg_option}}, // DBG #