summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5a/lex.c2
-rw-r--r--src/cmd/5g/gg.h1
-rw-r--r--src/cmd/5g/gsubr.c3
-rw-r--r--src/cmd/5g/reg.c184
-rw-r--r--src/cmd/5l/5.out.h4
-rw-r--r--src/cmd/5l/Makefile1
-rw-r--r--src/cmd/5l/asm.c117
-rw-r--r--src/cmd/5l/l.h25
-rw-r--r--src/cmd/5l/list.c7
-rw-r--r--src/cmd/5l/noop.c385
-rw-r--r--src/cmd/5l/obj.c28
-rw-r--r--src/cmd/5l/optab.c57
-rw-r--r--src/cmd/5l/pass.c20
-rw-r--r--src/cmd/5l/prof.c9
-rw-r--r--src/cmd/5l/softfloat.c2
-rw-r--r--src/cmd/5l/span.c234
-rw-r--r--src/cmd/5l/thumb.c1658
-rw-r--r--src/cmd/6g/gg.h1
-rw-r--r--src/cmd/6g/gsubr.c4
-rw-r--r--src/cmd/6g/reg.c155
-rw-r--r--src/cmd/6l/asm.c43
-rw-r--r--src/cmd/8g/gg.h1
-rw-r--r--src/cmd/8g/gsubr.c3
-rw-r--r--src/cmd/8g/reg.c111
-rw-r--r--src/cmd/8l/asm.c27
-rw-r--r--src/cmd/8l/l.h11
-rw-r--r--src/cmd/cgo/gcc.go18
-rw-r--r--src/cmd/gc/dcl.c14
-rw-r--r--src/cmd/gc/gen.c18
-rw-r--r--src/cmd/gc/go.h16
-rw-r--r--src/cmd/gc/go.y19
-rw-r--r--src/cmd/gc/lex.c6
-rw-r--r--src/cmd/gc/pgen.c115
-rw-r--r--src/cmd/gc/print.c4
-rw-r--r--src/cmd/gc/subr.c90
-rw-r--r--src/cmd/gc/typecheck.c296
-rw-r--r--src/cmd/gc/walk.c292
-rw-r--r--src/cmd/godefs/a.h1
-rw-r--r--src/cmd/godefs/main.c14
-rw-r--r--src/cmd/godefs/stabs.c10
-rw-r--r--src/cmd/godoc/spec.go7
-rw-r--r--src/cmd/gofix/main.go8
-rw-r--r--src/cmd/gofmt/gofmt.go9
-rwxr-xr-xsrc/cmd/gofmt/test.sh2
-rw-r--r--src/cmd/gopack/ar.c20
-rw-r--r--src/cmd/ld/dwarf.c35
-rw-r--r--src/cmd/ld/go.c4
-rw-r--r--src/cmd/ld/lib.c31
-rw-r--r--src/cmd/ld/lib.h3
-rw-r--r--src/cmd/ld/symtab.c78
-rw-r--r--src/libmach/8db.c1682
-rw-r--r--src/libmach/obj.c22
-rw-r--r--src/pkg/Makefile12
-rwxr-xr-xsrc/pkg/big/int.go8
-rwxr-xr-xsrc/pkg/big/int_test.go6
-rwxr-xr-xsrc/pkg/big/nat.go128
-rwxr-xr-xsrc/pkg/big/nat_test.go213
-rw-r--r--src/pkg/big/rat.go49
-rw-r--r--src/pkg/big/rat_test.go39
-rw-r--r--src/pkg/compress/lzw/reader.go226
-rw-r--r--src/pkg/compress/lzw/writer_test.go8
-rw-r--r--src/pkg/crypto/ocsp/ocsp.go23
-rw-r--r--src/pkg/crypto/rsa/rsa.go2
-rw-r--r--src/pkg/crypto/tls/tls.go2
-rw-r--r--src/pkg/crypto/twofish/twofish.go2
-rw-r--r--src/pkg/crypto/x509/cert_pool.go3
-rw-r--r--src/pkg/crypto/x509/crl/crl.go96
-rw-r--r--src/pkg/crypto/x509/crl/crl_test.go63
-rw-r--r--src/pkg/crypto/x509/pkix/Makefile (renamed from src/pkg/crypto/x509/crl/Makefile)4
-rw-r--r--src/pkg/crypto/x509/pkix/pkix.go167
-rw-r--r--src/pkg/crypto/x509/x509.go361
-rw-r--r--src/pkg/crypto/x509/x509_test.go102
-rw-r--r--src/pkg/ebnf/ebnf.go9
-rw-r--r--src/pkg/ebnf/ebnf_test.go33
-rw-r--r--src/pkg/ebnf/parser.go19
-rw-r--r--src/pkg/exec/exec.go20
-rw-r--r--src/pkg/exp/gui/Makefile11
-rw-r--r--src/pkg/exp/gui/gui.go (renamed from src/pkg/exp/draw/event.go)6
-rw-r--r--src/pkg/exp/gui/x11/Makefile (renamed from src/pkg/exp/draw/x11/Makefile)2
-rw-r--r--src/pkg/exp/gui/x11/auth.go (renamed from src/pkg/exp/draw/x11/auth.go)0
-rw-r--r--src/pkg/exp/gui/x11/conn.go (renamed from src/pkg/exp/draw/x11/conn.go)27
-rw-r--r--src/pkg/fmt/fmt_test.go14
-rw-r--r--src/pkg/go/build/Makefile22
-rw-r--r--src/pkg/go/build/build.go272
-rw-r--r--src/pkg/go/build/build_test.go57
-rw-r--r--src/pkg/go/build/cgotest/file.go45
-rw-r--r--src/pkg/go/build/dir.go173
-rw-r--r--src/pkg/go/build/path.go163
-rw-r--r--src/pkg/go/build/syslist_test.go62
-rw-r--r--src/pkg/go/scanner/scanner_test.go2
-rw-r--r--src/pkg/go/types/gcimporter.go7
-rw-r--r--src/pkg/html/doc.go1
-rw-r--r--src/pkg/html/token.go29
-rw-r--r--src/pkg/html/token_test.go10
-rw-r--r--src/pkg/http/client.go16
-rw-r--r--src/pkg/http/client_test.go16
-rw-r--r--src/pkg/http/httptest/server.go33
-rw-r--r--src/pkg/http/readrequest_test.go4
-rw-r--r--src/pkg/http/request.go67
-rw-r--r--src/pkg/http/requestwrite_test.go36
-rw-r--r--src/pkg/http/serve_test.go44
-rw-r--r--src/pkg/http/server.go19
-rw-r--r--src/pkg/http/transfer.go8
-rw-r--r--src/pkg/http/url.go18
-rw-r--r--src/pkg/http/url_test.go35
-rw-r--r--src/pkg/image/draw/Makefile (renamed from src/pkg/exp/draw/Makefile)3
-rw-r--r--src/pkg/image/draw/clip_test.go193
-rw-r--r--src/pkg/image/draw/draw.go (renamed from src/pkg/exp/draw/draw.go)44
-rw-r--r--src/pkg/image/draw/draw_test.go (renamed from src/pkg/exp/draw/draw_test.go)6
-rw-r--r--src/pkg/image/geom.go19
-rw-r--r--src/pkg/image/gif/reader.go6
-rw-r--r--src/pkg/image/image.go77
-rw-r--r--src/pkg/image/image_test.go71
-rw-r--r--src/pkg/image/tiff/reader.go114
-rw-r--r--src/pkg/image/ycbcr/ycbcr.go2
-rw-r--r--src/pkg/mail/message.go402
-rw-r--r--src/pkg/mail/message_test.go129
-rw-r--r--src/pkg/math/Makefile3
-rw-r--r--src/pkg/math/sqrt_arm.s10
-rw-r--r--src/pkg/math/sqrt_port.go4
-rw-r--r--src/pkg/net/Makefile6
-rw-r--r--src/pkg/net/interface.go89
-rw-r--r--src/pkg/net/interface_bsd.go195
-rw-r--r--src/pkg/net/interface_linux.go208
-rw-r--r--src/pkg/net/interface_stub.go51
-rw-r--r--src/pkg/net/interface_test.go90
-rw-r--r--src/pkg/netchan/import.go45
-rw-r--r--src/pkg/netchan/netchan_test.go10
-rw-r--r--src/pkg/os/Makefile12
-rw-r--r--src/pkg/os/env_plan9.go15
-rw-r--r--src/pkg/os/error_posix.go2
-rw-r--r--src/pkg/os/exec_posix.go25
-rw-r--r--src/pkg/os/exec_unix.go8
-rw-r--r--src/pkg/os/exec_windows.go12
-rwxr-xr-xsrc/pkg/os/mkunixsignals.sh (renamed from src/pkg/os/signal/mkunix.sh)2
-rw-r--r--src/pkg/os/signal/Makefile6
-rw-r--r--src/pkg/os/signal/signal.go25
-rw-r--r--src/pkg/os/signal/signal_test.go5
-rw-r--r--src/pkg/runtime/386/memmove.s12
-rw-r--r--src/pkg/runtime/amd64/memmove.s12
-rw-r--r--src/pkg/runtime/arm/softfloat.c10
-rw-r--r--src/pkg/runtime/linux/386/sys.s8
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s8
-rw-r--r--src/pkg/runtime/linux/arm/sys.s9
-rw-r--r--src/pkg/runtime/linux/mem.c34
-rw-r--r--src/pkg/runtime/runtime.h1
-rw-r--r--src/pkg/runtime/windows/thread.c2
-rw-r--r--src/pkg/strconv/quote.go119
-rw-r--r--src/pkg/strconv/quote_test.go62
-rw-r--r--src/pkg/sync/atomic/asm_arm.s8
-rw-r--r--src/pkg/sync/rwmutex_test.go2
-rw-r--r--src/pkg/syscall/syscall_windows.go9
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go21
-rw-r--r--src/pkg/syscall/ztypes_darwin_386.go4
-rw-r--r--src/pkg/syscall/ztypes_darwin_amd64.go4
-rw-r--r--src/pkg/syscall/ztypes_windows_386.go17
-rw-r--r--src/pkg/template/Makefile4
-rw-r--r--src/pkg/template/doc.go91
-rw-r--r--src/pkg/template/execute.go346
-rw-r--r--src/pkg/template/parse.go (renamed from src/pkg/template/template.go)486
-rw-r--r--src/pkg/testing/benchmark.go9
-rw-r--r--src/pkg/testing/testing.go6
-rw-r--r--src/pkg/unicode/Makefile1
-rw-r--r--src/pkg/unicode/digit.go2
-rw-r--r--src/pkg/unicode/digit_test.go2
-rw-r--r--src/pkg/unicode/graphic.go132
-rw-r--r--src/pkg/unicode/graphic_test.go122
-rw-r--r--src/pkg/unicode/letter.go43
-rw-r--r--src/pkg/unicode/letter_test.go2
-rw-r--r--src/pkg/unicode/maketables.go105
-rw-r--r--src/pkg/unicode/script_test.go17
-rw-r--r--src/pkg/unicode/tables.go1475
172 files changed, 8206 insertions, 5569 deletions
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index a04cda220..3978f1a6c 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -338,6 +338,8 @@ struct
"NRMD", LTYPEI, ANRMD,
*/
+ "SQRTF", LTYPEI, ASQRTF,
+ "SQRTD", LTYPEI, ASQRTD,
"CMPF", LTYPEL, ACMPF,
"CMPD", LTYPEL, ACMPD,
"ADDF", LTYPEK, AADDF,
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index fe404ed79..ce4558e21 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -23,6 +23,7 @@ struct Addr
char sval[NSNAME];
Sym* sym;
+ Node* node;
int width;
uchar type;
char name;
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 83a9949d6..bc39912ea 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1101,6 +1101,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->type = D_NONE;
a->name = D_NONE;
a->reg = NREG;
+ a->node = N;
if(n == N)
return;
@@ -1189,6 +1190,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->name = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 1cbeb3e3d..5fba02c9e 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -32,6 +32,8 @@
#include "gg.h"
#include "opt.h"
+#define NREGVAR 24
+#define REGBITS ((uint32)0xffffff)
#define P2R(p) (Reg*)(p->reg)
void addsplits(void);
@@ -128,6 +130,33 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = {
+ ".R0",
+ ".R1",
+ ".R2",
+ ".R3",
+ ".R4",
+ ".R5",
+ ".R6",
+ ".R7",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".F0",
+ ".F1",
+ ".F2",
+ ".F3",
+ ".F4",
+ ".F5",
+ ".F6",
+ ".F7",
+};
+
void
regopt(Prog *firstp)
{
@@ -136,7 +165,7 @@ regopt(Prog *firstp)
int i, z, nr;
uint32 vreg;
Bits bit;
-
+
if(first == 0) {
fmtinstall('Q', Qconv);
}
@@ -164,7 +193,17 @@ regopt(Prog *firstp)
r1 = R;
firstr = R;
lastr = R;
- nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -223,6 +262,16 @@ regopt(Prog *firstp)
bit = mkvar(r, &p->from);
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
+
+ /*
+ * middle always read when present
+ */
+ if(p->reg != NREG) {
+ if(p->from.type != D_FREG)
+ r->use1.b[0] |= RtoB(p->reg);
+ else
+ r->use1.b[0] |= FtoB(p->reg);
+ }
/*
* right side depends on opcode
@@ -233,6 +282,67 @@ regopt(Prog *firstp)
default:
yyerror("reg: unknown op: %A", p->as);
break;
+
+ /*
+ * right side read
+ */
+ case ATST:
+ case ATEQ:
+ case ACMP:
+ case ACMN:
+ case ACMPD:
+ case ACMPF:
+ rightread:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read or read+write, depending on middle
+ * ADD x, z => z += x
+ * ADD x, y, z => z = x + y
+ */
+ case AADD:
+ case AAND:
+ case AEOR:
+ case ASUB:
+ case ARSB:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ case AORR:
+ case ABIC:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case ADIVU:
+ if(p->reg != NREG)
+ goto rightread;
+ // fall through
+
+ /*
+ * right side read+write
+ */
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case AMULAL:
+ case AMULALU:
+ for(z=0; z<BITS; z++) {
+ r->use2.b[z] |= bit.b[z];
+ r->set.b[z] |= bit.b[z];
+ }
+ break;
/*
* right side write
@@ -240,11 +350,22 @@ regopt(Prog *firstp)
case ANOP:
case AMOVB:
case AMOVBU:
+ case AMOVD:
+ case AMOVDF:
+ case AMOVDW:
+ case AMOVF:
+ case AMOVFW:
case AMOVH:
case AMOVHU:
case AMOVW:
- case AMOVF:
- case AMOVD:
+ case AMOVWD:
+ case AMOVWF:
+ case AMVN:
+ case AMULL:
+ case AMULLU:
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
@@ -397,6 +518,24 @@ loop2:
}
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -606,6 +745,7 @@ addmove(Reg *r, int bn, int rn, int f)
a = &p1->to;
a->sym = v->sym;
a->name = v->name;
+ a->node = v->node;
a->offset = v->offset;
a->etype = v->etype;
a->type = D_OREG;
@@ -715,21 +855,40 @@ mkvar(Reg *r, Adr *a)
goto onereg;
case D_REGREG:
+ bit = zbits;
if(a->offset != NREG)
- r->regu |= RtoB(a->offset);
- goto onereg;
+ bit.b[0] |= RtoB(a->offset);
+ if(a->reg != NREG)
+ bit.b[0] |= RtoB(a->reg);
+ return bit;
case D_REG:
case D_SHIFT:
- case D_OREG:
onereg:
- if(a->reg != NREG)
- r->regu |= RtoB(a->reg);
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = RtoB(a->reg);
+ return bit;
+ }
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG) {
+ if(a == &r->prog->from)
+ r->use1.b[0] |= RtoB(a->reg);
+ else
+ r->use2.b[0] |= RtoB(a->reg);
+ if(r->prog->scond & (C_PBIT|C_WBIT))
+ r->set.b[0] |= RtoB(a->reg);
+ }
break;
case D_FREG:
- if(a->reg != NREG)
- r->regu |= FtoB(a->reg);
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = FtoB(a->reg);
+ return bit;
+ }
break;
}
@@ -795,7 +954,8 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
-
+ v->node = a->node;
+
if(debug['R'])
print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 002b46d45..cf86ae48b 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -53,8 +53,6 @@
#define REGLINK 14
#define REGPC 15
-#define REGTMPT 7 /* used by the loader for thumb code */
-
#define NFREG 8
#define FREGRET 0
#define FREGEXT 7
@@ -126,6 +124,8 @@ enum as
AMULD,
ADIVF,
ADIVD,
+ ASQRTF,
+ ASQRTD,
ASRL,
ASRA,
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index c11ebe990..9f4a192aa 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -22,7 +22,6 @@ OFILES=\
optab.$O\
pass.$O\
prof.$O\
- thumb.$O\
softfloat.$O\
span.$O\
symtab.$O\
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 81c08e353..4afed2b80 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -34,8 +34,6 @@
#include "../ld/lib.h"
#include "../ld/elf.h"
-int32 OFFSET;
-
static Prog *PP;
char linuxdynld[] = "/lib/ld-linux.so.2";
@@ -295,7 +293,7 @@ asmb(void)
{
int32 t;
int a, dynsym;
- uint32 fo, symo, startva, elfsymo, elfstro, elfsymsize;
+ uint32 fo, symo, startva;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -305,10 +303,6 @@ asmb(void)
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- elfsymsize = 0;
- elfstro = 0;
- elfsymo = 0;
-
sect = segtext.sect;
seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
codeblk(sect->vaddr, sect->len);
@@ -361,34 +355,28 @@ asmb(void)
debug['s'] = 1;
break;
case Hplan9x32:
- OFFSET = HEADR+textsize+segdata.filelen;
- seek(cout, OFFSET, 0);
+ symo = HEADR+segtext.len+segdata.filelen;
break;
case Hnetbsd:
- OFFSET += rnd(segdata.filelen, 4096);
- seek(cout, OFFSET, 0);
+ symo = rnd(segdata.filelen, 4096);
break;
ElfSym:
symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
+ seek(cout, symo, 0);
if(iself) {
if(debug['v'])
Bprint(&bso, "%5.2f elfsym\n", cputime());
- elfsymo = symo+8+symsize+lcsize;
- seek(cout, elfsymo, 0);
- asmelfsym32();
+ asmelfsym();
cflush();
- elfstro = seek(cout, 0, 1);
- elfsymsize = elfstro - elfsymo;
ewrite(cout, elfstrdat, elfstrsize);
// if(debug['v'])
// Bprint(&bso, "%5.2f dwarf\n", cputime());
// dwarfemitdebugsections();
}
- asmthumbmap();
cflush();
}
@@ -397,8 +385,7 @@ asmb(void)
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
- OFFSET = 0;
- seek(cout, OFFSET, 0);
+ seek(cout, 0L, 0);
switch(HEADTYPE) {
case Hnoheader: /* no header */
break;
@@ -599,15 +586,15 @@ asmb(void)
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
+ sh->off = symo;
+ sh->size = symsize;
sh->addralign = 4;
sh->entsize = 16;
sh->link = eh->shnum; // link to strtab
sh = newElfShdr(elfstr[ElfStrStrtab]);
sh->type = SHT_STRTAB;
- sh->off = elfstro;
+ sh->off = symo+symsize;
sh->size = elfstrsize;
sh->addralign = 1;
@@ -740,59 +727,6 @@ nopstat(char *f, Count *c)
(double)(c->outof - c->count)/c->outof);
}
-static void
-outt(int32 f, int32 l)
-{
- if(debug['L'])
- Bprint(&bso, "tmap: %ux-%ux\n", f, l);
- lput(f);
- lput(l);
-}
-
-void
-asmthumbmap(void)
-{
- int32 pc, lastt;
- Prog *p;
-
- if(!seenthumb)
- return;
- pc = 0;
- lastt = -1;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- pc = p->pc - INITTEXT;
- setarch(p);
- if(thumb){
- if(p->from.sym->foreign){ // 8 bytes of ARM first
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- pc += 8;
- }
- if(lastt < 0)
- lastt = pc;
- }
- else{
- if(p->from.sym->foreign){ // 4 bytes of THUMB first
- if(lastt < 0)
- lastt = pc;
- pc += 4;
- }
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- }
- if(cursym->next == nil)
- for(; p != P; p = p->link)
- pc = p->pc = INITTEXT;
- }
- if(lastt >= 0)
- outt(lastt, pc+1);
-}
-
void
asmout(Prog *p, Optab *o, int32 *out)
{
@@ -816,7 +750,7 @@ if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
+if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
break;
case 1: /* op R,[R],R */
@@ -880,10 +814,6 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
v = -8;
if(p->cond != P)
v = (p->cond->pc - pc) - 8;
-#ifdef CALLEEBX
- if(p->as == ABL)
- v += fninc(p->to.sym);
-#endif
o1 = opbra(p->as, p->scond);
o1 |= (v >> 2) & 0xffffff;
break;
@@ -1198,7 +1128,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
r = p->reg;
if(r == NREG) {
r = rt;
- if(p->as == AMOVF || p->as == AMOVD)
+ if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD)
r = 0;
}
o1 |= rf | (r<<16) | (rt<<12);
@@ -1340,19 +1270,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o2 ^= (1<<6);
break;
case 74: /* bx $I */
-#ifdef CALLEEBX
- diag("bx $i case (arm)");
-#endif
- if(!seenthumb)
- diag("ABX $I and seenthumb==0");
- v = p->cond->pc;
- if(p->to.sym->thumb)
- v |= 1; // T bit
- o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
- o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
- o4 = opbra(AB, 14); // B over o6
- o5 = v;
+ diag("ABX $I");
break;
case 75: /* bx O(R) */
aclass(&p->to);
@@ -1371,14 +1289,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
break;
case 76: /* bx O(R) when returning from fn*/
- if(!seenthumb)
- diag("ABXRET and seenthumb==0");
- aclass(&p->to);
-// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg);
- if(instoffset != 0)
- diag("non-zero offset in ABXRET");
- // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp
- o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+ diag("ABXRET");
break;
case 77: /* ldrex oreg,reg */
aclass(&p->from);
@@ -1632,6 +1543,8 @@ oprrr(int a, int sc)
case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
+ case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index f3c9d839d..182f3e738 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -144,8 +144,6 @@ struct Sym
int32 sig;
int32 size;
uchar special;
- uchar thumb; // thumb code
- uchar foreign; // called by arm if thumb, by thumb if arm
uchar fnptr; // used as fn ptr
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
@@ -208,7 +206,6 @@ enum
LFROM = 1<<0,
LTO = 1<<1,
LPOOL = 1<<2,
- V4 = 1<<3, /* arm v4 arch */
C_NONE = 0,
C_REG,
@@ -221,21 +218,16 @@ enum
C_RCON, /* 0xff rotated */
C_NCON, /* ~RCON */
C_SCON, /* 0xffff */
- C_BCON, /* thumb */
C_LCON,
C_ZFCON,
C_SFCON,
C_LFCON,
- C_GCON, /* thumb */
C_RACON,
- C_SACON, /* thumb */
C_LACON,
- C_GACON, /* thumb */
C_SBRA,
C_LBRA,
- C_GBRA, /* thumb */
C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
@@ -250,12 +242,10 @@ enum
C_ROREG,
C_SROREG, /* both S and R */
C_LOREG,
- C_GOREG, /* thumb */
C_PC,
C_SP,
C_HREG,
- C_OFFPC, /* thumb */
C_ADDR, /* reference to relocatable address */
@@ -287,9 +277,6 @@ EXTERN union
#define cbuf u.obuf
#define xbuf u.ibuf
-#define setarch(p) if((p)->as==ATEXT) thumb=(p)->reg&ALLTHUMBS
-#define setthumb(p) if((p)->as==ATEXT) seenthumb|=(p)->reg&ALLTHUMBS
-
#ifndef COFFCVT
EXTERN int32 HEADR; /* length of header */
@@ -319,7 +306,6 @@ EXTERN int nerrors;
EXTERN int32 instoffset;
EXTERN Opcross opcross[8];
EXTERN Oprang oprange[ALAST];
-EXTERN Oprang thumboprange[ALAST];
EXTERN char* outfile;
EXTERN int32 pc;
EXTERN uchar repop[ALAST];
@@ -333,14 +319,10 @@ EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
EXTERN Prog zprg;
EXTERN int dtype;
-EXTERN int armv4;
-EXTERN int thumb;
-EXTERN int seenthumb;
EXTERN int armsize;
extern char* anames[];
extern Optab optab[];
-extern Optab thumboptab[];
void addpool(Prog*, Adr*);
EXTERN Prog* blitrl;
@@ -368,17 +350,13 @@ int Oconv(Fmt*);
int Pconv(Fmt*);
int Sconv(Fmt*);
int aclass(Adr*);
-int thumbaclass(Adr*, Prog*);
void addhist(int32, int);
Prog* appendp(Prog*);
void asmb(void);
-void asmthumbmap(void);
void asmout(Prog*, Optab*, int32*);
-void thumbasmout(Prog*, Optab*);
int32 atolwhex(char*);
Prog* brloop(Prog*);
void buildop(void);
-void thumbbuildop(void);
void buildrep(int, int);
void cflush(void);
int chipzero(Ieee*);
@@ -442,9 +420,6 @@ int32 immaddr(int32);
int32 opbra(int, int);
int brextra(Prog*);
int isbranch(Prog*);
-int fnpinc(Sym *);
-int fninc(Sym *);
-void thumbcount(void);
void fnptrs(void);
void doelf(void);
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 2ae25d491..fa838215b 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -412,7 +412,6 @@ static char*
cnames[] =
{
[C_ADDR] = "C_ADDR",
- [C_BCON] = "C_BCON",
[C_FAUTO] = "C_FAUTO",
[C_ZFCON] = "C_SFCON",
[C_SFCON] = "C_SFCON",
@@ -420,11 +419,7 @@ cnames[] =
[C_FCR] = "C_FCR",
[C_FOREG] = "C_FOREG",
[C_FREG] = "C_FREG",
- [C_GACON] = "C_GACON",
- [C_GBRA] = "C_GBRA",
- [C_GCON] = "C_GCON",
[C_GOK] = "C_GOK",
- [C_GOREG] = "C_GOREG",
[C_HAUTO] = "C_HAUTO",
[C_HFAUTO] = "C_HFAUTO",
[C_HFOREG] = "C_HFOREG",
@@ -437,7 +432,6 @@ cnames[] =
[C_LOREG] = "C_LOREG",
[C_NCON] = "C_NCON",
[C_NONE] = "C_NONE",
- [C_OFFPC] = "C_OFFPC",
[C_PC] = "C_PC",
[C_PSR] = "C_PSR",
[C_RACON] = "C_RACON",
@@ -445,7 +439,6 @@ cnames[] =
[C_REG] = "C_REG",
[C_REGREG] = "C_REGREG",
[C_ROREG] = "C_ROREG",
- [C_SACON] = "C_SACON",
[C_SAUTO] = "C_SAUTO",
[C_SBRA] = "C_SBRA",
[C_SCON] = "C_SCON",
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index bdcc3cad8..e7c2db5f2 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -47,74 +47,11 @@ static Sym* sym_modu;
static void setdiv(int);
-static Prog *
-movrr(Prog *q, int rs, int rd, Prog *p)
-{
- if(q == nil)
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = rs;
- q->to.type = D_REG;
- q->to.reg = rd;
- q->link = p->link;
- return q;
-}
-
-static Prog *
-fnret(Prog *q, int rs, int foreign, Prog *p)
-{
- q = movrr(q, rs, REGPC, p);
- if(foreign){ // BX rs
- q->as = ABXRET;
- q->from.type = D_NONE;
- q->from.reg = NREG;
- q->to.reg = rs;
- }
- return q;
-}
-
-static Prog *
-aword(int32 w, Prog *p)
-{
- Prog *q;
-
- q = prg();
- q->as = AWORD;
- q->line = p->line;
- q->from.type = D_NONE;
- q->reg = NREG;
- q->to.type = D_CONST;
- q->to.offset = w;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-static Prog *
-adword(int32 w1, int32 w2, Prog *p)
-{
- Prog *q;
-
- q = prg();
- q->as = ADWORD;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = w1;
- q->reg = NREG;
- q->to.type = D_CONST;
- q->to.offset = w2;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
void
noops(void)
{
- Prog *p, *q, *q1, *q2;
- int o, foreign;
+ Prog *p, *q, *q1;
+ int o;
Prog *pmorestack;
Sym *symmorestack;
@@ -140,8 +77,6 @@ noops(void)
q = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
-
switch(p->as) {
case ATEXT:
p->mark |= LEAF;
@@ -206,7 +141,6 @@ noops(void)
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
o = p->as;
switch(o) {
case ATEXT:
@@ -224,54 +158,12 @@ noops(void)
Bflush(&bso);
cursym->text->mark |= LEAF;
}
-#ifdef CALLEEBX
- if(p->from.sym->foreign){
- if(thumb)
- // don't allow literal pool to separate these
- p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
- // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
- else
- p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
- }
-#endif
if(cursym->text->mark & LEAF) {
cursym->leaf = 1;
if(!autosize)
break;
}
- if(thumb){
- if(!(p->reg & NOSPLIT))
- diag("stack splitting not supported in thumb");
- if(!(cursym->text->mark & LEAF)){
- q = movrr(nil, REGLINK, REGTMPT-1, p);
- p->link = q;
- q1 = prg();
- q1->as = AMOVW;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT-1;
- q1->to.type = D_OREG;
- q1->to.name = D_NONE;
- q1->to.reg = REGSP;
- q1->to.offset = 0;
- q1->link = q->link;
- q->link = q1;
- }
- if(autosize){
- q2 = prg();
- q2->as = ASUB;
- q2->line = p->line;
- q2->from.type = D_CONST;
- q2->from.offset = autosize;
- q2->to.type = D_REG;
- q2->to.reg = REGSP;
- q2->link = p->link;
- p->link = q2;
- }
- break;
- }
-
if(p->reg & NOSPLIT) {
q1 = prg();
q1->as = AMOVW;
@@ -432,16 +324,9 @@ noops(void)
case ARET:
nocache(p);
- foreign = seenthumb && (cursym->foreign || cursym->fnptr);
-// print("%s %d %d\n", cursym->name, cursym->foreign, cursym->fnptr);
if(cursym->text->mark & LEAF) {
if(!autosize) {
- if(thumb){
- p = fnret(p, REGLINK, foreign, p);
- break;
- }
-// if(foreign) print("ABXRET 1 %s\n", cursym->name);
- p->as = foreign ? ABXRET : AB;
+ p->as = AB;
p->from = zprg.from;
p->to.type = D_OREG;
p->to.offset = 0;
@@ -449,95 +334,16 @@ noops(void)
break;
}
}
- if(thumb){
- diag("thumb not maintained");
- errorexit();
- if(cursym->text->mark & LEAF){
- if(autosize){
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = REGSP;
- q = nil;
- }
- else
- q = p;
- q = fnret(q, REGLINK, foreign, p);
- if(q != p)
- p->link = q;
- }
- else{
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- if(autosize){
- q = prg();
- q->as = AADD;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- }
- else
- q = p;
- q1 = fnret(nil, REGTMPT-1, foreign, p);
- q1->link = q->link;
- q->link = q1;
- }
- break;
- }
- if(foreign) {
- diag("foreign not maintained");
- errorexit();
-// if(foreign) print("ABXRET 3 %s\n", cursym->name);
-#define R 1
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = R;
- q = prg();
- q->as = AADD;
- q->scond = p->scond;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- q1 = prg();
- q1->as = ABXRET;
- q1->scond = p->scond;
- q1->line = p->line;
- q1->to.type = D_OREG;
- q1->to.offset = 0;
- q1->to.reg = R;
- q1->link = q->link;
- q->link = q1;
-#undef R
- }
- else {
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
- }
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so no spadj.
break;
case AADD:
@@ -589,7 +395,7 @@ noops(void)
if(q1->reg == NREG)
p->from.reg = q1->to.reg;
p->to.type = D_REG;
- p->to.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
p->to.offset = 0;
/* CALL appropriate */
@@ -598,14 +404,7 @@ noops(void)
p->link = q;
p = q;
-#ifdef CALLEEBX
p->as = ABL;
-#else
- if(prog_div->from.sym->thumb)
- p->as = thumb ? ABL : ABX;
- else
- p->as = thumb ? ABX : ABL;
-#endif
p->line = q1->line;
p->to.type = D_BRANCH;
p->cond = p;
@@ -637,7 +436,7 @@ noops(void)
p->as = AMOVW;
p->line = q1->line;
p->from.type = D_REG;
- p->from.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->from.reg = REGTMP;
p->from.offset = 0;
p->to.type = D_REG;
p->to.reg = q1->to.reg;
@@ -669,12 +468,6 @@ noops(void)
break;
case AMOVW:
- if(thumb){
- Adr *a = &p->from;
-
- if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
- diag("SP offset not multiple of 4");
- }
if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
p->spadj = -p->to.offset;
if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
@@ -682,136 +475,6 @@ noops(void)
if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
p->spadj = -p->from.offset;
break;
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- if(thumb){
- if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->from.name == D_AUTO)
- q->from.offset += autosize;
- else if(p->from.name == D_PARAM)
- q->from.offset += autosize+4;
- q->from.name = D_NONE;
- q->from.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- }
- if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->to.name == D_AUTO)
- q->to.offset += autosize;
- else if(p->to.name == D_PARAM)
- q->to.offset += autosize+4;
- q->to.name = D_NONE;
- q->to.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- if(q->to.offset < 0 || q->to.offset > 255){ // complicated
- p->to.reg = REGTMPT+1; // mov sp, r8
- q1 = prg();
- q1->line = p->line;
- q1->as = AMOVW;
- q1->from.type = D_CONST;
- q1->from.offset = q->to.offset;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // mov $o, r7
- p->link = q1;
- q1->link = q;
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT+1;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // add r8, r7
- p->link->link = q1;
- q1->link = q;
- q->to.offset = 0; // mov* r, 0(r7)
- /* phew */
- }
- }
- }
- break;
- case AMOVM:
- if(thumb){
- if(p->from.type == D_OREG){
- if(p->from.offset == 0)
- p->from.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- else if(p->to.type == D_OREG){
- if(p->to.offset == 0)
- p->to.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- }
- break;
- case AB:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMPT-1;
- q->to.type = D_REG;
- q->to.reg = REGPC;
- q->link = p->link;
- p->link = q;
- }
- }
- if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
- // print("warn %s: b (R%d) assuming a return\n", cursym->name, p->to.reg);
- p->as = ABXRET;
- }
- break;
- case ABL:
- case ABX:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = o;
- p->from.type = D_NONE;
- p->to.type = D_REG;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = o;
- q->line = p->line;
- q->from.type = D_NONE;
- q->to.type = D_REG;
- q->to.reg = REGTMPT-1;
- q->link = p->link;
- p->link = q;
- }
- }
- break;
}
}
}
@@ -876,13 +539,19 @@ setdiv(int as)
Prog *p = nil;
switch(as){
- case ADIV: p = prog_div; break;
- case ADIVU: p = prog_divu; break;
- case AMOD: p = prog_mod; break;
- case AMODU: p = prog_modu; break;
+ case ADIV:
+ p = prog_div;
+ break;
+ case ADIVU:
+ p = prog_divu;
+ break;
+ case AMOD:
+ p = prog_mod;
+ break;
+ case AMODU:
+ p = prog_modu;
+ break;
}
- if(thumb != p->from.sym->thumb)
- p->from.sym->foreign = 1;
}
void
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 96ba0010f..dd3a7329a 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -67,6 +67,7 @@ static char*
linkername[] =
{
"runtime.softfloat",
+ "math.sqrtGoC",
};
void
@@ -241,7 +242,6 @@ main(int argc, char *argv[])
zprg.from.reg = NREG;
zprg.to = zprg.from;
buildop();
- thumbbuildop(); // could build on demand
histgen = 0;
pc = 0;
dtype = 4;
@@ -285,10 +285,8 @@ main(int argc, char *argv[])
asmb();
undef();
- if(debug['c']){
- thumbcount();
+ if(debug['c'])
print("ARM size = %d\n", armsize);
- }
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
@@ -405,8 +403,6 @@ nopout(Prog *p)
p->to.type = D_NONE;
}
-static void puntfp(Prog *);
-
void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
@@ -621,8 +617,6 @@ loop:
else
textp = s;
etextp = s;
- setarch(p);
- setthumb(p);
p->align = 4;
autosize = (p->to.offset+3L) & ~3L;
p->to.offset = autosize;
@@ -630,7 +624,6 @@ loop:
s->type = STEXT;
s->text = p;
s->value = pc;
- s->thumb = thumb;
lastp = p;
p->pc = pc;
pc++;
@@ -672,13 +665,9 @@ loop:
case AMULD:
case ADIVF:
case ADIVD:
- if(thumb)
- puntfp(p);
goto casedef;
case AMOVF:
- if(thumb)
- puntfp(p);
if(skip)
goto casedef;
@@ -700,8 +689,6 @@ loop:
goto casedef;
case AMOVD:
- if(thumb)
- puntfp(p);
if(skip)
goto casedef;
@@ -757,17 +744,6 @@ prg(void)
return p;
}
-static void
-puntfp(Prog *p)
-{
- USED(p);
- /* floating point - punt for now */
- cursym->text->reg = NREG; /* ARM */
- cursym->thumb = 0;
- thumb = 0;
- // print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line);
-}
-
Prog*
appendp(Prog *q)
{
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 4816aa40f..514786f85 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -77,7 +77,6 @@ Optab optab[] =
{ ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
{ AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
@@ -181,34 +180,34 @@ Optab optab[] =
{ ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
- { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
- { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
-
- { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
- { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO|V4 },
-
- { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM|V4 },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM|V4 },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM|V4 },
+ { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
{ ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
{ ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 7e1ba6a09..194a1ed5f 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -100,7 +100,6 @@ xfol(Prog *p, Prog **last)
loop:
if(p == P)
return;
- setarch(p);
a = p->as;
if(a == AB) {
q = p->cond;
@@ -210,14 +209,7 @@ patch(void)
vexit = s->value;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
a = p->as;
- if(seenthumb && a == ABL){
- // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
- // print("%s calls %s\n", s1->name, s->name);
- if((s = p->to.sym) != S && s->thumb != cursym->thumb)
- s->foreign = 1;
- }
if((a == ABL || a == ABX || a == AB || a == ARET) &&
p->to.type != D_BRANCH && p->to.sym != S) {
s = p->to.sym;
@@ -254,19 +246,7 @@ patch(void)
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
a = p->as;
- if(seenthumb && a == ABL) {
-#ifdef CALLEEBX
- if(0)
- {}
-#else
- if((s = p->to.sym) != S && (s->foreign || s->fnptr))
- p->as = ABX;
-#endif
- else if(p->to.type == D_OREG)
- p->as = ABX;
- }
if(p->cond != P) {
p->cond = brloop(p->cond);
if(p->cond != P)
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
index ad115a8ca..48ad2dc59 100644
--- a/src/cmd/5l/prof.c
+++ b/src/cmd/5l/prof.c
@@ -47,7 +47,6 @@ doprof1(void)
s = lookup("__mcount", 0);
n = 1;
for(p = firstp->link; p != P; p = p->link) {
- setarch(p);
if(p->as == ATEXT) {
q = prg();
q->line = p->line;
@@ -74,7 +73,7 @@ doprof1(void)
p->from.sym = s;
p->from.offset = n*4 + 4;
p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
q = prg();
q->line = p->line;
@@ -86,7 +85,7 @@ doprof1(void)
p->from.type = D_CONST;
p->from.offset = 1;
p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
q = prg();
q->line = p->line;
@@ -96,7 +95,7 @@ doprof1(void)
p = q;
p->as = AMOVW;
p->from.type = D_REG;
- p->from.reg = thumb ? REGTMPT : REGTMP;
+ p->from.reg = REGTMP;
p->to.type = D_OREG;
p->to.name = D_EXTERN;
p->to.sym = s;
@@ -143,7 +142,6 @@ doprof2(void)
ps4 = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
if(cursym == s2) {
ps2 = p;
p->reg = 1;
@@ -155,7 +153,6 @@ doprof2(void)
}
for(cursym = textp; cursym != nil; cursym = cursym->next)
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
if(p->as == ATEXT) {
if(p->reg & NOPROF) {
for(;;) {
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 03d8c6d26..4f799d17e 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -54,6 +54,8 @@ softfloat(void)
case AMULD:
case ADIVF:
case ADIVD:
+ case ASQRTF:
+ case ASQRTD:
goto soft;
default:
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 4067f1a32..eb79f6b5a 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -50,86 +50,6 @@ isbranch(Prog *p)
}
static int
-ispad(Prog *p)
-{
- if(p->as != AMOVW)
- return 0;
- if(p->from.type != D_REG || p->from.reg != REGTMP)
- return 0;
- if(p->to.type != D_REG || p->to.reg != REGTMP)
- return 0;
- return 1;
-}
-
-int
-fninc(Sym *s)
-{
- if(thumb){
- if(s->thumb){
- if(s->foreign)
- return 8;
- else
- return 0;
- }
- else{
- if(s->foreign)
- return 0;
- else
- diag("T A !foreign in fninc");
- }
- }
- else{
- if(s->thumb){
- if(s->foreign)
- return 0;
- else
- diag("A T !foreign in fninc");
- }
- else{
- if(s->foreign)
- return 4;
- else
- return 0;
- }
- }
- return 0;
-}
-
-int
-fnpinc(Sym *s)
-{
- if(!s->fnptr){ // a simplified case BX O(R) -> BL O(R)
- if(!debug['f'])
- diag("fnptr == 0 in fnpinc");
- if(s->foreign)
- diag("bad usage in fnpinc %s %d %d", s->name, s->foreign, s->thumb);
- return 0;
- }
- /* 0, 1, 2, 3 squared */
- if(s->thumb)
- return s->foreign ? 9 : 1;
- else
- return s->foreign ? 4 : 0;
-}
-
-static Prog *
-pad(Prog *p, int pc)
-{
- Prog *q;
-
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMP;
- q->to.type = D_REG;
- q->to.reg = REGTMP;
- q->pc = pc;
- q->link = p->link;
- return q;
-}
-
-static int
scan(Prog *op, Prog *p, int c)
{
Prog *q;
@@ -182,7 +102,6 @@ span(void)
otxt = c;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
p->pc = c;
cursym->value = c;
@@ -193,19 +112,14 @@ span(void)
if(c-otxt >= 1L<<17)
bflag = 1;
otxt = c;
- if(thumb && blitrl)
- pool.extra += brextra(p);
for(op = p, p = p->link; p != P; op = p, p = p->link) {
curp = p;
- setarch(p);
p->pc = c;
o = oplook(p);
m = o->size;
// must check literal pool here in case p generates many instructions
if(blitrl){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
if(checkpool(op, p->as == ACASE ? casesz(p) : m))
c = p->pc = scan(op, p, c);
}
@@ -230,8 +144,6 @@ span(void)
c += m;
}
if(blitrl){
- if(thumb && isbranch(op))
- pool.extra += brextra(op);
if(checkpool(op, 0))
c = scan(op, P, c);
}
@@ -253,10 +165,7 @@ span(void)
cursym->value = c;
for(p = cursym->text; p != P; p = p->link) {
curp = p;
- setarch(p);
p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
o = oplook(p);
/* very large branches
if(o->type == 6 && p->cond) {
@@ -298,74 +207,6 @@ span(void)
}
}
- if(seenthumb){ // branch resolution
- int passes = 0;
- int lastc = 0;
- int again;
- Prog *oop;
-
- loop:
- passes++;
- if(passes > 100){
- diag("span looping !");
- errorexit();
- }
- c = INITTEXT;
- oop = op = nil;
- again = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- cursym->value = c;
- for(p = cursym->text; p != P; oop = op, op = p, p = p->link) {
- curp = p;
- setarch(p);
- if(p->pc != c)
- again = 1;
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
- m = o->size;
- if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
- if(p->as == ABL)
- m = 4;
- else
- m = 2;
- p->align = 0;
- }
- if(p->align){
- if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
- if(ispad(op)){
- oop->link = p;
- op = oop;
- c -= 2;
- p->pc = c;
- }
- else{
- op->link = pad(op, c);
- op = op->link;
- c += 2;
- p->pc = c;
- }
- again = 1;
- }
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- }
- c += m;
- }
- cursym->size = c - cursym->value;
- }
- if(c != lastc || again){
- lastc = c;
- goto loop;
- }
- }
c = rnd(c, 8);
/*
@@ -378,7 +219,6 @@ span(void)
*/
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
autosize = p->to.offset + 4;
symgrow(cursym, cursym->size);
@@ -412,13 +252,6 @@ span(void)
int
checkpool(Prog *p, int sz)
{
- if(thumb){
- if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc)
- return flushpool(p, 1, 0);
- else if(p->link == P)
- return flushpool(p, 2, 0);
- return 0;
- }
if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
return flushpool(p, 1, 0);
else if(p->link == P)
@@ -441,7 +274,7 @@ flushpool(Prog *p, int skip, int force)
q->link = blitrl;
blitrl = q;
}
- else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048)))
+ else if(!force && (p->pc+pool.size-pool.start < 2048))
return 0;
elitrl->link = p->link;
p->link = blitrl;
@@ -461,10 +294,7 @@ addpool(Prog *p, Adr *a)
Prog *q, t;
int c;
- if(thumb)
- c = thumbaclass(a, p);
- else
- c = aclass(a);
+ c = aclass(a);
t = zprg;
t.as = AWORD;
@@ -480,12 +310,10 @@ addpool(Prog *p, Adr *a)
case C_FOREG:
case C_SOREG:
case C_HOREG:
- case C_GOREG:
case C_FAUTO:
case C_SAUTO:
case C_LAUTO:
case C_LACON:
- case C_GACON:
t.to.type = D_CONST;
t.to.offset = instoffset;
break;
@@ -591,16 +419,6 @@ symaddr(Sym *s)
return 0;
case STEXT:
-/* TODO(rsc): what is this for?
-#ifdef CALLEEBX
- v += fnpinc(s);
-#else
- if(s->thumb)
- v++; // T bit
-#endif
-*/
- break;
-
case SELFDATA:
case SRODATA:
case SDATA:
@@ -768,35 +586,19 @@ oplook(Prog *p)
int a1, a2, a3, r;
char *c1, *c3;
Optab *o, *e;
- Optab *otab;
- Oprang *orange;
- if(thumb){
- otab = thumboptab;
- orange = thumboprange;
- }
- else{
- otab = optab;
- orange = oprange;
- }
a1 = p->optab;
if(a1)
- return otab+(a1-1);
+ return optab+(a1-1);
a1 = p->from.class;
if(a1 == 0) {
- if(thumb)
- a1 = thumbaclass(&p->from, p) + 1;
- else
- a1 = aclass(&p->from) + 1;
+ a1 = aclass(&p->from) + 1;
p->from.class = a1;
}
a1--;
a3 = p->to.class;
if(a3 == 0) {
- if(thumb)
- a3 = thumbaclass(&p->to, p) + 1;
- else
- a3 = aclass(&p->to) + 1;
+ a3 = aclass(&p->to) + 1;
p->to.class = a3;
}
a3--;
@@ -804,35 +606,35 @@ oplook(Prog *p)
if(p->reg != NREG)
a2 = C_REG;
r = p->as;
- o = orange[r].start;
+ o = oprange[r].start;
if(o == 0) {
a1 = opcross[repop[r]][a1][a2][a3];
if(a1) {
p->optab = a1+1;
- return otab+a1;
+ return optab+a1;
}
- o = orange[r].stop; /* just generate an error */
+ o = oprange[r].stop; /* just generate an error */
}
if(debug['O']) {
print("oplook %A %O %O %O\n",
(int)p->as, a1, a2, a3);
print(" %d %d\n", p->from.type, p->to.type);
}
- e = orange[r].stop;
+ e = oprange[r].stop;
c1 = xcmp[a1];
c3 = xcmp[a3];
for(; o<e; o++)
if(o->a2 == a2)
if(c1[o->a1])
if(c3[o->a3]) {
- p->optab = (o-otab)+1;
+ p->optab = (o-optab)+1;
return o;
}
diag("illegal combination %A %O %O %O, %d %d",
p->as, a1, a2, a3, p->from.type, p->to.type);
prasm(p);
if(o == 0)
- o = otab;
+ o = optab;
return o;
}
@@ -883,9 +685,6 @@ cmp(int a, int b)
if(b == C_SBRA)
return 1;
break;
- case C_GBRA:
- if(b == C_SBRA || b == C_LBRA)
- return 1;
case C_HREG:
return cmp(C_SP, b) || cmp(C_PC, b);
@@ -905,9 +704,6 @@ ocmp(const void *a1, const void *a2)
n = p1->as - p2->as;
if(n)
return n;
- n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */
- if(n)
- return n;
n = p1->a1 - p2->a1;
if(n)
return n;
@@ -925,15 +721,11 @@ buildop(void)
{
int i, n, r;
- armv4 = 1;
for(i=0; i<C_GOK; i++)
for(n=0; n<C_GOK; n++)
xcmp[i][n] = cmp(n, i);
for(n=0; optab[n].as != AXXX; n++)
- if((optab[n].flag & V4) && !armv4) {
- optab[n].as = AXXX;
- break;
- }
+ ;
qsort(optab, n, sizeof(optab[0]), ocmp);
for(i=0; i<n; i++) {
r = optab[i].as;
@@ -1023,6 +815,8 @@ buildop(void)
oprange[AMULD] = oprange[r];
oprange[ADIVF] = oprange[r];
oprange[ADIVD] = oprange[r];
+ oprange[ASQRTF] = oprange[r];
+ oprange[ASQRTD] = oprange[r];
oprange[AMOVFD] = oprange[r];
oprange[AMOVDF] = oprange[r];
break;
diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c
deleted file mode 100644
index a6f729bed..000000000
--- a/src/cmd/5l/thumb.c
+++ /dev/null
@@ -1,1658 +0,0 @@
-// Inferno utils/5l/thumb.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/thumb.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.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-static int32 thumboprr(int);
-static int32 thumboprrr(int, int);
-static int32 thumbopirr(int , int);
-static int32 thumbopri(int);
-static int32 thumbophh(int);
-static int32 thumbopbra(int);
-static int32 thumbopmv(int, int);
-static void lowreg(Prog *, int);
-static void mult(Prog *, int, int);
-static void numr(Prog *, int, int, int);
-static void regis(Prog *, int, int, int);
-static void dis(int, int);
-
-// build a constant using neg, add and shift - only worth it if < 6 bytes */
-static int
-immbuildcon(int c, Prog *p)
-{
- int n = 0;
-
- USED(p);
- if(c >= 0 && c <= 255)
- return 0; // mv
- if(c >= -255 && c < 0) // mv, neg
- return 1;
- if(c >= 256 && c <= 510) // mv, add
- return 1;
- if(c < 0)
- return 0;
- while(!(c & 1)){
- n++;
- c >>= 1;
- }
- if(c >= 0 && c <= 255) // mv, lsl
- return 1;
- return 0;
-}
-
-// positive 5 bit offset from register - O(R)
-// positive 8 bit offset from register - mov O, R then [R, R]
-// otherwise O goes in literal pool - mov O1(PC), R then [R, R]
-static int
-immoreg(int off, Prog *p)
-{
- int v = 1;
- int as = p->as;
-
- if(off < 0)
- return C_GOREG;
- if(as == AMOVW)
- v = 4;
- else if(as == AMOVH || as == AMOVHU)
- v = 2;
- else if(as == AMOVB || as == AMOVBU)
- v = 1;
- else
- diag("bad op in immoreg");
- if(off/v <= 31)
- return C_SOREG;
- if(off <= 255)
- return C_LOREG;
- return C_GOREG;
-}
-
-// positive 8 bit - mov O, R then 0(R)
-// otherwise O goes in literal pool - mov O1(PC), R then 0(R)
-static int
-immacon(int off, Prog *p, int t1, int t2)
-{
- USED(p);
- if(off < 0)
- return t2;
- if(off <= 255)
- return t1;
- return t2;
-}
-
-// unsigned 8 bit in words
-static int
-immauto(int off, Prog *p)
-{
- if(p->as != AMOVW)
- diag("bad op in immauto");
- mult(p, off, 4);
- if(off >= 0 && off <= 1020)
- return C_SAUTO;
- return C_LAUTO;
-}
-
-static int
-immsmall(int off, Prog *p, int t1, int t2, int t3)
-{
- USED(p);
- if(off >= 0 && off <= 7)
- return t1;
- if(off >= 0 && off <= 255)
- return t2;
- return t3;
-}
-
-static int
-immcon(int off, Prog *p)
-{
- int as = p->as;
-
- if(as == ASLL || as == ASRL || as == ASRA)
- return C_SCON;
- if(p->to.type == D_REG && p->to.reg == REGSP){
- if(as == AADD || as == ASUB){
- if(off >= 0 && off <= 508)
- return C_SCON;
- if(as == ASUB){
- p->as = AADD;
- p->from.offset = -p->from.offset;
- }
- return C_LCON;
- }
- diag("unknown type in immcon");
- }
- if(as == AADD || as == ASUB){
- if(p->reg != NREG)
- return immsmall(off, p, C_SCON, C_LCON, C_GCON);
- return immacon(off, p, C_SCON, C_LCON);
- }
- if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p))
- return C_BCON;
- if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p))
- return C_BCON;
- if(as == ACMP || as == AMOVW)
- return immacon(off, p, C_SCON, C_LCON);
- return C_LCON;
-}
-
-int
-thumbaclass(Adr *a, Prog *p)
-{
- Sym *s;
- int t;
-
- switch(a->type) {
- case D_NONE:
- return C_NONE;
- case D_REG:
- if(a->reg == REGSP)
- return C_SP;
- if(a->reg == REGPC)
- return C_PC;
- if(a->reg >= 8)
- return C_HREG;
- return C_REG;
- case D_SHIFT:
- diag("D_SHIFT in thumbaclass");
- return C_SHIFT;
- case D_FREG:
- diag("D_FREG in thumbaclass");
- return C_FREG;
- case D_FPCR:
- diag("D_FPCR in thumbaclass");
- return C_FCR;
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- t = a->sym->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- a->sym->name, TNAME);
- a->sym->type = SDATA;
- }
- instoffset = a->sym->value + a->offset;
- return C_ADDR; /* INITDAT unknown at this stage */
- case D_AUTO:
- instoffset = autosize + a->offset;
- return immauto(instoffset, p);
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
-// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4);
- return immauto(instoffset, p);
- case D_NONE:
- instoffset = a->offset;
- if(a->reg == REGSP)
- return immauto(instoffset, p);
- else
- return immoreg(instoffset, p);
- }
- return C_GOK;
- case D_PSR:
- diag("D_PSR in thumbaclass");
- return C_PSR;
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- }
- instoffset = s->value + a->offset;
- if(s->type == STEXT){
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- return C_LCON; /* INITDAT unknown at this stage */
- // return immcon(instoffset, p);
- }
- return C_GOK;
- case D_FCONST:
- diag("D_FCONST in thumaclass");
- return C_LFCON;
- case D_CONST:
- switch(a->name) {
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
- return immcon(instoffset, p);
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case SCONST:
- case STEXT:
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- instoffset = s->value + a->offset;
- return C_LCON; /* INITDAT unknown at this stage */
- // return immcon(instoffset, p);
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- if(p->from.reg == REGSP || p->from.reg == NREG)
- return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON;
- else if(p->from.reg == p->to.reg)
- return immacon(instoffset, p, C_SACON, C_GACON);
- return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON);
- }
- return C_GOK;
- case D_BRANCH: {
- int v, va;
-
- p->align = 0;
- v = -4;
- va = 0;
- if(p->cond != P){
- v = (p->cond->pc - p->pc) - 4;
- va = p->cond->pc;
- }
- instoffset = v;
- if(p->as == AB){
- if(v >= -2048 && v <= 2046)
- return C_SBRA;
- p->align = 4;
- instoffset = va;
- return C_LBRA;
- }
- if(p->as == ABL){
-#ifdef CALLEEBX
- int e;
-
- if((e = fninc(p->to.sym))) {
- v += e;
- va += e;
- instoffset += e;
- }
-#endif
- if(v >= -4194304 && v <= 4194302)
- return C_SBRA;
- p->align = 2;
- instoffset = va;
- return C_LBRA;
- }
- if(p->as == ABX){
- v = va;
- if(v >= 0 && v <= 255)
- return C_SBRA;
- p->align = 2;
- instoffset = va;
- return C_LBRA;
- }
- if(v >= -256 && v <= 254)
- return C_SBRA;
- if(v >= -(2048-2) && v <= (2046+2))
- return C_LBRA;
- p->align = 2;
- instoffset = va;
- return C_GBRA;
- }
- }
- return C_GOK;
-}
-
-// as a1 a2 a3 type size param lit vers
-Optab thumboptab[] =
-{
- { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
- { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 },
- { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 },
- { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 },
- { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 },
- { AADD, C_REG, C_REG, C_REG, 2, 2, 0 },
- { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 },
- { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 },
- { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 },
- { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM },
- // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM },
- { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 },
- { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 },
- { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 },
- { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM },
- { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 },
- { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 },
- { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM },
- { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 },
- { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 },
- { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM },
- // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM },
- // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM },
- { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 },
- { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM },
- { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 },
- { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 },
- { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 },
- { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 },
- { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
- { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 },
- { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 },
- { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 },
- { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL },
- { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 },
- { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 },
- { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 },
- { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL },
- { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 },
- { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 },
- { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 },
- { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 },
- // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 },
- // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 },
- { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 },
- { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 },
- { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 },
- { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 },
- { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 },
- { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 },
- { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_ADDR, 17, 4, 0 },
- { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 },
- { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP },
- { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM },
- // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM },
- { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 },
- { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 },
- { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM },
- { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 },
- { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 },
- { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVW, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
-
- { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },
-};
-
-#define OPCNTSZ 52
-int opcount[OPCNTSZ];
-
-// is this too pessimistic ?
-int
-brextra(Prog *p)
-{
- int c;
-
- // +2 is for padding
- if(p->as == ATEXT)
- return 0-0+2;
- if(!isbranch(p))
- diag("bad op in brextra()");
- c = thumbaclass(&p->to, p);
- switch(p->as){
- case AB:
- if(c != C_SBRA)
- return 0;
- return 8-2+2;
- case ABL:
- if(c != C_SBRA)
- return 0;
- return 14-4+2;
- case ABX:
- if(c == C_REG || c == C_HREG)
- return 0;
-#ifdef CALLEEBX
- diag("ABX $I in brextra");
-#endif
- if(c != C_SBRA)
- return 0;
- return 14-10+2;
- default:
- if(c == C_GBRA)
- return 0;
- if(c == C_LBRA)
- return 10-4+2;
- return 10-2+2;
- }
- return 0;
-}
-
-#define high(r) ((r)>=8)
-
-static int32
-mv(Prog *p, int r, int off)
-{
- int v, o;
- if(p != nil && p->cond != nil){ // in literal pool
- v = p->cond->pc - p->pc - 4;
- if(p->cond->pc & 3)
- diag("mv: bad literal pool alignment");
- if(v & 3)
- v += 2; // ensure M(4) offset
- mult(p, v, 4);
- off = v/4;
- numr(p, off, 0, 255);
- o = 0x9<<11;
- }
- else{
- numr(p, off, 0, 255);
- o = 0x4<<11;
- }
- o |= (r<<8) | off;
- return o;
-}
-
-static void
-mvcon(Prog *p, int r, int c, int32 *o1, int32 *o2)
-{
- int op = 0, n = 0;
-
- if(c >= 0 && c <= 255)
- diag("bad c in mvcon");
- if(c >= -255 && c < 0) // mv, neg
- c = -c;
- else if(c >= 256 && c <= 510){ // mv, add
- n = rand()%(511-c) + (c-255);
- c -= n;
- // n = c-255;
- // c = 255;
- op = AADD;
- }
- else{
- if(c < 0)
- diag("-ve in mvcon");
- while(!(c & 1)){
- n++;
- c >>= 1;
- }
- if(c >= 0 && c <= 255) // mv, lsl
- op = ASLL;
- else
- diag("bad shift in mvcon");
- }
- *o1 = mv(p, r, c);
- switch(op){
- case 0:
- *o2 = (1<<14) | (9<<6) | (r<<3) | r;
- break;
- case AADD:
- *o2 = (6<<11) | (r<<8) | n;
- break;
- case ASLL:
- *o2 = (n<<6) | (r<<3) | r;
- break;
- }
-}
-
-static int32
-mvlh(int rs, int rd)
-{
- int o = 0x46<<8;
-
- if(high(rs)){
- rs -= 8;
- o |= 1<<6;
- }
- if(high(rd)){
- rd -= 8;
- o |= 1<<7;
- }
- o |= (rs<<3) | rd;
- return o;
-}
-
-void
-thumbbuildop()
-{
- int i, n, r;
- Optab *optab = thumboptab;
- Oprang *oprange = thumboprange;
-
- for(n=0; optab[n].as != AXXX; n++)
- ;
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
-
- switch(r)
- {
- default:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case AMVN:
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[AMUL] = oprange[r];
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- oprange[AMULU] = oprange[r];
- break;
- case ACMN:
- oprange[ATST] = oprange[r];
- break;
- case ASRL:
- oprange[ASRA] = oprange[r];
- oprange[ASLL] = oprange[r];
- break;
- case AADD:
- oprange[ASUB] = oprange[r];
- break;
- }
- }
-}
-
-void
-thumbasmout(Prog *p, Optab *o)
-{
- int32 o1, o2, o3, o4, o5, o6, o7, v;
- int r, rf, rt;
-
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0;
-if(debug['P']) print("%ux: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
- opcount[o->type] += o->size;
- switch(o->type) {
- default:
- diag("unknown asm %d", o->type);
- prasm(p);
- break;
- case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
- break;
- case 1: /* op R, -, R or op R, R, - */
- o1 = thumboprr(p->as);
- if(rt == NREG)
- rt = r;
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x10<<10) | (rf<<3) | rt;
- break;
- case 2: /* add/sub R, R, R or add/sub R, -, R */
- o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
- if(r == NREG)
- r = rt;
- lowreg(p, rf);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt;
- break;
- case 3: /* add/sub $I, R, R or add/sub $I, -, R */
- thumbaclass(&p->from, p);
- o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
- if(r == NREG)
- r = rt;
- numr(p, instoffset, 0, 7);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt;
- break;
- case 4: /* shift $I, R, R or shift $I, -, R */
- thumbaclass(&p->from, p);
- if(instoffset < 0)
- diag("negative shift in thumbasmout");
- instoffset %= 32;
- o1 = thumbopri(p->as);
- if(r == NREG)
- r = rt;
- numr(p, instoffset, 0, 31);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt;
- break;
- case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */
- thumbaclass(&p->from, p);
- o1 = thumbopri(p->as);
- if(rt == NREG)
- rt = r;
- numr(p, instoffset, 0, 255);
- lowreg(p, rt);
- o1 |= (0x1<<13) | (rt<<8) | instoffset;
- break;
- case 6: /* add $I, PC/SP, R */
- if(p->as == ASUB)
- diag("subtract in add $I, PC/SP, R");
- thumbaclass(&p->from, p);
- o1 = r == REGSP ? 0x1<<11 : 0x0<<11;
- numr(p, instoffset, 0, 255);
- regis(p, r, REGSP, REGPC);
- lowreg(p, rt);
- o1 |= (0xa<<12) | (rt<<8) | instoffset;
- break;
- case 7: /* add, sub $I, SP */
- thumbaclass(&p->from, p);
- o1 = p->as == AADD ? 0x0<<7 : 0x1<<7;
- numr(p, instoffset, 0, 508);
- mult(p, instoffset, 4);
- regis(p, rt, REGSP, REGSP);
- o1 |= (0xb0<<8) | (instoffset>>2);
- break;
- case 8: /* add/mov/cmp R, R where at least 1 reg is high */
- o1 = 0;
- if(rt == NREG)
- rt = r;
- if(high(rf)){
- o1 |= 1<<6;
- rf -= 8;
- }
- if(high(rt)){
- o1 |= 2<<6;
- rt -= 8;
- }
- if(o1 == 0)
- diag("no high register(%P)", p);
- o1 |= thumbophh(p->as);
- o1 |= (0x11<<10) | (rf<<3) | rt;
- break;
- case 9: /* B $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -2048, 2046);
- o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 10: /* Bcc $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -256, 254);
- o1 = thumbopbra(p->as);
- o1 |= (0xd<<12) | ((instoffset>>1)&0xff);
- break;
- case 11: /* BL $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -4194304, 4194302);
- o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff);
- o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 12: /* BX $I */
-#ifdef CALLEEBX
- diag("BX $I case");
-#endif
- thumbaclass(&p->to, p);
- if(p->to.sym->thumb)
- instoffset |= 1; // T bit
- o1 = mvlh(REGPC, REGTMPT);
- o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset)
- o3 = mvlh(REGTMPT, REGLINK);
- o4 = mv(nil, REGTMPT, instoffset);
- o5 = (0x11c<<6) | (REGTMPT<<3);
- // o1 = mv(nil, REGTMPT, v);
- // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK;
- // o3 = (0x11c<<6) | (REGTMPT<<3);
- break;
- case 13: /* B O(R) */
- diag("B O(R)");
- break;
- case 14: /* BL O(R) */
- diag("BL O(R)");
- break;
- case 15: /* BX R */
- o1 = mvlh(REGPC, REGTMPT);
- o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset)
- o3 = mvlh(REGTMPT, REGLINK);
- o4 = 0;
- if(high(rt)){
- rt -= 8;
- o4 |= 1<<6;
- }
- o4 |= (0x8e<<7) | (rt<<3);
- // o1 = (0x11c<<6) | (rt<<3);
- break;
- case 16: /* SWI $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, 0, 255);
- o1 = (0xdf<<8) | instoffset;
- break;
- case 17: /* AWORD */
- thumbaclass(&p->to, p);
- o1 = instoffset&0xffff;
- o2 = (instoffset>>16)&0xffff;
- break;
- case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */
- thumbaclass(&p->from, p);
- rf = o->param;
- o1 = rf == REGSP ? 0x13<<11 : 0x9<<11;
- regis(p, rf, REGSP, REGPC);
- lowreg(p, rt);
- mult(p, instoffset, 4);
- numr(p, instoffset/4, 0, 255);
- o1 |= (rt<<8) | (instoffset/4);
- break;
- case 19: /* AMOVW... O(R), R */
- thumbaclass(&p->from, p);
- o1 = thumbopmv(p->as, 1);
- v = 4;
- if(p->as == AMOVHU)
- v = 2;
- else if(p->as == AMOVBU)
- v = 1;
- mult(p, instoffset, v);
- lowreg(p, rf);
- lowreg(p, rt);
- numr(p, instoffset/v, 0, 31);
- o1 |= ((instoffset/v)<<6) | (rf<<3) | rt;
- break;
- case 20: /* AMOVW R, O(SP) */
- thumbaclass(&p->to, p);
- o1 = 0x12<<11;
- if(rt != NREG) regis(p, rt, REGSP, REGSP);
- lowreg(p, rf);
- mult(p, instoffset, 4);
- numr(p, instoffset/4, 0, 255);
- o1 |= (rf<<8) | (instoffset/4);
- break;
- case 21: /* AMOVW... R, O(R) */
- thumbaclass(&p->to, p);
- o1 = thumbopmv(p->as, 0);
- v = 4;
- if(p->as == AMOVHU || p->as == AMOVH)
- v = 2;
- else if(p->as == AMOVBU || p->as == AMOVB)
- v = 1;
- lowreg(p, rf);
- lowreg(p, rt);
- mult(p, instoffset, v);
- numr(p, instoffset/v, 0, 31);
- o1 |= ((instoffset/v)<<6) | (rt<<3) | rf;
- break;
- case 22: /* AMOVW R, R -> ASLL $0, R, R */
- o1 = thumbopri(ASLL);
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (rf<<3) | rt;
- break;
- case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */
- o1 = thumbopri(ASLL);
- o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL);
- v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16;
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt;
- o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt;
- break;
- case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */
- thumbaclass(&p->from, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rf == rt)
- r = REGTMPT;
- else
- r = rt;
- if(p->as == AMOVB)
- numr(p, instoffset, 0, 31);
- else{
- mult(p, instoffset, 2);
- numr(p, instoffset, 0, 62);
- }
- o1 = mv(p, r, instoffset);
- o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
- o2 |= (r<<6) | (rf<<3) | rt;
- break;
- case 25: /* MOVW $sacon, R */
- thumbaclass(&p->from, p);
-// print("25: %d %d %d %d\n", instoffset, rf, r, rt);
- if(rf == NREG)
- rf = REGSP;
- lowreg(p, rt);
- if(rf == REGSP){
- mult(p, instoffset, 4);
- numr(p, instoffset>>2, 0, 255);
- o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R
- }
- else if(rf == rt){
- numr(p, instoffset, 0, 255);
- o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R
- }
- else{
- lowreg(p, rf);
- numr(p, instoffset, 0, 7);
- o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd
- }
- break;
- case 26: /* AMOVM $c, oreg -> stmia */
- lowreg(p, rt);
- numr(p, p->from.offset, -256, 255);
- o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff);
- break;
- case 27: /* AMOVM oreg, $c ->ldmia */
- lowreg(p, rf);
- numr(p, p->to.offset, -256, 256);
- o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff);
- break;
- case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */
- thumbaclass(&p->from, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rf == rt)
- r = REGTMPT;
- else
- r = rt;
- o1 = mv(p, r, instoffset);
- o2 = thumboprrr(p->as, 1);
- o2 |= (r<<6) | (rf<<3) | rt;
- break;
- case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */
- thumbaclass(&p->to, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rt == REGTMPT){ // used as tmp reg
- if(instoffset >= 0 && instoffset <= 255){
- o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7
- o2 = thumbopirr(p->as, 0);
- o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R)
- }
- else
- diag("big offset - case 29");
- }
- else{
- o1 = mv(p, REGTMPT, instoffset);
- o2 = thumboprrr(p->as, 0);
- o2 |= (REGTMPT<<6) | (rt<<3) | rf;
- }
- break;
- case 30: /* AMOVW... *addr, R */
- diag("likely broken"); // does this still refer to SB?
- thumbaclass(&p->from, p);
- o1 = mv(p, rt, instoffset); // MOV addr, rtmp
- o2 = thumbopmv(p->as, 1);
- lowreg(p, rt);
- o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R
- break;
- case 31: /* AMOVW... R, *addr */
- diag("likely broken"); // does this still refer to SB?
- thumbaclass(&p->to, p);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = thumbopmv(p->as, 0);
- lowreg(p, rf);
- o2 |= (REGTMPT<<3) | rf;
- break;
- case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */
- thumbaclass(&p->from, p);
- o1 = mv(p, rt, instoffset);
- lowreg(p, rt);
- o2 = mv(nil, REGTMPT, 0);
- o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
- o3 |= (REGTMPT<<6) | (rt<<3) | rt;
- break;
- case 33: /* AMOVW O(SP), R (O large) */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, rt, instoffset);
- o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt
- o3 = thumbopmv(p->as, 1);
- o3 |= (rt<<3) | rt;
- break;
- case 34: /* AMOVW R, O(SP) (O large) */
- thumbaclass(&p->to, p);
- lowreg(p, rf);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP
- o3 = thumbopmv(p->as, 0);
- o3 |= (REGTMPT<<3) | rf;
- break;
- case 35: /* AMOVW $lacon, R */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- if(rf == NREG)
- rf = REGSP;
- if(rf == rt)
- rf = r = REGTMPT;
- else
- r = rt;
-// print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt);
- o1 = mv(p, r, instoffset); // mov O, Rd
- if(high(rf))
- o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd
- else
- o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd
- break;
- case 36: /* AADD/ASUB $i, r, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- lowreg(p, rt);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (r<<3) | rt;
- break;
- case 37: /* AADD/ASUB $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (rt<<3) | rt;
- break;
- case 38: /* AMOVW $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, rt, instoffset);
- break;
- case 39: /* ACMP $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x10a<<6) | (REGTMPT<<3) | r;
- break;
- case 40: /* add, sub $I, SP when $I large*/
- thumbaclass(&p->from, p);
- if(p->as == ASUB)
- instoffset = -instoffset;
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8);
- regis(p, rt, REGSP, REGSP);
- break;
- case 41: /* BL LBRA */
- thumbaclass(&p->to, p);
- o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
- o2 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o3 = instoffset&0xffff; // $lab
- o4 = (instoffset>>16)&0xffff;
- break;
- case 42: /* Bcc GBRA */
- thumbaclass(&p->to, p);
- o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot
- // ab lbra
- o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
- o3 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o4 = instoffset&0xffff; // $lab
- o5 = (instoffset>>16)&0xffff;
- break;
- case 43: /* BL LBRA */
- thumbaclass(&p->to, p);
- o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
- o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7
- o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
- o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
- o5 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o6 = instoffset&0xffff; // $lab
- o7 = (instoffset>>16)&0xffff;
- break;
- case 44: /* BX LBRA */
-#ifdef CALLEEBX
- diag("BX LBRA case");
-#endif
- thumbaclass(&p->to, p);
- if(p->to.sym->thumb)
- instoffset |= 1; // T bit
- o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
- o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7
- o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
- o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
- o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7
- o6 = instoffset&0xffff; // $lab
- o7 = (instoffset>>16)&0xffff;
- break;
- case 45: /* BX R when returning from fn */
- o1 = 0;
- if(high(rt)){
- rt -= 8;
- o1 |= 1<<6;
- }
- o1 |= (0x8e<<7) | (rt<<3);
- break;
- case 46: /* Bcc LBRA */
- thumbaclass(&p->to, p);
- o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot
- // ab lbra
- instoffset -= 2;
- numr(p, instoffset, -2048, 2046);
- o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 47: /* mov $i, R where $i can be built */
- thumbaclass(&p->from, p);
- mvcon(p, rt, instoffset, &o1, &o2);
- break;
- case 48: /* ACMP $i, r when $i built up */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- mvcon(p, REGTMPT, instoffset, &o1, &o2);
- o3 = (0x10a<<6) | (REGTMPT<<3) | r;
- break;
- case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- lowreg(p, rt);
- numr(p, instoffset, 0, 255);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (r<<3) | rt;
- break;
- case 50: /* ADWORD */
- thumbaclass(&p->from, p);
- o1 = instoffset&0xffff;
- o2 = (instoffset>>16)&0xffff;
- thumbaclass(&p->to, p);
- o3 = instoffset&0xffff;
- o4 = (instoffset>>16)&0xffff;
- break;
- case 51: /* BL r */
- o1 = mvlh(REGPC, REGLINK); // mov pc, lr
- o2 = mvlh(rt, REGPC); // mov r, pc
- break;
- }
-
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 2:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- hputl(o1);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux\t%P\n", v, o1, o2, p);
- hputl(o1);
- hputl(o2);
- break;
- case 6:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- break;
- case 10:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- hputl(o6);
- break;
- case 14:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- hputl(o6);
- hputl(o7);
- break;
- }
- if(debug['G']){
- if(o->type == 17){
- print("%x: word %d\n", p->pc, (o2<<16)+o1);
- return;
- }
- if(o->type == 50){
- print("%x: word %d\n", p->pc, (o2<<16)+o1);
- print("%x: word %d\n", p->pc, (o4<<16)+o3);
- return;
- }
- if(o->size > 0) dis(o1, p->pc);
- if(o->size > 2) dis(o2, p->pc+2);
- if(o->size > 4) dis(o3, p->pc+4);
- if(o->size > 6) dis(o4, p->pc+6);
- if(o->size > 8) dis(o5, p->pc+8);
- if(o->size > 10) dis(o6, p->pc+10);
- if(o->size > 12) dis(o7, p->pc+12);
- // if(o->size > 14) dis(o8, p->pc+14);
- }
-}
-
-static int32
-thumboprr(int a)
-{
- switch(a) {
- case AMVN: return 0xf<<6;
- case ACMP: return 0xa<<6;
- case ACMN: return 0xb<<6;
- case ATST: return 0x8<<6;
- case AADC: return 0x5<<6;
- case ASBC: return 0x6<<6;
- case AMUL:
- case AMULU: return 0xd<<6;
- case AAND: return 0x0<<6;
- case AEOR: return 0x1<<6;
- case AORR: return 0xc<<6;
- case ABIC: return 0xe<<6;
- case ASRL: return 0x3<<6;
- case ASRA: return 0x4<<6;
- case ASLL: return 0x2<<6;
- }
- diag("bad thumbop oprr %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopirr(int a, int ld)
-{
- if(ld)
- diag("load in thumbopirr");
- switch(a){
- case AMOVW: return 0xc<<11;
- case AMOVH:
- case AMOVHU: return 0x10<<11;
- case AMOVB:
- case AMOVBU: return 0xe<<11;
- }
- return 0;
-}
-
-static int32
-thumboprrr(int a, int ld)
-{
- if(ld){
- switch(a){
- case AMOVW: return 0x2c<<9;
- case AMOVH: return 0x2f<<9;
- case AMOVB: return 0x2b<<9;
- case AMOVHU: return 0x2d<<9;
- case AMOVBU: return 0x2e<<9;
- }
- }
- else{
- switch(a){
- case AMOVW: return 0x28<<9;
- case AMOVHU:
- case AMOVH: return 0x29<<9;
- case AMOVBU:
- case AMOVB: return 0x2a<<9;
- }
- }
- diag("bad thumbop oprrr %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopri(int a)
-{
- switch(a) {
- case ASRL: return 0x1<<11;
- case ASRA: return 0x2<<11;
- case ASLL: return 0x0<<11;
- case AADD: return 0x2<<11;
- case ASUB: return 0x3<<11;
- case AMOVW: return 0x0<<11;
- case ACMP: return 0x1<<11;
- }
- diag("bad thumbop opri %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbophh(int a)
-{
- switch(a) {
- case AADD: return 0x0<<8;
- case AMOVW: return 0x2<<8;
- case ACMP: return 0x1<<8;
- }
- diag("bad thumbop ophh %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopbra(int a)
-{
- switch(a) {
- case ABEQ: return 0x0<<8;
- case ABNE: return 0x1<<8;
- case ABCS: return 0x2<<8;
- case ABHS: return 0x2<<8;
- case ABCC: return 0x3<<8;
- case ABLO: return 0x3<<8;
- case ABMI: return 0x4<<8;
- case ABPL: return 0x5<<8;
- case ABVS: return 0x6<<8;
- case ABVC: return 0x7<<8;
- case ABHI: return 0x8<<8;
- case ABLS: return 0x9<<8;
- case ABGE: return 0xa<<8;
- case ABLT: return 0xb<<8;
- case ABGT: return 0xc<<8;
- case ABLE: return 0xd<<8;
- }
- diag("bad thumbop opbra %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopmv(int a, int ld)
-{
- switch(a) {
- case AMOVW: return (ld ? 0xd : 0xc)<<11;
- case AMOVH:
- case AMOVHU: return (ld ? 0x11: 0x10)<<11;
- case AMOVB:
- case AMOVBU: return (ld ? 0xf : 0xe)<<11;
- }
- diag("bad thumbop opmv %d", a);
- prasm(curp);
- return 0;
-}
-
-static void
-lowreg(Prog *p, int r)
-{
- if(high(r))
- diag("high reg [%P]", p);
-}
-
-static void
-mult(Prog *p, int n, int m)
-{
- if(m*(n/m) != n)
- diag("%d not M(%d) [%P]", n, m, p);
-}
-
-static void
-numr(Prog *p, int n, int min, int max)
-{
- if(n < min || n > max)
- diag("%d not in %d-%d [%P]", n, min, max, p);
-}
-
-static void
-regis(Prog *p, int r, int r1, int r2)
-{
- if(r != r1 && r != r2)
- diag("reg %d not %d or %d [%P]", r, r1, r2, p);
-}
-
-void
-hputl(int n)
-{
- cbp[1] = n>>8;
- cbp[0] = n;
- cbp += 2;
- cbc -= 2;
- if(cbc <= 0)
- cflush();
-}
-
-void
-thumbcount()
-{
- int i, c = 0, t = 0;
-
- for (i = 0; i < OPCNTSZ; i++)
- t += opcount[i];
- if(t == 0)
- return;
- for (i = 0; i < OPCNTSZ; i++){
- c += opcount[i];
- print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t);
- }
-}
-
-char *op1[] = { "lsl", "lsr", "asr" };
-char *op2[] = { "add", "sub" };
-char *op3[] = { "movw", "cmp", "add", "sub" };
-char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
- "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" };
-char *op5[] = { "add", "cmp", "movw", "bx" };
-char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" };
-char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" };
-char *op8[] = { "smovh", "lmovhu" };
-char *op9[] = { "smovw", "lmovw" };
-char *op10[] = { "push", "pop" };
-char *op11[] = { "stmia", "ldmia" };
-
-char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
- "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
-
-#define B(h, l) bits(i, h, l)
-#define IMM(h, l) B(h, l)
-#define REG(h, l) reg(B(h, l))
-#define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh))
-#define COND(h, l) cond[B(h, l)]
-#define OP1(h, l) op1[B(h, l)]
-#define OP2(h, l) op2[B(h, l)]
-#define OP3(h, l) op3[B(h, l)]
-#define OP4(h, l) op4[B(h, l)]
-#define OP5(h, l) op5[B(h, l)]
-#define OP6(h, l) op6[B(h, l)]
-#define OP7(h, l) op7[B(h, l)]
-#define OP8(h, l) op8[B(h, l)]
-#define OP9(h, l) op9[B(h, l)]
-#define OP10(h, l) op10[B(h, l)]
-#define OP11(h, l) op11[B(h, l)]
-#define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l)
-#define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l)
-#define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l)
-
-static int
-bits(int i, int h, int l)
-{
- if(h < l)
- diag("h < l in bits");
- return (i&(((1<<(h-l+1))-1)<<l))>>l;
-}
-
-static char *
-reg(int r)
-{
- static char s[4][4];
- static int i = 0;
-
- if(r < 0 || r > 7)
- diag("register %d out of range", r);
- i++;
- if(i == 4)
- i = 0;
- sprint(s[i], "r%d", r);
- return s[i];
-}
-
-static char *regnames[] = { "sp", "lr", "pc" };
-
-static char *
-lhreg(int r, int lh)
-{
- static char s[4][4];
- static int i = 0;
-
- if(lh == 0)
- return reg(r);
- if(r < 0 || r > 7)
- diag("high register %d out of range", r);
- i++;
- if(i == 4)
- i = 0;
- if(r >= 5)
- sprint(s[i], "%s", regnames[r-5]);
- else
- sprint(s[i], "r%d", r+8);
- return s[i];
-}
-
-static void
-illegal(int i, int pc)
-{
- diag("%x: %x illegal instruction", pc, i);
-}
-
-static void
-dis(int i, int pc)
-{
- static int lasto;
- int o, l;
- char *op;
-
- print("%x: %x: ", pc, i);
- if(i&0xffff0000)
- illegal(i, pc);
- o = B(15, 13);
- switch(o){
- case 0:
- o = B(12, 11);
- switch(o){
- case 0:
- case 1:
- case 2:
- print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0));
- return;
- case 3:
- if(B(10, 10) == 0)
- print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0));
- return;
- }
- case 1:
- print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8));
- return;
- case 2:
- o = B(12, 10);
- if(o == 0){
- print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0));
- return;
- }
- if(o == 1){
- o = B(9, 8);
- if(o == 3){
- SBZ(7, 7);
- SBZ(2, 0);
- print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6));
- return;
- }
- SNBZ(7, 6);
- print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7));
- return;
- }
- if(o == 2 || o == 3){
- print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8));
- return;
- }
- op = OP6(11, 9);
- if(*op == 'l')
- print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3));
- return;
- case 3:
- op = OP7(12, 11);
- if(B(12, 11) == 0 || B(12,11) == 1)
- l = 4;
- else
- l = 1;
- if(*op == 'l')
- print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3));
- return;
- case 4:
- if(B(12, 12) == 0){
- op = OP8(11, 11);
- if(*op == 'l')
- print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3));
- return;
- }
- op = OP9(11, 11);
- if(*op == 'l')
- print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8));
- else
- print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0));
- return;
- case 5:
- if(B(12, 12) == 0){
- if(B(11, 11) == 0)
- print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8));
- else
- print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8));
- return;
- }
- if(B(11, 8) == 0){
- print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0));
- return;
- }
- SBO(10, 10);
- SBZ(9, 9);
- if(B(8, 8) == 0)
- print("%s sp, %d\n", OP10(11, 11), IMM(7, 0));
- else
- print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0));
- return;
- case 6:
- if(B(12, 12) == 0){
- print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0));
- return;
- }
- if(B(11, 8) == 0xf){
- print("swi %d\n", IMM(7, 0));
- return;
- }
- o = IMM(7, 0);
- if(o&0x80)
- o |= 0xffffff00;
- o = pc+4+(o<<1);
- print("b%s %x\n", COND(11, 8), o);
- return;
- case 7:
- o = B(12, 11);
- switch(o){
- case 0:
- o = IMM(10, 0);
- if(o&0x400)
- o |= 0xfffff800;
- o = pc+4+(o<<1);
- print("b %x\n", o);
- return;
- case 1:
- illegal(i, pc);
- return;
- case 2:
- lasto = IMM(10, 0);
- print("bl\n");
- return;
- case 3:
- if(lasto&0x400)
- lasto |= 0xfffff800;
- o = IMM(10, 0);
- o = (pc-2)+4+(o<<1)+(lasto<<12);
- print("bl %x\n", o);
- return;
- }
- }
-}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 7efb2c252..2493771a0 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -23,6 +23,7 @@ struct Addr
Sym* gotype;
Sym* sym;
+ Node* node;
int width;
uchar type;
uchar index;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index ed98d1bc9..ae6ae5765 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -988,7 +988,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->index = D_NONE;
a->type = D_NONE;
a->gotype = S;
-
+ a->node = N;
if(n == N)
return;
@@ -1067,6 +1067,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->type = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index b4b5b7d6b..af9b29cbc 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -33,6 +33,8 @@
#define EXTERN
#include "opt.h"
+#define NREGVAR 32 /* 16 general + 16 floating */
+#define REGBITS ((uint32)0xffffffff)
#define P2R(p) (Reg*)(p->reg)
static int first = 1;
@@ -114,6 +116,41 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = {
+ ".AX",
+ ".CX",
+ ".DX",
+ ".BX",
+ ".SP",
+ ".BP",
+ ".SI",
+ ".DI",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".X0",
+ ".X1",
+ ".X2",
+ ".X3",
+ ".X4",
+ ".X5",
+ ".X6",
+ ".X7",
+ ".X8",
+ ".X9",
+ ".X10",
+ ".X11",
+ ".X12",
+ ".X13",
+ ".X14",
+ ".X15",
+};
+
void
regopt(Prog *firstp)
{
@@ -143,6 +180,17 @@ regopt(Prog *firstp)
firstr = R;
lastr = R;
nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -247,6 +295,9 @@ regopt(Prog *firstp)
case ACOMISD:
case AUCOMISS:
case AUCOMISD:
+ case ATESTB:
+ case ATESTL:
+ case ATESTQ:
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
break;
@@ -254,6 +305,7 @@ regopt(Prog *firstp)
/*
* right side write
*/
+ case ALEAQ:
case ANOP:
case AMOVL:
case AMOVQ:
@@ -261,6 +313,8 @@ regopt(Prog *firstp)
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
case AMOVBQSX:
case AMOVBQZX:
case AMOVLQSX:
@@ -269,6 +323,7 @@ regopt(Prog *firstp)
case AMOVWLZX:
case AMOVWQSX:
case AMOVWQZX:
+ case APOPQ:
case AMOVSS:
case AMOVSD:
@@ -357,6 +412,8 @@ regopt(Prog *firstp)
case AIMULL:
case AIMULQ:
case AIMULW:
+ case ANEGB:
+ case ANEGW:
case ANEGL:
case ANEGQ:
case ANOTL:
@@ -366,6 +423,23 @@ regopt(Prog *firstp)
case ASBBL:
case ASBBQ:
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
case AXCHGB:
case AXCHGW:
case AXCHGL:
@@ -411,32 +485,44 @@ regopt(Prog *firstp)
if(p->to.type != D_NONE)
break;
- case AIDIVB:
case AIDIVL:
- case AIDIVQ:
case AIDIVW:
- case AIMULB:
- case ADIVB:
+ case AIDIVQ:
case ADIVL:
- case ADIVQ:
case ADIVW:
- case AMULB:
+ case ADIVQ:
case AMULL:
- case AMULQ:
case AMULW:
+ case AMULQ:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
case ACWD:
- case ACDQ:
- case ACQO:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
break;
+ case ACDQ:
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
case AREP:
case AREPN:
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
- r->regu |= RtoB(D_CX);
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
break;
case AMOVSB:
@@ -447,7 +533,8 @@ regopt(Prog *firstp)
case ACMPSL:
case ACMPSQ:
case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
@@ -458,16 +545,22 @@ regopt(Prog *firstp)
case ASCASL:
case ASCASQ:
case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
case AOUTSB:
case AOUTSL:
case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
break;
}
}
@@ -574,6 +667,24 @@ loop2:
dumpit("pass4", firstr);
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -726,6 +837,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
+ a->node = v->node;
// need to clean this up with wptr and
// some of the defaults
@@ -818,6 +930,7 @@ mkvar(Reg *r, Adr *a)
{
Var *v;
int i, t, n, et, z, w, flag;
+ uint32 regu;
int32 o;
Bits bit;
Sym *s;
@@ -829,14 +942,17 @@ mkvar(Reg *r, Adr *a)
if(t == D_NONE)
goto none;
- if(r != R) {
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
- }
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
switch(t) {
default:
- goto none;
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
case D_ADDR:
a->type = a->index;
@@ -906,6 +1022,7 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
+ v->node = a->node;
if(debug['R'])
print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 320f4c9e9..4c04112b7 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -698,7 +698,7 @@ asmb(void)
{
int32 magic;
int a, dynsym;
- vlong vl, startva, symo, elfsymo, elfstro, elfsymsize, machlink;
+ vlong vl, startva, symo, machlink;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -709,9 +709,6 @@ asmb(void)
Bflush(&bso);
elftextsh = 0;
- elfsymsize = 0;
- elfstro = 0;
- elfsymo = 0;
if(debug['v'])
Bprint(&bso, "%5.2f codeblk\n", cputime());
@@ -790,36 +787,13 @@ asmb(void)
symo = rnd(symo, PEFILEALIGN);
break;
}
+ seek(cout, symo, 0);
switch(HEADTYPE) {
default:
if(iself) {
- /*
- * the symbol information is stored as
- * 32-bit symbol table size
- * 32-bit line number table size
- * symbol table
- * line number table
- */
- seek(cout, symo+8, 0);
- if(debug['v'])
- Bprint(&bso, "%5.2f sp\n", cputime());
- Bflush(&bso);
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
+ asmelfsym();
cflush();
- elfsymo = symo+8+symsize+lcsize;
- seek(cout, elfsymo, 0);
- asmelfsym64();
- cflush();
- elfstro = seek(cout, 0, 1);
- elfsymsize = elfstro - elfsymo;
ewrite(cout, elfstrdat, elfstrsize);
if(debug['v'])
@@ -830,7 +804,6 @@ asmb(void)
break;
case Hdarwin:
case Hwindows:
- seek(cout, symo, 0);
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -1054,15 +1027,15 @@ asmb(void)
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
+ sh->off = symo;
+ sh->size = symsize;
sh->addralign = 8;
sh->entsize = 24;
sh->link = eh->shnum; // link to strtab
sh = newElfShdr(elfstr[ElfStrStrtab]);
sh->type = SHT_STRTAB;
- sh->off = elfstro;
+ sh->off = symo+symsize;
sh->size = elfstrsize;
sh->addralign = 1;
@@ -1149,6 +1122,10 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Auto *a;
Sym *s;
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
for(s=allsym; s!=S; s=s->allsym) {
if(s->hide)
continue;
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 57cd1b56b..7da60d767 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -25,6 +25,7 @@ struct Addr
Sym* gotype;
Sym* sym;
+ Node* node;
int width;
uchar type;
uchar index;
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 5ad35fdce..6bcc3eed8 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -1720,6 +1720,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->index = D_NONE;
a->type = D_NONE;
a->gotype = S;
+ a->node = N;
if(n == N)
return;
@@ -1777,6 +1778,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->type = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 1465d372c..a2f3def37 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -33,6 +33,8 @@
#define EXTERN
#include "opt.h"
+#define NREGVAR 8
+#define REGBITS ((uint32)0xff)
#define P2R(p) (Reg*)(p->reg)
static int first = 1;
@@ -114,6 +116,8 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = { ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di" };
+
void
regopt(Prog *firstp)
{
@@ -142,7 +146,17 @@ regopt(Prog *firstp)
r1 = R;
firstr = R;
lastr = R;
- nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -249,14 +263,19 @@ regopt(Prog *firstp)
/*
* right side write
*/
+ case AFSTSW:
+ case ALEAL:
case ANOP:
case AMOVL:
case AMOVB:
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
case AMOVWLSX:
case AMOVWLZX:
+ case APOPL:
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
@@ -321,6 +340,23 @@ regopt(Prog *firstp)
case AADCL:
case ASBBL:
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
case AXCHGB:
case AXCHGW:
case AXCHGL:
@@ -349,20 +385,32 @@ regopt(Prog *firstp)
if(p->to.type != D_NONE)
break;
- case AIDIVB:
case AIDIVL:
case AIDIVW:
- case AIMULB:
- case ADIVB:
case ADIVL:
case ADIVW:
- case AMULB:
case AMULL:
case AMULW:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
case ACWD:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
case ACDQ:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
break;
case AREP:
@@ -370,7 +418,8 @@ regopt(Prog *firstp)
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
- r->regu |= RtoB(D_CX);
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
break;
case AMOVSB:
@@ -379,7 +428,8 @@ regopt(Prog *firstp)
case ACMPSB:
case ACMPSL:
case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
@@ -388,16 +438,22 @@ regopt(Prog *firstp)
case ASCASB:
case ASCASL:
case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
case AOUTSB:
case AOUTSL:
case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
break;
}
}
@@ -504,6 +560,24 @@ loop2:
dumpit("pass4", firstr);
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -656,6 +730,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
+ a->node = v->node;
// need to clean this up with wptr and
// some of the defaults
@@ -732,7 +807,7 @@ Bits
mkvar(Reg *r, Adr *a)
{
Var *v;
- int i, t, n, et, z, w, flag;
+ int i, t, n, et, z, w, flag, regu;
int32 o;
Bits bit;
Sym *s;
@@ -744,14 +819,17 @@ mkvar(Reg *r, Adr *a)
if(t == D_NONE)
goto none;
- if(r != R) {
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
- }
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
switch(t) {
default:
- goto none;
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
case D_ADDR:
a->type = a->index;
@@ -821,6 +899,7 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
+ v->node = a->node;
if(debug['R'])
print("bit=%2d et=%2d w=%d %S %D flag=%d\n", i, et, w, s, a, v->addr);
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index c426a88a4..cb900d28d 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -663,7 +663,7 @@ asmb(void)
{
int32 v, magic;
int a, dynsym;
- uint32 symo, startva, machlink, elfsymo, elfstro, elfsymsize;
+ uint32 symo, startva, machlink;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -675,10 +675,6 @@ asmb(void)
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- elfsymsize = 0;
- elfstro = 0;
- elfsymo = 0;
-
sect = segtext.sect;
seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
codeblk(sect->vaddr, sect->len);
@@ -724,10 +720,10 @@ asmb(void)
if(iself)
goto Elfsym;
case Hgarbunix:
- seek(cout, rnd(HEADR+segtext.filelen, 8192)+segdata.filelen, 0);
+ symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
break;
case Hunixcoff:
- seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
break;
case Hplan9x32:
symo = HEADR+segtext.filelen+segdata.filelen;
@@ -749,17 +745,14 @@ asmb(void)
symo = rnd(symo, PEFILEALIGN);
break;
}
+ seek(cout, symo, 0);
switch(HEADTYPE) {
default:
if(iself) {
if(debug['v'])
Bprint(&bso, "%5.2f elfsym\n", cputime());
- elfsymo = symo+8+symsize+lcsize;
- seek(cout, elfsymo, 0);
- asmelfsym32();
+ asmelfsym();
cflush();
- elfstro = seek(cout, 0, 1);
- elfsymsize = elfstro - elfsymo;
ewrite(cout, elfstrdat, elfstrsize);
if(debug['v'])
@@ -768,10 +761,9 @@ asmb(void)
}
break;
case Hplan9x32:
- seek(cout, symo, 0);
asmplan9sym();
cflush();
-
+
sym = lookup("pclntab", 0);
if(sym != nil) {
lcsize = sym->np;
@@ -783,7 +775,6 @@ asmb(void)
break;
case Hdarwin:
case Hwindows:
- seek(cout, symo, 0);
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
@@ -1110,15 +1101,15 @@ asmb(void)
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
+ sh->off = symo;
+ sh->size = symsize;
sh->addralign = 4;
sh->entsize = 16;
sh->link = eh->shnum; // link to strtab
sh = newElfShdr(elfstr[ElfStrStrtab]);
sh->type = SHT_STRTAB;
- sh->off = elfstro;
+ sh->off = symo+symsize;
sh->size = elfstrsize;
sh->addralign = 1;
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 8f39ef519..7e7cd5d63 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -260,11 +260,15 @@ EXTERN union
#define cbuf u.obuf
#define xbuf u.ibuf
-#pragma varargck type "A" uint
+#pragma varargck type "A" int
#pragma varargck type "D" Adr*
+#pragma varargck type "I" int
+#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
+#pragma varargck type "Y" Sym*
+#pragma varargck type "i" char*
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
@@ -383,11 +387,6 @@ void deadcode(void);
#define WPUT(a) wputl(a)
#define VPUT(a) vputl(a)
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "A" int
-
/* Used by ../ld/dwarf.c */
enum
{
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index fa7602cf2..10411e94f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -660,11 +660,14 @@ func (p *Package) gccName() (ret string) {
}
// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
-func (p *Package) gccMachine() string {
- if p.PtrSize == 8 {
- return "-m64"
- }
- return "-m32"
+func (p *Package) gccMachine() []string {
+ switch runtime.GOARCH {
+ case "amd64":
+ return []string{"-m64"}
+ case "386":
+ return []string{"-m32"}
+ }
+ return nil
}
const gccTmp = "_obj/_cgo_.o"
@@ -674,7 +677,6 @@ const gccTmp = "_obj/_cgo_.o"
func (p *Package) gccCmd() []string {
c := []string{
p.gccName(),
- p.gccMachine(),
"-Wall", // many warnings
"-Werror", // warnings are errors
"-o" + gccTmp, // write object to tmp
@@ -684,6 +686,7 @@ func (p *Package) gccCmd() []string {
"-xc", // input language is C
}
c = append(c, p.GccOptions...)
+ c = append(c, p.gccMachine()...)
c = append(c, "-") //read input from standard input
return c
}
@@ -719,7 +722,8 @@ func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
// #defines that gcc encountered while processing the input
// and its included files.
func (p *Package) gccDefines(stdin []byte) string {
- base := []string{p.gccName(), p.gccMachine(), "-E", "-dM", "-xc"}
+ base := []string{p.gccName(), "-E", "-dM", "-xc"}
+ base = append(base, p.gccMachine()...)
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
return stdout
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 78c676346..83be82f92 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -438,20 +438,6 @@ newtype(Sym *s)
return t;
}
-/*
- * type check top level declarations
- */
-void
-dclchecks(void)
-{
- NodeList *l;
-
- for(l=externdcl; l; l=l->next) {
- if(l->n->op != ONAME)
- continue;
- typecheck(&l->n, Erv);
- }
-}
/*
* := declarations
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 0b6f5bbd8..feb55e905 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -51,6 +51,8 @@ allocparams(void)
}
if(n->op != ONAME || n->class != PAUTO)
continue;
+ if (n->xoffset != BADWIDTH)
+ continue;
if(n->type == T)
continue;
dowidth(n->type);
@@ -669,14 +671,18 @@ dotoffset(Node *n, int *oary, Node **nn)
* make a new off the books
*/
void
-tempname(Node *n, Type *t)
+tempname(Node *nn, Type *t)
{
+ Node *n;
Sym *s;
uint32 w;
if(stksize < 0)
fatal("tempname not during code generation");
+ if (curfn == N)
+ fatal("no curfn for tempname");
+
if(t == T) {
yyerror("tempname called with nil type");
t = types[TINT32];
@@ -687,14 +693,15 @@ tempname(Node *n, Type *t)
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
- memset(n, 0, sizeof(*n));
- n->op = ONAME;
+ n = nod(ONAME, N, N);
n->sym = s;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
n->noescape = 1;
+ n->curfn = curfn;
+ curfn->dcl = list(curfn->dcl, n);
dowidth(t);
w = t->width;
@@ -703,5 +710,8 @@ tempname(Node *n, Type *t)
if(thechar == '5')
stksize = rnd(stksize, widthptr);
n->xoffset = -stksize;
- n->pun = anyregalloc();
+
+ // print("\ttmpname (%d): %N\n", stksize, n);
+
+ *nn = *n;
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index f5c0443f8..86db48391 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -225,7 +225,7 @@ struct Node
Type* realtype; // as determined by typecheck
NodeList* list;
NodeList* rlist;
- Node* orig; // original form, for printing
+ Node* orig; // original form, for printing, and tracking copies of ONAMEs
// for-body
NodeList* ninit;
@@ -273,6 +273,7 @@ struct Node
int32 lineno;
int32 endlineno;
vlong xoffset;
+ int32 stkdelta; // offset added by stack frame compaction phase.
int32 ostk;
int32 iota;
};
@@ -547,6 +548,7 @@ struct Var
vlong offset;
Sym* sym;
Sym* gotype;
+ Node* node;
int width;
char name;
char etype;
@@ -862,7 +864,6 @@ NodeList* checkarglist(NodeList *all, int input);
Node* colas(NodeList *left, NodeList *right);
void colasdefn(NodeList *left, Node *defn);
NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
-void dclchecks(void);
Node* dclname(Sym *s);
void declare(Node *n, int ctxt);
Type* dostruct(NodeList *l, int et);
@@ -1108,6 +1109,7 @@ int istype(Type *t, int et);
void linehist(char *file, int32 off, int relative);
NodeList* list(NodeList *l, Node *n);
NodeList* list1(Node *n);
+void listsort(NodeList**, int(*f)(Node*, Node*));
Node* liststmt(NodeList *l);
NodeList* listtreecopy(NodeList *l);
Sym* lookup(char *name);
@@ -1166,6 +1168,11 @@ int exportassignok(Type *t, char *desc);
int islvalue(Node *n);
Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
+Node* typecheckdef(Node *n);
+void resumetypecopy(void);
+void copytype(Node *n, Type *t);
+void defertypecopy(Node *n, Type *t);
+void queuemethod(Node *n);
/*
* unsafe.c
@@ -1177,15 +1184,10 @@ Node* unsafenmagic(Node *n);
*/
Node* callnew(Type *t);
Node* chanfn(char *name, int n, Type *t);
-void copytype(Node *n, Type *t);
-void defertypecopy(Node *n, Type *t);
Node* mkcall(char *name, Type *t, NodeList **init, ...);
Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
-void queuemethod(Node *n);
-void resumetypecopy(void);
int vmatch1(Node *l, Node *r);
void walk(Node *fn);
-Node* walkdef(Node *n);
void walkexpr(Node **np, NodeList **init);
void walkexprlist(NodeList *l, NodeList **init);
void walkexprlistsafe(NodeList *l, NodeList **init);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index fdaab4fa4..1278c2586 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1792,24 +1792,12 @@ hidden_opt_sym:
}
hidden_dcl:
- hidden_opt_sym hidden_type
+ hidden_opt_sym hidden_type hidden_tag
{
$$ = nod(ODCLFIELD, $1, typenod($2));
+ $$->val = $3;
}
-| hidden_opt_sym LDDD
- {
- Type *t;
-
- yyerror("invalid variadic function type in import - recompile import");
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = typ(TINTER);
- $$ = nod(ODCLFIELD, $1, typenod(t));
- $$->isddd = 1;
- }
-
-| hidden_opt_sym LDDD hidden_type
+| hidden_opt_sym LDDD hidden_type hidden_tag
{
Type *t;
@@ -1818,6 +1806,7 @@ hidden_dcl:
t->type = $3;
$$ = nod(ODCLFIELD, $1, typenod(t));
$$->isddd = 1;
+ $$->val = $4;
}
hidden_structdcl:
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 5e2f73fc5..88acb60af 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -5,7 +5,7 @@
#define EXTERN
#include "go.h"
#include "y.tab.h"
-#include <ar.h>
+#include <ar.h>
#undef getc
#undef ungetc
@@ -274,7 +274,9 @@ main(int argc, char *argv[])
funccompile(l->n, 1);
}
- dclchecks();
+ for(l=externdcl; l; l=l->next)
+ if(l->n->op == ONAME)
+ typecheck(&l->n, Erv);
if(nerrors)
errorexit();
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 9bd845dde..ab6186697 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#undef EXTERN
-#define EXTERN
-#include "gg.h"
-#include "opt.h"
+#include "gg.h"
+#include "opt.h"
+
+static void compactframe(Prog* p);
void
compile(Node *fn)
@@ -16,6 +16,7 @@ compile(Node *fn)
int32 lno;
Type *t;
Iter save;
+ vlong oldstksize;
if(newproc == N) {
newproc = sysfunc("newproc");
@@ -109,11 +110,115 @@ compile(Node *fn)
regopt(ptxt);
}
+ oldstksize = stksize;
+ if(thechar != '5')
+ compactframe(ptxt);
+ if(0)
+ print("compactframe: %ld to %ld\n", oldstksize, stksize);
+
defframe(ptxt);
- if(debug['f'])
+ if(0)
frame(0);
ret:
lineno = lno;
}
+
+
+// Sort the list of stack variables. autos after anything else,
+// within autos, unused after used, and within used on reverse alignment.
+// non-autos sort on offset.
+static int
+cmpstackvar(Node *a, Node *b)
+{
+ if (a->class != b->class)
+ return (a->class == PAUTO) ? 1 : -1;
+ if (a->class != PAUTO)
+ return a->xoffset - b->xoffset;
+ if ((a->used == 0) != (b->used == 0))
+ return b->used - a->used;
+ return b->type->align - a->type->align;
+
+}
+
+static void
+compactframe(Prog* ptxt)
+{
+ NodeList *ll;
+ Node* n;
+ Prog *p;
+ uint32 w;
+
+ if (stksize == 0)
+ return;
+
+ // Mark the PAUTO's unused.
+ for(ll=curfn->dcl; ll != nil; ll=ll->next)
+ if (ll->n->class == PAUTO && ll->n->op == ONAME)
+ ll->n->used = 0;
+
+ // Sweep the prog list to mark any used nodes.
+ for (p = ptxt; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+
+ listsort(&curfn->dcl, cmpstackvar);
+
+ // Unused autos are at the end, chop 'em off.
+ ll = curfn->dcl;
+ n = ll->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ curfn->dcl = nil;
+ stksize = 0;
+ return;
+ }
+
+ for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
+ n = ll->next->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ ll->next = nil;
+ curfn->dcl->end = ll;
+ break;
+ }
+ }
+
+ // Reassign stack offsets of the locals that are still there.
+ stksize = 0;
+ for(ll = curfn->dcl; ll != nil; ll=ll->next) {
+ n = ll->n;
+ // TODO find out where the literal autos come from
+ if (n->class != PAUTO || n->op != ONAME)
+ continue;
+
+ w = n->type->width;
+ if((w >= MAXWIDTH) || (w < 1))
+ fatal("bad width");
+ stksize += w;
+ stksize = rnd(stksize, n->type->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
+ n->stkdelta = -stksize - n->xoffset;
+ }
+
+ // Fixup instructions.
+ for (p = ptxt; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+
+ // The debug information needs accurate offsets on the symbols.
+ for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
+ if (ll->n->class != PAUTO || ll->n->op != ONAME)
+ continue;
+ ll->n->xoffset += ll->n->stkdelta;
+ ll->n->stkdelta = 0;
+ }
+}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index e03a14080..e88e0f844 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -134,6 +134,10 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "(node %O)", n->op);
break;
+ case OREGISTER:
+ fmtprint(f, "%R", n->val.u.reg);
+ break;
+
case OLITERAL:
if(n->sym != S) {
fmtprint(f, "%S", n->sym);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 4c0819cd8..49797f9df 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -105,7 +105,7 @@ hcrash(void)
flusherrors();
if(outfile)
unlink(outfile);
- *(int*)0 = 0;
+ *(volatile int*)0 = 0;
}
}
@@ -480,6 +480,7 @@ nod(int op, Node *nleft, Node *nright)
n->right = nright;
n->lineno = parserline();
n->xoffset = BADWIDTH;
+ n->orig = n;
return n;
}
@@ -1031,10 +1032,21 @@ Econv(Fmt *fp)
return fmtstrcpy(fp, etnames[et]);
}
+static const char* classnames[] = {
+ "Pxxx",
+ "PEXTERN",
+ "PAUTO",
+ "PPARAM",
+ "PPARAMOUT",
+ "PPARAMREF",
+ "PFUNC",
+};
+
int
Jconv(Fmt *fp)
{
Node *n;
+ char *s;
n = va_arg(fp->args, Node*);
if(n->ullman != 0)
@@ -1049,12 +1061,18 @@ Jconv(Fmt *fp)
if(n->lineno != 0)
fmtprint(fp, " l(%d)", n->lineno);
- if(n->xoffset != 0)
- fmtprint(fp, " x(%lld)", n->xoffset);
-
- if(n->class != 0)
- fmtprint(fp, " class(%d)", n->class);
+ if(n->xoffset != BADWIDTH)
+ fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
+ if(n->class != 0) {
+ s = "";
+ if (n->class & PHEAP) s = ",heap";
+ if ((n->class & ~PHEAP) < nelem(classnames))
+ fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
+ else
+ fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
+ }
+
if(n->colas != 0)
fmtprint(fp, " colas(%d)", n->colas);
@@ -1076,6 +1094,8 @@ Jconv(Fmt *fp)
if(n->pun != 0)
fmtprint(fp, " pun(%d)", n->pun);
+ if(n->used != 0)
+ fmtprint(fp, " used(%d)", n->used);
return 0;
}
@@ -3339,6 +3359,64 @@ list(NodeList *l, Node *n)
return concat(l, list1(n));
}
+void
+listsort(NodeList** l, int(*f)(Node*, Node*))
+{
+ NodeList *l1, *l2, *le;
+
+ if(*l == nil || (*l)->next == nil)
+ return;
+
+ l1 = *l;
+ l2 = *l;
+ for(;;) {
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = nil;
+ l2->end = (*l)->end;
+ (*l)->end = l1;
+
+ l1 = *l;
+ listsort(&l1, f);
+ listsort(&l2, f);
+
+ if ((*f)(l1->n, l2->n) < 0) {
+ *l = l1;
+ } else {
+ *l = l2;
+ l2 = l1;
+ l1 = *l;
+ }
+
+ // now l1 == *l; and l1 < l2
+
+ while ((l1 != nil) && (l2 != nil)) {
+ while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
+ l1 = l1->next;
+
+ // l1 is last one from l1 that is < l2
+ le = l1->next; // le is the rest of l1, first one that is >= l2
+ if (le != nil)
+ le->end = (*l)->end;
+
+ (*l)->end = l1; // cut *l at l1
+ *l = concat(*l, l2); // glue l2 to *l's tail
+
+ l1 = l2; // l1 is the first element of *l that is < the new l2
+ l2 = le; // ... because l2 now is the old tail of l1
+ }
+
+ *l = concat(*l, l2); // any remainder
+}
+
NodeList*
listtreecopy(NodeList *l)
{
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 44d08352d..04dc1a507 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -8,7 +8,6 @@
* evaluates compile time constants.
* marks variables that escape the local frame.
* rewrites n->op to be more specific in some cases.
- * sets n->walk to walking function.
*/
#include "go.h"
@@ -33,6 +32,8 @@ static void stringtoarraylit(Node**);
static Node* resolve(Node*);
static Type* getforwtype(Node*);
+static NodeList* typecheckdefstack;
+
/*
* resolve ONONAME to definition, if any.
*/
@@ -159,7 +160,7 @@ typecheck(Node **np, int top)
if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
defertypecopy(n, ft);
- walkdef(n);
+ typecheckdef(n);
n->realtype = n->type;
if(n->op == ONONAME)
goto error;
@@ -2523,3 +2524,294 @@ getforwtype(Node *n)
}
}
}
+
+static int ntypecheckdeftype;
+static NodeList *methodqueue;
+
+static void
+domethod(Node *n)
+{
+ Node *nt;
+
+ nt = n->type->nname;
+ typecheck(&nt, Etype);
+ if(nt->type == T) {
+ // type check failed; leave empty func
+ n->type->etype = TFUNC;
+ n->type->nod = N;
+ return;
+ }
+ *n->type = *nt->type;
+ n->type->nod = N;
+ checkwidth(n->type);
+}
+
+typedef struct NodeTypeList NodeTypeList;
+struct NodeTypeList {
+ Node *n;
+ Type *t;
+ NodeTypeList *next;
+};
+
+static NodeTypeList *dntq;
+static NodeTypeList *dntend;
+
+void
+defertypecopy(Node *n, Type *t)
+{
+ NodeTypeList *ntl;
+
+ if(n == N || t == T)
+ return;
+
+ ntl = mal(sizeof *ntl);
+ ntl->n = n;
+ ntl->t = t;
+ ntl->next = nil;
+
+ if(dntq == nil)
+ dntq = ntl;
+ else
+ dntend->next = ntl;
+
+ dntend = ntl;
+}
+
+void
+resumetypecopy(void)
+{
+ NodeTypeList *l;
+
+ for(l=dntq; l; l=l->next)
+ copytype(l->n, l->t);
+}
+
+void
+copytype(Node *n, Type *t)
+{
+ *n->type = *t;
+
+ t = n->type;
+ t->sym = n->sym;
+ t->local = n->local;
+ t->vargen = n->vargen;
+ t->siggen = 0;
+ t->method = nil;
+ t->nod = N;
+ t->printed = 0;
+ t->deferwidth = 0;
+}
+
+static void
+typecheckdeftype(Node *n)
+{
+ int maplineno, embedlineno, lno;
+ Type *t;
+ NodeList *l;
+
+ ntypecheckdeftype++;
+ lno = lineno;
+ setlineno(n);
+ n->type->sym = n->sym;
+ n->typecheck = 1;
+ typecheck(&n->ntype, Etype);
+ if((t = n->ntype->type) == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+
+ maplineno = n->type->maplineno;
+ embedlineno = n->type->embedlineno;
+
+ // copy new type and clear fields
+ // that don't come along.
+ // anything zeroed here must be zeroed in
+ // typedcl2 too.
+ copytype(n, t);
+
+ // double-check use of type as map key.
+ if(maplineno) {
+ lineno = maplineno;
+ maptype(n->type, types[TBOOL]);
+ }
+ if(embedlineno) {
+ lineno = embedlineno;
+ if(isptr[t->etype])
+ yyerror("embedded type cannot be a pointer");
+ }
+
+ret:
+ lineno = lno;
+
+ // if there are no type definitions going on, it's safe to
+ // try to resolve the method types for the interfaces
+ // we just read.
+ if(ntypecheckdeftype == 1) {
+ while((l = methodqueue) != nil) {
+ methodqueue = nil;
+ for(; l; l=l->next)
+ domethod(l->n);
+ }
+ }
+ ntypecheckdeftype--;
+}
+
+void
+queuemethod(Node *n)
+{
+ if(ntypecheckdeftype == 0) {
+ domethod(n);
+ return;
+ }
+ methodqueue = list(methodqueue, n);
+}
+
+Node*
+typecheckdef(Node *n)
+{
+ int lno;
+ Node *e;
+ Type *t;
+ NodeList *l;
+
+ lno = lineno;
+ setlineno(n);
+
+ if(n->op == ONONAME) {
+ if(!n->diag) {
+ n->diag = 1;
+ if(n->lineno != 0)
+ lineno = n->lineno;
+ yyerror("undefined: %S", n->sym);
+ }
+ return n;
+ }
+
+ if(n->walkdef == 1)
+ return n;
+
+ l = mal(sizeof *l);
+ l->n = n;
+ l->next = typecheckdefstack;
+ typecheckdefstack = l;
+
+ if(n->walkdef == 2) {
+ flusherrors();
+ print("typecheckdef loop:");
+ for(l=typecheckdefstack; l; l=l->next)
+ print(" %S", l->n->sym);
+ print("\n");
+ fatal("typecheckdef loop");
+ }
+ n->walkdef = 2;
+
+ if(n->type != T || n->sym == S) // builtin or no name
+ goto ret;
+
+ switch(n->op) {
+ default:
+ fatal("typecheckdef %O", n->op);
+
+ case OLITERAL:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ n->ntype = N;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ e = n->defn;
+ n->defn = N;
+ if(e == N) {
+ lineno = n->lineno;
+ dump("typecheckdef nil defn", n);
+ yyerror("xxx");
+ }
+ typecheck(&e, Erv | Eiota);
+ if(e->type != T && e->op != OLITERAL) {
+ yyerror("const initializer must be constant");
+ goto ret;
+ }
+ if(isconst(e, CTNIL)) {
+ yyerror("const initializer cannot be nil");
+ goto ret;
+ }
+ t = n->type;
+ if(t != T) {
+ if(!okforconst[t->etype]) {
+ yyerror("invalid constant type %T", t);
+ goto ret;
+ }
+ if(!isideal(e->type) && !eqtype(t, e->type)) {
+ yyerror("cannot use %+N as type %T in const initializer", e, t);
+ goto ret;
+ }
+ convlit(&e, t);
+ }
+ n->val = e->val;
+ n->type = e->type;
+ break;
+
+ case ONAME:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ if(n->type != T)
+ break;
+ if(n->defn == N) {
+ if(n->etype != 0) // like OPRINTN
+ break;
+ if(nerrors > 0) {
+ // Can have undefined variables in x := foo
+ // that make x have an n->ndefn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break;
+ }
+ fatal("var without type, init: %S", n->sym);
+ }
+ if(n->defn->op == ONAME) {
+ typecheck(&n->defn, Erv);
+ n->type = n->defn->type;
+ break;
+ }
+ typecheck(&n->defn, Etop); // fills in n->type
+ break;
+
+ case OTYPE:
+ if(curfn)
+ defercheckwidth();
+ n->walkdef = 1;
+ n->type = typ(TFORW);
+ n->type->sym = n->sym;
+ typecheckdeftype(n);
+ if(curfn)
+ resumecheckwidth();
+ break;
+
+ case OPACK:
+ // nothing to see here
+ break;
+ }
+
+ret:
+ if(typecheckdefstack->n != n)
+ fatal("typecheckdefstack mismatch");
+ l = typecheckdefstack;
+ typecheckdefstack = l->next;
+
+ lineno = lno;
+ n->walkdef = 1;
+ return n;
+}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index ccc65ff21..65a504bff 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -21,8 +21,6 @@ static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
-static NodeList* walkdefstack;
-
// can this code branch reach the end
// without an unconditional RETURN
// this is hard, so it is conservative
@@ -100,296 +98,6 @@ walk(Node *fn)
}
}
-static int nwalkdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
- Node *nt;
-
- nt = n->type->nname;
- typecheck(&nt, Etype);
- if(nt->type == T) {
- // type check failed; leave empty func
- n->type->etype = TFUNC;
- n->type->nod = N;
- return;
- }
- *n->type = *nt->type;
- n->type->nod = N;
- checkwidth(n->type);
-}
-
-typedef struct NodeTypeList NodeTypeList;
-struct NodeTypeList {
- Node *n;
- Type *t;
- NodeTypeList *next;
-};
-
-static NodeTypeList *dntq;
-static NodeTypeList *dntend;
-
-void
-defertypecopy(Node *n, Type *t)
-{
- NodeTypeList *ntl;
-
- if(n == N || t == T)
- return;
-
- ntl = mal(sizeof *ntl);
- ntl->n = n;
- ntl->t = t;
- ntl->next = nil;
-
- if(dntq == nil)
- dntq = ntl;
- else
- dntend->next = ntl;
-
- dntend = ntl;
-}
-
-void
-resumetypecopy(void)
-{
- NodeTypeList *l;
-
- for(l=dntq; l; l=l->next)
- copytype(l->n, l->t);
-}
-
-void
-copytype(Node *n, Type *t)
-{
- *n->type = *t;
-
- t = n->type;
- t->sym = n->sym;
- t->local = n->local;
- t->vargen = n->vargen;
- t->siggen = 0;
- t->method = nil;
- t->nod = N;
- t->printed = 0;
- t->deferwidth = 0;
-}
-
-static void
-walkdeftype(Node *n)
-{
- int maplineno, embedlineno, lno;
- Type *t;
- NodeList *l;
-
- nwalkdeftype++;
- lno = lineno;
- setlineno(n);
- n->type->sym = n->sym;
- n->typecheck = 1;
- typecheck(&n->ntype, Etype);
- if((t = n->ntype->type) == T) {
- n->diag = 1;
- goto ret;
- }
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
-
- maplineno = n->type->maplineno;
- embedlineno = n->type->embedlineno;
-
- // copy new type and clear fields
- // that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
- copytype(n, t);
-
- // double-check use of type as map key.
- if(maplineno) {
- lineno = maplineno;
- maptype(n->type, types[TBOOL]);
- }
- if(embedlineno) {
- lineno = embedlineno;
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- }
-
-ret:
- lineno = lno;
-
- // if there are no type definitions going on, it's safe to
- // try to resolve the method types for the interfaces
- // we just read.
- if(nwalkdeftype == 1) {
- while((l = methodqueue) != nil) {
- methodqueue = nil;
- for(; l; l=l->next)
- domethod(l->n);
- }
- }
- nwalkdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
- if(nwalkdeftype == 0) {
- domethod(n);
- return;
- }
- methodqueue = list(methodqueue, n);
-}
-
-Node*
-walkdef(Node *n)
-{
- int lno;
- Node *e;
- Type *t;
- NodeList *l;
-
- lno = lineno;
- setlineno(n);
-
- if(n->op == ONONAME) {
- if(!n->diag) {
- n->diag = 1;
- if(n->lineno != 0)
- lineno = n->lineno;
- yyerror("undefined: %S", n->sym);
- }
- return n;
- }
-
- if(n->walkdef == 1)
- return n;
-
- l = mal(sizeof *l);
- l->n = n;
- l->next = walkdefstack;
- walkdefstack = l;
-
- if(n->walkdef == 2) {
- flusherrors();
- print("walkdef loop:");
- for(l=walkdefstack; l; l=l->next)
- print(" %S", l->n->sym);
- print("\n");
- fatal("walkdef loop");
- }
- n->walkdef = 2;
-
- if(n->type != T || n->sym == S) // builtin or no name
- goto ret;
-
- switch(n->op) {
- default:
- fatal("walkdef %O", n->op);
-
- case OLITERAL:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- n->ntype = N;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- e = n->defn;
- n->defn = N;
- if(e == N) {
- lineno = n->lineno;
- dump("walkdef nil defn", n);
- yyerror("xxx");
- }
- typecheck(&e, Erv | Eiota);
- if(e->type != T && e->op != OLITERAL) {
- yyerror("const initializer must be constant");
- goto ret;
- }
- if(isconst(e, CTNIL)) {
- yyerror("const initializer cannot be nil");
- goto ret;
- }
- t = n->type;
- if(t != T) {
- if(!okforconst[t->etype]) {
- yyerror("invalid constant type %T", t);
- goto ret;
- }
- if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %+N as type %T in const initializer", e, t);
- goto ret;
- }
- convlit(&e, t);
- }
- n->val = e->val;
- n->type = e->type;
- break;
-
- case ONAME:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- if(n->type != T)
- break;
- if(n->defn == N) {
- if(n->etype != 0) // like OPRINTN
- break;
- if(nerrors > 0) {
- // Can have undefined variables in x := foo
- // that make x have an n->ndefn == nil.
- // If there are other errors anyway, don't
- // bother adding to the noise.
- break;
- }
- fatal("var without type, init: %S", n->sym);
- }
- if(n->defn->op == ONAME) {
- typecheck(&n->defn, Erv);
- n->type = n->defn->type;
- break;
- }
- typecheck(&n->defn, Etop); // fills in n->type
- break;
-
- case OTYPE:
- if(curfn)
- defercheckwidth();
- n->walkdef = 1;
- n->type = typ(TFORW);
- n->type->sym = n->sym;
- walkdeftype(n);
- if(curfn)
- resumecheckwidth();
- break;
-
- case OPACK:
- // nothing to see here
- break;
- }
-
-ret:
- if(walkdefstack->n != n)
- fatal("walkdefstack mismatch");
- l = walkdefstack;
- walkdefstack = l->next;
-
- lineno = lno;
- n->walkdef = 1;
- return n;
-}
void
walkstmtlist(NodeList *l)
diff --git a/src/cmd/godefs/a.h b/src/cmd/godefs/a.h
index 03ab91f65..9b4957467 100644
--- a/src/cmd/godefs/a.h
+++ b/src/cmd/godefs/a.h
@@ -75,6 +75,7 @@ extern Const *con;
extern int ncon;
extern Type **typ;
extern int ntyp;
+extern int kindsize[];
// Language output
typedef struct Lang Lang;
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
index d4163421d..6a8630179 100644
--- a/src/cmd/godefs/main.c
+++ b/src/cmd/godefs/main.c
@@ -181,7 +181,7 @@ main(int argc, char **argv)
char **av, *q, *r, *tofree, *name;
char nambuf[100];
Biobuf *bin, *bout;
- Type *t;
+ Type *t, *tt;
Field *f;
int orig_output_fd;
@@ -373,8 +373,16 @@ Continue:
prefix = prefixlen(t);
for(j=0; j<t->nf; j++) {
f = &t->f[j];
- if(f->type->kind == 0)
- continue;
+ if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
+ // unknown type but <= 64 bits and bit size is a power of two.
+ // could be enum - make Uint64 and then let it reduce
+ tt = emalloc(sizeof *tt);
+ *tt = *f->type;
+ f->type = tt;
+ tt->kind = Uint64;
+ while(tt->kind > Uint8 && kindsize[tt->kind] > f->size)
+ tt->kind -= 2;
+ }
// padding
if(t->kind == Struct || lang == &go) {
if(f->offset%8 != 0 || f->size%8 != 0) {
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
index 30a05fc70..2c3d431b8 100644
--- a/src/cmd/godefs/stabs.c
+++ b/src/cmd/godefs/stabs.c
@@ -149,7 +149,7 @@ Intrange intranges[] = {
16, 0, Void,
};
-static int kindsize[] = {
+int kindsize[] = {
0,
0,
8,
@@ -381,14 +381,6 @@ parsedef(char **pp, char *name)
while(f->type->kind == Typedef)
f->type = f->type->type;
- if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
- // unknown type but <= 64 bits and bit size is a power of two.
- // could be enum - make Uint64 and then let it reduce
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- tt->kind = Uint64;
- }
// rewrite
// uint32 x : 8;
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index d863ca0d8..444e36e08 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -129,6 +129,9 @@ func (p *ebnfParser) parseTerm() bool {
func (p *ebnfParser) parseSequence() {
+ if !p.parseTerm() {
+ p.errorExpected(p.pos, "term")
+ }
for p.parseTerm() {
}
}
@@ -148,7 +151,9 @@ func (p *ebnfParser) parseExpression() {
func (p *ebnfParser) parseProduction() {
p.parseIdentifier(true)
p.expect(token.ASSIGN)
- p.parseExpression()
+ if p.tok != token.PERIOD {
+ p.parseExpression()
+ }
p.expect(token.PERIOD)
}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
index ba2061a00..1b091c18a 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/gofix/main.go
@@ -248,5 +248,11 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) {
f1.Write(b1)
f2.Write(b2)
- return exec.Command("diff", f1.Name(), f2.Name()).CombinedOutput()
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
}
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 16bcd3c4d..ea1c1b00f 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -260,5 +260,12 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) {
f1.Write(b1)
f2.Write(b2)
- return exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
+
}
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
index f60ff9b32..5dce2ed7a 100755
--- a/src/cmd/gofmt/test.sh
+++ b/src/cmd/gofmt/test.sh
@@ -36,7 +36,7 @@ apply1() {
# the following files are skipped because they are test cases
# for syntax errors and thus won't parse in the first place:
case `basename "$F"` in
- func3.go | const2.go | char_lit1.go | blank1.go | \
+ func3.go | const2.go | char_lit1.go | blank1.go | ddd1.go | \
bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \
bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index 017978ced..0b5e608c7 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -1532,25 +1532,7 @@ arwrite(int fd, Armember *bp)
int
page(Arfile *ap)
{
- Armember *bp;
-
- bp = ap->head;
- if (!ap->paged) { /* not yet paged - create file */
- ap->fname = mktemp(ap->fname);
- ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
- if (ap->fd < 0) {
- fprint(2,"gopack: can't create temp file\n");
- return 0;
- }
- ap->paged = 1;
- }
- if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
- return 0;
- ap->head = bp->next;
- if (ap->tail == bp)
- ap->tail = bp->next;
- free(bp->member);
- free(bp);
+ sysfatal("page");
return 1;
}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index de600f555..1721def67 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1348,7 +1348,7 @@ synthesizemaptypes(DWDie *die)
valtype = defptrto(valtype);
newrefattr(fld, DW_AT_type, valtype);
newmemberoffsetattr(fld, hashsize + datavo);
- newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
+ newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
// Construct hash_subtable<hash_entry<K,V>>
dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1359,7 +1359,7 @@ synthesizemaptypes(DWDie *die)
substitutetype(dwhs, "end", defptrto(dwhe));
substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash_subtable, DW_AT_byte_size)->value, NULL);
+ getattr(hash_subtable, DW_AT_byte_size)->value, nil);
// Construct hash<K,V>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1369,7 +1369,7 @@ synthesizemaptypes(DWDie *die)
copychildren(dwh, hash);
substitutetype(dwh, "st", defptrto(dwhs));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash, DW_AT_byte_size)->value, NULL);
+ getattr(hash, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
@@ -1401,30 +1401,30 @@ synthesizechantypes(DWDie *die)
// sudog<T>
dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("sudog",
- getattr(elemtype, DW_AT_name)->data, NULL));
+ getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dws, sudog);
substitutetype(dws, "elem", elemtype);
newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
- sudogsize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+ sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
// waitq<T>
dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, NULL));
+ mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dww, waitq);
substitutetype(dww, "first", defptrto(dws));
substitutetype(dww, "last", defptrto(dws));
newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(waitq, DW_AT_byte_size)->value, NULL);
+ getattr(waitq, DW_AT_byte_size)->value, nil);
// hchan<T>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL));
+ mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dwh, hchan);
substitutetype(dwh, "recvq", dww);
substitutetype(dwh, "sendq", dww);
substitutetype(dwh, "free", defptrto(dws));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hchan, DW_AT_byte_size)->value, NULL);
+ getattr(hchan, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
@@ -1436,6 +1436,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
{
DWDie *dv, *dt;
+ USED(size);
if (strncmp(s, "go.string.", 10) == 0)
return;
@@ -1592,7 +1593,7 @@ addhistfile(char *zentry)
// if the histfile stack contains ..../runtime/runtime_defs.go
// use that to set gdbscript
static void
-finddebugruntimepath()
+finddebugruntimepath(void)
{
int i, l;
char *c;
@@ -1841,7 +1842,8 @@ writelines(void)
char *n, *nn;
unitstart = -1;
- epc = pc = 0;
+ pc = 0;
+ epc = 0;
lc = 1;
llc = 1;
currfile = -1;
@@ -1903,7 +1905,8 @@ writelines(void)
// 4 zeros: the string termination + 3 fields.
}
- epc = pc = s->text->pc;
+ pc = s->text->pc;
+ epc = pc;
currfile = 1;
lc = 1;
llc = 1;
@@ -1992,7 +1995,7 @@ writelines(void)
newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
// push dwvar down dwfunc->child to preserve order
- newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, NULL);
+ newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
dwfunc->child = dwvar->link; // take dwvar out from the top of the list
for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
if (offs > getattr(*dws, DW_AT_internal_location)->value)
@@ -2345,7 +2348,11 @@ dwarfemitdebugsections(void)
infoo = cpos();
writeinfo();
- gdbscripto = arangeso = pubtypeso = pubnameso = infoe = cpos();
+ infoe = cpos();
+ pubnameso = infoe;
+ pubtypeso = infoe;
+ arangeso = infoe;
+ gdbscripto = infoe;
if (fwdcount > 0) {
if (debug['v'])
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index a19fe460d..05d1cc136 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -415,8 +415,8 @@ loaddynimport(char *file, char *pkg, char *p, int n)
char *pend, *next, *name, *def, *p0, *lib, *q;
Sym *s;
+ USED(file);
pend = p + n;
- p0 = p;
for(; p<pend; p=next) {
next = strchr(p, '\n');
if(next == nil)
@@ -485,8 +485,8 @@ loaddynexport(char *file, char *pkg, char *p, int n)
char *pend, *next, *local, *elocal, *remote, *p0;
Sym *s;
+ USED(file);
pend = p + n;
- p0 = p;
for(; p<pend; p=next) {
next = strchr(p, '\n');
if(next == nil)
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 105d982e4..04ee790a4 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -69,7 +69,7 @@ libinit(void)
// add goroot to the end of the libdir list.
libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch);
- unlink(outfile);
+ remove(outfile);
cout = create(outfile, 1, 0775);
if(cout < 0) {
diag("cannot create %s", outfile);
@@ -235,24 +235,34 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
}
void
-loadlib(void)
+loadinternal(char *name)
{
char pname[1024];
int i, found;
found = 0;
for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/runtime.a", libdir[i]);
+ snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
if(debug['v'])
- Bprint(&bso, "searching for runtime.a in %s\n", pname);
+ Bprint(&bso, "searching for %s.a in %s\n", name, pname);
if(access(pname, AEXIST) >= 0) {
- addlibpath("internal", "internal", pname, "runtime");
+ addlibpath("internal", "internal", pname, name);
found = 1;
break;
}
}
if(!found)
- Bprint(&bso, "warning: unable to find runtime.a\n");
+ Bprint(&bso, "warning: unable to find %s.a\n", name);
+}
+
+void
+loadlib(void)
+{
+ int i;
+
+ loadinternal("runtime");
+ if(thechar == '5')
+ loadinternal("math");
for(i=0; i<libraryp; i++) {
if(debug['v'])
@@ -398,9 +408,6 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
eof = Boffset(f) + len;
pn = strdup(pn);
-
- USED(c4);
- USED(magic);
c1 = Bgetc(f);
c2 = Bgetc(f);
@@ -410,7 +417,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
Bungetc(f);
Bungetc(f);
Bungetc(f);
-
+
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
ldelf(f, pkg, len, pn);
@@ -498,7 +505,6 @@ _lookup(char *symb, int v, int creat)
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
- c = symb[0];
for(s = hash[h]; s != S; s = s->hash)
if(memcmp(s->name, symb, l) == 0)
return s;
@@ -523,7 +529,7 @@ _lookup(char *symb, int v, int creat)
s->size = 0;
hash[h] = s;
nsymbol++;
-
+
s->allsym = allsym;
allsym = s;
return s;
@@ -550,7 +556,6 @@ copyhistfrog(char *buf, int nbuf)
p = buf;
ep = buf + nbuf;
- i = 0;
for(i=0; i<histfrogp; i++) {
p = seprint(p, ep, "%s", histfrog[i]->name+1);
if(i+1<histfrogp && (p == buf || p[-1] != '/'))
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index f69f5a35d..dfd18fbff 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -186,8 +186,7 @@ vlong addsize(Sym*, Sym*);
vlong adduint8(Sym*, uint8);
vlong adduint16(Sym*, uint16);
void asmsym(void);
-void asmelfsym32(void);
-void asmelfsym64(void);
+void asmelfsym(void);
void asmplan9sym(void);
void strnput(char*, int);
void dodata(void);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index da698fcc0..e3093b2aa 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -61,49 +61,35 @@ putelfstr(char *s)
}
void
-putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
+ switch(thechar) {
+ case '6':
+ LPUT(off);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ VPUT(addr);
+ VPUT(size);
+ symsize += ELF64SYMSIZE;
break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
+ default:
+ LPUT(off);
+ LPUT(addr);
+ LPUT(size);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ symsize += ELF32SYMSIZE;
break;
}
-
- stroff = putelfstr(s);
- LPUT(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- WPUT(shndx);
- VPUT(addr);
- VPUT(size);
}
void
-asmelfsym64(void)
+putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
- genasmsym(putelfsym64);
-}
+ int bind, type, shndx, off;
-void
-putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
switch(t) {
default:
return;
@@ -113,27 +99,27 @@ putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
break;
case 'D':
type = STT_OBJECT;
- shndx = elftextsh + 1;
+ if((x->type&~SSUB) == SRODATA)
+ shndx = elftextsh + 1;
+ else
+ shndx = elftextsh + 2;
break;
case 'B':
type = STT_OBJECT;
- shndx = elftextsh + 2;
+ shndx = elftextsh + 3;
break;
}
-
- stroff = putelfstr(s);
- LPUT(stroff); // string
- LPUT(addr);
- LPUT(size);
- cput((bind<<4)|(type&0xF));
- cput(0);
- WPUT(shndx);
+ bind = ver ? STB_LOCAL : STB_GLOBAL;
+ off = putelfstr(s);
+ putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
}
void
-asmelfsym32(void)
+asmelfsym(void)
{
- genasmsym(putelfsym32);
+ // the first symbol entry is reserved
+ putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
+ genasmsym(putelfsym);
}
void
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
index 80aa4fe69..5a195baf8 100644
--- a/src/libmach/8db.c
+++ b/src/libmach/8db.c
@@ -62,32 +62,32 @@ static char LESSSTACK[] = "sys·lessstack";
static char MORESTACK[] = "sys·morestack";
static char *excname[] =
{
-[0] "divide error",
-[1] "debug exception",
-[4] "overflow",
-[5] "bounds check",
-[6] "invalid opcode",
-[7] "math coprocessor emulation",
-[8] "double fault",
-[9] "math coprocessor overrun",
-[10] "invalid TSS",
-[11] "segment not present",
-[12] "stack exception",
-[13] "general protection violation",
-[14] "page fault",
-[16] "math coprocessor error",
-[17] "alignment check",
-[18] "machine check",
-[19] "floating-point exception",
-[24] "clock",
-[25] "keyboard",
-[27] "modem status",
-[28] "serial line status",
-[30] "floppy disk",
-[36] "mouse",
-[37] "math coprocessor",
-[38] "hard disk",
-[64] "system call",
+[0] = "divide error",
+[1] = "debug exception",
+[4] = "overflow",
+[5] = "bounds check",
+[6] = "invalid opcode",
+[7] = "math coprocessor emulation",
+[8] = "double fault",
+[9] = "math coprocessor overrun",
+[10] = "invalid TSS",
+[11] = "segment not present",
+[12] = "stack exception",
+[13] = "general protection violation",
+[14] = "page fault",
+[16] = "math coprocessor error",
+[17] = "alignment check",
+[18] = "machine check",
+[19] = "floating-point exception",
+[24] = "clock",
+[25] = "keyboard",
+[27] = "modem status",
+[28] = "serial line status",
+[30] = "floppy disk",
+[36] = "mouse",
+[37] = "math coprocessor",
+[38] = "hard disk",
+[64] = "system call",
};
Machdata i386mach =
@@ -436,28 +436,28 @@ enum {
static Optable optab0F00[8]=
{
-[0x00] 0,0, "MOVW LDT,%e",
-[0x01] 0,0, "MOVW TR,%e",
-[0x02] 0,0, "MOVW %e,LDT",
-[0x03] 0,0, "MOVW %e,TR",
-[0x04] 0,0, "VERR %e",
-[0x05] 0,0, "VERW %e",
+[0x00] = { 0,0, "MOVW LDT,%e" },
+[0x01] = { 0,0, "MOVW TR,%e" },
+[0x02] = { 0,0, "MOVW %e,LDT" },
+[0x03] = { 0,0, "MOVW %e,TR" },
+[0x04] = { 0,0, "VERR %e" },
+[0x05] = { 0,0, "VERW %e" },
};
static Optable optab0F01[8]=
{
-[0x00] 0,0, "MOVL GDTR,%e",
-[0x01] 0,0, "MOVL IDTR,%e",
-[0x02] 0,0, "MOVL %e,GDTR",
-[0x03] 0,0, "MOVL %e,IDTR",
-[0x04] 0,0, "MOVW MSW,%e", /* word */
-[0x06] 0,0, "MOVW %e,MSW", /* word */
-[0x07] 0,0, "INVLPG %e", /* or SWAPGS */
+[0x00] = { 0,0, "MOVL GDTR,%e" },
+[0x01] = { 0,0, "MOVL IDTR,%e" },
+[0x02] = { 0,0, "MOVL %e,GDTR" },
+[0x03] = { 0,0, "MOVL %e,IDTR" },
+[0x04] = { 0,0, "MOVW MSW,%e" }, /* word */
+[0x06] = { 0,0, "MOVW %e,MSW" }, /* word */
+[0x07] = { 0,0, "INVLPG %e" }, /* or SWAPGS */
};
static Optable optab0F01F8[1]=
{
-[0x00] 0,0, "SWAPGS",
+[0x00] = { 0,0, "SWAPGS" },
};
/* 0F71 */
@@ -466,13 +466,13 @@ static Optable optab0F01F8[1]=
static Optable optab0FAE[8]=
{
-[0x00] 0,0, "FXSAVE %e",
-[0x01] 0,0, "FXRSTOR %e",
-[0x02] 0,0, "LDMXCSR %e",
-[0x03] 0,0, "STMXCSR %e",
-[0x05] 0,0, "LFENCE",
-[0x06] 0,0, "MFENCE",
-[0x07] 0,0, "SFENCE",
+[0x00] = { 0,0, "FXSAVE %e" },
+[0x01] = { 0,0, "FXRSTOR %e" },
+[0x02] = { 0,0, "LDMXCSR %e" },
+[0x03] = { 0,0, "STMXCSR %e" },
+[0x05] = { 0,0, "LFENCE" },
+[0x06] = { 0,0, "MFENCE" },
+[0x07] = { 0,0, "SFENCE" },
};
/* 0F18 */
@@ -480,455 +480,455 @@ static Optable optab0FAE[8]=
static Optable optab0FBA[8]=
{
-[0x04] Ib,0, "BT%S %i,%e",
-[0x05] Ib,0, "BTS%S %i,%e",
-[0x06] Ib,0, "BTR%S %i,%e",
-[0x07] Ib,0, "BTC%S %i,%e",
+[0x04] = { Ib,0, "BT%S %i,%e" },
+[0x05] = { Ib,0, "BTS%S %i,%e" },
+[0x06] = { Ib,0, "BTR%S %i,%e" },
+[0x07] = { Ib,0, "BTC%S %i,%e" },
};
static Optable optab0F0F[256]=
{
-[0x0c] 0,0, "PI2FW %m,%M",
-[0x0d] 0,0, "PI2L %m,%M",
-[0x1c] 0,0, "PF2IW %m,%M",
-[0x1d] 0,0, "PF2IL %m,%M",
-[0x8a] 0,0, "PFNACC %m,%M",
-[0x8e] 0,0, "PFPNACC %m,%M",
-[0x90] 0,0, "PFCMPGE %m,%M",
-[0x94] 0,0, "PFMIN %m,%M",
-[0x96] 0,0, "PFRCP %m,%M",
-[0x97] 0,0, "PFRSQRT %m,%M",
-[0x9a] 0,0, "PFSUB %m,%M",
-[0x9e] 0,0, "PFADD %m,%M",
-[0xa0] 0,0, "PFCMPGT %m,%M",
-[0xa4] 0,0, "PFMAX %m,%M",
-[0xa6] 0,0, "PFRCPIT1 %m,%M",
-[0xa7] 0,0, "PFRSQIT1 %m,%M",
-[0xaa] 0,0, "PFSUBR %m,%M",
-[0xae] 0,0, "PFACC %m,%M",
-[0xb0] 0,0, "PFCMPEQ %m,%M",
-[0xb4] 0,0, "PFMUL %m,%M",
-[0xb6] 0,0, "PFRCPI2T %m,%M",
-[0xb7] 0,0, "PMULHRW %m,%M",
-[0xbb] 0,0, "PSWAPL %m,%M",
+[0x0c] = { 0,0, "PI2FW %m,%M" },
+[0x0d] = { 0,0, "PI2L %m,%M" },
+[0x1c] = { 0,0, "PF2IW %m,%M" },
+[0x1d] = { 0,0, "PF2IL %m,%M" },
+[0x8a] = { 0,0, "PFNACC %m,%M" },
+[0x8e] = { 0,0, "PFPNACC %m,%M" },
+[0x90] = { 0,0, "PFCMPGE %m,%M" },
+[0x94] = { 0,0, "PFMIN %m,%M" },
+[0x96] = { 0,0, "PFRCP %m,%M" },
+[0x97] = { 0,0, "PFRSQRT %m,%M" },
+[0x9a] = { 0,0, "PFSUB %m,%M" },
+[0x9e] = { 0,0, "PFADD %m,%M" },
+[0xa0] = { 0,0, "PFCMPGT %m,%M" },
+[0xa4] = { 0,0, "PFMAX %m,%M" },
+[0xa6] = { 0,0, "PFRCPIT1 %m,%M" },
+[0xa7] = { 0,0, "PFRSQIT1 %m,%M" },
+[0xaa] = { 0,0, "PFSUBR %m,%M" },
+[0xae] = { 0,0, "PFACC %m,%M" },
+[0xb0] = { 0,0, "PFCMPEQ %m,%M" },
+[0xb4] = { 0,0, "PFMUL %m,%M" },
+[0xb6] = { 0,0, "PFRCPI2T %m,%M" },
+[0xb7] = { 0,0, "PMULHRW %m,%M" },
+[0xbb] = { 0,0, "PSWAPL %m,%M" },
};
static Optable optab0FC7[8]=
{
-[0x01] 0,0, "CMPXCHG8B %e",
+[0x01] = { 0,0, "CMPXCHG8B %e" },
};
static Optable optab660F71[8]=
{
-[0x02] Ib,0, "PSRLW %i,%X",
-[0x04] Ib,0, "PSRAW %i,%X",
-[0x06] Ib,0, "PSLLW %i,%X",
+[0x02] = { Ib,0, "PSRLW %i,%X" },
+[0x04] = { Ib,0, "PSRAW %i,%X" },
+[0x06] = { Ib,0, "PSLLW %i,%X" },
};
static Optable optab660F72[8]=
{
-[0x02] Ib,0, "PSRLL %i,%X",
-[0x04] Ib,0, "PSRAL %i,%X",
-[0x06] Ib,0, "PSLLL %i,%X",
+[0x02] = { Ib,0, "PSRLL %i,%X" },
+[0x04] = { Ib,0, "PSRAL %i,%X" },
+[0x06] = { Ib,0, "PSLLL %i,%X" },
};
static Optable optab660F73[8]=
{
-[0x02] Ib,0, "PSRLQ %i,%X",
-[0x03] Ib,0, "PSRLO %i,%X",
-[0x06] Ib,0, "PSLLQ %i,%X",
-[0x07] Ib,0, "PSLLO %i,%X",
+[0x02] = { Ib,0, "PSRLQ %i,%X" },
+[0x03] = { Ib,0, "PSRLO %i,%X" },
+[0x06] = { Ib,0, "PSLLQ %i,%X" },
+[0x07] = { Ib,0, "PSLLO %i,%X" },
};
static Optable optab660F[256]=
{
-[0x2B] RM,0, "MOVNTPD %x,%e",
-[0x2E] RM,0, "UCOMISD %x,%X",
-[0x2F] RM,0, "COMISD %x,%X",
-[0x5A] RM,0, "CVTPD2PS %x,%X",
-[0x5B] RM,0, "CVTPS2PL %x,%X",
-[0x6A] RM,0, "PUNPCKHLQ %x,%X",
-[0x6B] RM,0, "PACKSSLW %x,%X",
-[0x6C] RM,0, "PUNPCKLQDQ %x,%X",
-[0x6D] RM,0, "PUNPCKHQDQ %x,%X",
-[0x6E] RM,0, "MOV%S %e,%X",
-[0x6F] RM,0, "MOVO %x,%X", /* MOVDQA */
-[0x70] RM,Ib, "PSHUFL %i,%x,%X",
-[0x71] RMOP,0, optab660F71,
-[0x72] RMOP,0, optab660F72,
-[0x73] RMOP,0, optab660F73,
-[0x7E] RM,0, "MOV%S %X,%e",
-[0x7F] RM,0, "MOVO %X,%x",
-[0xC4] RM,Ib, "PINSRW %i,%e,%X",
-[0xC5] RMR,Ib, "PEXTRW %i,%X,%e",
-[0xD4] RM,0, "PADDQ %x,%X",
-[0xD5] RM,0, "PMULLW %x,%X",
-[0xD6] RM,0, "MOVQ %X,%x",
-[0xE6] RM,0, "CVTTPD2PL %x,%X",
-[0xE7] RM,0, "MOVNTO %X,%e",
-[0xF7] RM,0, "MASKMOVOU %x,%X",
+[0x2B] = { RM,0, "MOVNTPD %x,%e" },
+[0x2E] = { RM,0, "UCOMISD %x,%X" },
+[0x2F] = { RM,0, "COMISD %x,%X" },
+[0x5A] = { RM,0, "CVTPD2PS %x,%X" },
+[0x5B] = { RM,0, "CVTPS2PL %x,%X" },
+[0x6A] = { RM,0, "PUNPCKHLQ %x,%X" },
+[0x6B] = { RM,0, "PACKSSLW %x,%X" },
+[0x6C] = { RM,0, "PUNPCKLQDQ %x,%X" },
+[0x6D] = { RM,0, "PUNPCKHQDQ %x,%X" },
+[0x6E] = { RM,0, "MOV%S %e,%X" },
+[0x6F] = { RM,0, "MOVO %x,%X" }, /* MOVDQA */
+[0x70] = { RM,Ib, "PSHUFL %i,%x,%X" },
+[0x71] = { RMOP,0, optab660F71 },
+[0x72] = { RMOP,0, optab660F72 },
+[0x73] = { RMOP,0, optab660F73 },
+[0x7E] = { RM,0, "MOV%S %X,%e" },
+[0x7F] = { RM,0, "MOVO %X,%x" },
+[0xC4] = { RM,Ib, "PINSRW %i,%e,%X" },
+[0xC5] = { RMR,Ib, "PEXTRW %i,%X,%e" },
+[0xD4] = { RM,0, "PADDQ %x,%X" },
+[0xD5] = { RM,0, "PMULLW %x,%X" },
+[0xD6] = { RM,0, "MOVQ %X,%x" },
+[0xE6] = { RM,0, "CVTTPD2PL %x,%X" },
+[0xE7] = { RM,0, "MOVNTO %X,%e" },
+[0xF7] = { RM,0, "MASKMOVOU %x,%X" },
};
static Optable optabF20F[256]=
{
-[0x10] RM,0, "MOVSD %x,%X",
-[0x11] RM,0, "MOVSD %X,%x",
-[0x2A] RM,0, "CVTS%S2SD %e,%X",
-[0x2C] RM,0, "CVTTSD2S%S %x,%r",
-[0x2D] RM,0, "CVTSD2S%S %x,%r",
-[0x5A] RM,0, "CVTSD2SS %x,%X",
-[0x6F] RM,0, "MOVOU %x,%X",
-[0x70] RM,Ib, "PSHUFLW %i,%x,%X",
-[0x7F] RM,0, "MOVOU %X,%x",
-[0xD6] RM,0, "MOVQOZX %M,%X",
-[0xE6] RM,0, "CVTPD2PL %x,%X",
+[0x10] = { RM,0, "MOVSD %x,%X" },
+[0x11] = { RM,0, "MOVSD %X,%x" },
+[0x2A] = { RM,0, "CVTS%S2SD %e,%X" },
+[0x2C] = { RM,0, "CVTTSD2S%S %x,%r" },
+[0x2D] = { RM,0, "CVTSD2S%S %x,%r" },
+[0x5A] = { RM,0, "CVTSD2SS %x,%X" },
+[0x6F] = { RM,0, "MOVOU %x,%X" },
+[0x70] = { RM,Ib, "PSHUFLW %i,%x,%X" },
+[0x7F] = { RM,0, "MOVOU %X,%x" },
+[0xD6] = { RM,0, "MOVQOZX %M,%X" },
+[0xE6] = { RM,0, "CVTPD2PL %x,%X" },
};
static Optable optabF30F[256]=
{
-[0x10] RM,0, "MOVSS %x,%X",
-[0x11] RM,0, "MOVSS %X,%x",
-[0x2A] RM,0, "CVTS%S2SS %e,%X",
-[0x2C] RM,0, "CVTTSS2S%S %x,%r",
-[0x2D] RM,0, "CVTSS2S%S %x,%r",
-[0x5A] RM,0, "CVTSS2SD %x,%X",
-[0x5B] RM,0, "CVTTPS2PL %x,%X",
-[0x6F] RM,0, "MOVOU %x,%X",
-[0x70] RM,Ib, "PSHUFHW %i,%x,%X",
-[0x7E] RM,0, "MOVQOZX %x,%X",
-[0x7F] RM,0, "MOVOU %X,%x",
-[0xD6] RM,0, "MOVQOZX %m*,%X",
-[0xE6] RM,0, "CVTPL2PD %x,%X",
+[0x10] = { RM,0, "MOVSS %x,%X" },
+[0x11] = { RM,0, "MOVSS %X,%x" },
+[0x2A] = { RM,0, "CVTS%S2SS %e,%X" },
+[0x2C] = { RM,0, "CVTTSS2S%S %x,%r" },
+[0x2D] = { RM,0, "CVTSS2S%S %x,%r" },
+[0x5A] = { RM,0, "CVTSS2SD %x,%X" },
+[0x5B] = { RM,0, "CVTTPS2PL %x,%X" },
+[0x6F] = { RM,0, "MOVOU %x,%X" },
+[0x70] = { RM,Ib, "PSHUFHW %i,%x,%X" },
+[0x7E] = { RM,0, "MOVQOZX %x,%X" },
+[0x7F] = { RM,0, "MOVOU %X,%x" },
+[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
+[0xE6] = { RM,0, "CVTPL2PD %x,%X" },
};
static Optable optab0F[256]=
{
-[0x00] RMOP,0, optab0F00,
-[0x01] RMOP,0, optab0F01,
-[0x02] RM,0, "LAR %e,%r",
-[0x03] RM,0, "LSL %e,%r",
-[0x05] 0,0, "SYSCALL",
-[0x06] 0,0, "CLTS",
-[0x07] 0,0, "SYSRET",
-[0x08] 0,0, "INVD",
-[0x09] 0,0, "WBINVD",
-[0x0B] 0,0, "UD2",
-[0x0F] RM,AUX, optab0F0F, /* 3DNow! */
-[0x10] RM,0, "MOVU%s %x,%X",
-[0x11] RM,0, "MOVU%s %X,%x",
-[0x12] RM,0, "MOV[H]L%s %x,%X", /* TO DO: H if source is XMM */
-[0x13] RM,0, "MOVL%s %X,%e",
-[0x14] RM,0, "UNPCKL%s %x,%X",
-[0x15] RM,0, "UNPCKH%s %x,%X",
-[0x16] RM,0, "MOV[L]H%s %x,%X", /* TO DO: L if source is XMM */
-[0x17] RM,0, "MOVH%s %X,%x",
-[0x20] RMR,0, "MOVL %C,%e",
-[0x21] RMR,0, "MOVL %D,%e",
-[0x22] RMR,0, "MOVL %e,%C",
-[0x23] RMR,0, "MOVL %e,%D",
-[0x24] RMR,0, "MOVL %T,%e",
-[0x26] RMR,0, "MOVL %e,%T",
-[0x28] RM,0, "MOVA%s %x,%X",
-[0x29] RM,0, "MOVA%s %X,%x",
-[0x2A] RM,0, "CVTPL2%s %m*,%X",
-[0x2B] RM,0, "MOVNT%s %X,%e",
-[0x2C] RM,0, "CVTT%s2PL %x,%M",
-[0x2D] RM,0, "CVT%s2PL %x,%M",
-[0x2E] RM,0, "UCOMISS %x,%X",
-[0x2F] RM,0, "COMISS %x,%X",
-[0x30] 0,0, "WRMSR",
-[0x31] 0,0, "RDTSC",
-[0x32] 0,0, "RDMSR",
-[0x33] 0,0, "RDPMC",
-[0x42] RM,0, "CMOVC %e,%r", /* CF */
-[0x43] RM,0, "CMOVNC %e,%r", /* ¬ CF */
-[0x44] RM,0, "CMOVZ %e,%r", /* ZF */
-[0x45] RM,0, "CMOVNZ %e,%r", /* ¬ ZF */
-[0x46] RM,0, "CMOVBE %e,%r", /* CF ∨ ZF */
-[0x47] RM,0, "CMOVA %e,%r", /* ¬CF ∧ ¬ZF */
-[0x48] RM,0, "CMOVS %e,%r", /* SF */
-[0x49] RM,0, "CMOVNS %e,%r", /* ¬ SF */
-[0x4A] RM,0, "CMOVP %e,%r", /* PF */
-[0x4B] RM,0, "CMOVNP %e,%r", /* ¬ PF */
-[0x4C] RM,0, "CMOVLT %e,%r", /* LT ≡ OF ≠ SF */
-[0x4D] RM,0, "CMOVGE %e,%r", /* GE ≡ ZF ∨ SF */
-[0x4E] RM,0, "CMOVLE %e,%r", /* LE ≡ ZF ∨ LT */
-[0x4F] RM,0, "CMOVGT %e,%r", /* GT ≡ ¬ZF ∧ GE */
-[0x50] RM,0, "MOVMSK%s %X,%r", /* TO DO: check */
-[0x51] RM,0, "SQRT%s %x,%X",
-[0x52] RM,0, "RSQRT%s %x,%X",
-[0x53] RM,0, "RCP%s %x,%X",
-[0x54] RM,0, "AND%s %x,%X",
-[0x55] RM,0, "ANDN%s %x,%X",
-[0x56] RM,0, "OR%s %x,%X", /* TO DO: S/D */
-[0x57] RM,0, "XOR%s %x,%X", /* S/D */
-[0x58] RM,0, "ADD%s %x,%X", /* S/P S/D */
-[0x59] RM,0, "MUL%s %x,%X",
-[0x5A] RM,0, "CVTPS2PD %x,%X",
-[0x5B] RM,0, "CVTPL2PS %x,%X",
-[0x5C] RM,0, "SUB%s %x,%X",
-[0x5D] RM,0, "MIN%s %x,%X",
-[0x5E] RM,0, "DIV%s %x,%X", /* TO DO: S/P S/D */
-[0x5F] RM,0, "MAX%s %x,%X",
-[0x60] RM,0, "PUNPCKLBW %m,%M",
-[0x61] RM,0, "PUNPCKLWL %m,%M",
-[0x62] RM,0, "PUNPCKLLQ %m,%M",
-[0x63] RM,0, "PACKSSWB %m,%M",
-[0x64] RM,0, "PCMPGTB %m,%M",
-[0x65] RM,0, "PCMPGTW %m,%M",
-[0x66] RM,0, "PCMPGTL %m,%M",
-[0x67] RM,0, "PACKUSWB %m,%M",
-[0x68] RM,0, "PUNPCKHBW %m,%M",
-[0x69] RM,0, "PUNPCKHWL %m,%M",
-[0x6A] RM,0, "PUNPCKHLQ %m,%M",
-[0x6B] RM,0, "PACKSSLW %m,%M",
-[0x6E] RM,0, "MOV%S %e,%M",
-[0x6F] RM,0, "MOVQ %m,%M",
-[0x70] RM,Ib, "PSHUFW %i,%m,%M",
-[0x74] RM,0, "PCMPEQB %m,%M",
-[0x75] RM,0, "PCMPEQW %m,%M",
-[0x76] RM,0, "PCMPEQL %m,%M",
-[0x7E] RM,0, "MOV%S %M,%e",
-[0x7F] RM,0, "MOVQ %M,%m",
-[0xAE] RMOP,0, optab0FAE,
-[0xAA] 0,0, "RSM",
-[0xB0] RM,0, "CMPXCHGB %r,%e",
-[0xB1] RM,0, "CMPXCHG%S %r,%e",
-[0xC0] RMB,0, "XADDB %r,%e",
-[0xC1] RM,0, "XADD%S %r,%e",
-[0xC2] RM,Ib, "CMP%s %x,%X,%#i",
-[0xC3] RM,0, "MOVNTI%S %r,%e",
-[0xC6] RM,Ib, "SHUF%s %i,%x,%X",
-[0xC8] 0,0, "BSWAP AX",
-[0xC9] 0,0, "BSWAP CX",
-[0xCA] 0,0, "BSWAP DX",
-[0xCB] 0,0, "BSWAP BX",
-[0xCC] 0,0, "BSWAP SP",
-[0xCD] 0,0, "BSWAP BP",
-[0xCE] 0,0, "BSWAP SI",
-[0xCF] 0,0, "BSWAP DI",
-[0xD1] RM,0, "PSRLW %m,%M",
-[0xD2] RM,0, "PSRLL %m,%M",
-[0xD3] RM,0, "PSRLQ %m,%M",
-[0xD5] RM,0, "PMULLW %m,%M",
-[0xD6] RM,0, "MOVQOZX %m*,%X",
-[0xD7] RM,0, "PMOVMSKB %m,%r",
-[0xD8] RM,0, "PSUBUSB %m,%M",
-[0xD9] RM,0, "PSUBUSW %m,%M",
-[0xDA] RM,0, "PMINUB %m,%M",
-[0xDB] RM,0, "PAND %m,%M",
-[0xDC] RM,0, "PADDUSB %m,%M",
-[0xDD] RM,0, "PADDUSW %m,%M",
-[0xDE] RM,0, "PMAXUB %m,%M",
-[0xDF] RM,0, "PANDN %m,%M",
-[0xE0] RM,0, "PAVGB %m,%M",
-[0xE1] RM,0, "PSRAW %m,%M",
-[0xE2] RM,0, "PSRAL %m,%M",
-[0xE3] RM,0, "PAVGW %m,%M",
-[0xE4] RM,0, "PMULHUW %m,%M",
-[0xE5] RM,0, "PMULHW %m,%M",
-[0xE7] RM,0, "MOVNTQ %M,%e",
-[0xE8] RM,0, "PSUBSB %m,%M",
-[0xE9] RM,0, "PSUBSW %m,%M",
-[0xEA] RM,0, "PMINSW %m,%M",
-[0xEB] RM,0, "POR %m,%M",
-[0xEC] RM,0, "PADDSB %m,%M",
-[0xED] RM,0, "PADDSW %m,%M",
-[0xEE] RM,0, "PMAXSW %m,%M",
-[0xEF] RM,0, "PXOR %m,%M",
-[0xF1] RM,0, "PSLLW %m,%M",
-[0xF2] RM,0, "PSLLL %m,%M",
-[0xF3] RM,0, "PSLLQ %m,%M",
-[0xF4] RM,0, "PMULULQ %m,%M",
-[0xF5] RM,0, "PMADDWL %m,%M",
-[0xF6] RM,0, "PSADBW %m,%M",
-[0xF7] RMR,0, "MASKMOVQ %m,%M",
-[0xF8] RM,0, "PSUBB %m,%M",
-[0xF9] RM,0, "PSUBW %m,%M",
-[0xFA] RM,0, "PSUBL %m,%M",
-[0xFC] RM,0, "PADDB %m,%M",
-[0xFD] RM,0, "PADDW %m,%M",
-[0xFE] RM,0, "PADDL %m,%M",
-
-[0x80] Iwds,0, "JOS %p",
-[0x81] Iwds,0, "JOC %p",
-[0x82] Iwds,0, "JCS %p",
-[0x83] Iwds,0, "JCC %p",
-[0x84] Iwds,0, "JEQ %p",
-[0x85] Iwds,0, "JNE %p",
-[0x86] Iwds,0, "JLS %p",
-[0x87] Iwds,0, "JHI %p",
-[0x88] Iwds,0, "JMI %p",
-[0x89] Iwds,0, "JPL %p",
-[0x8a] Iwds,0, "JPS %p",
-[0x8b] Iwds,0, "JPC %p",
-[0x8c] Iwds,0, "JLT %p",
-[0x8d] Iwds,0, "JGE %p",
-[0x8e] Iwds,0, "JLE %p",
-[0x8f] Iwds,0, "JGT %p",
-[0x90] RMB,0, "SETOS %e",
-[0x91] RMB,0, "SETOC %e",
-[0x92] RMB,0, "SETCS %e",
-[0x93] RMB,0, "SETCC %e",
-[0x94] RMB,0, "SETEQ %e",
-[0x95] RMB,0, "SETNE %e",
-[0x96] RMB,0, "SETLS %e",
-[0x97] RMB,0, "SETHI %e",
-[0x98] RMB,0, "SETMI %e",
-[0x99] RMB,0, "SETPL %e",
-[0x9a] RMB,0, "SETPS %e",
-[0x9b] RMB,0, "SETPC %e",
-[0x9c] RMB,0, "SETLT %e",
-[0x9d] RMB,0, "SETGE %e",
-[0x9e] RMB,0, "SETLE %e",
-[0x9f] RMB,0, "SETGT %e",
-[0xa0] 0,0, "PUSHL FS",
-[0xa1] 0,0, "POPL FS",
-[0xa2] 0,0, "CPUID",
-[0xa3] RM,0, "BT%S %r,%e",
-[0xa4] RM,Ib, "SHLD%S %r,%i,%e",
-[0xa5] RM,0, "SHLD%S %r,CL,%e",
-[0xa8] 0,0, "PUSHL GS",
-[0xa9] 0,0, "POPL GS",
-[0xab] RM,0, "BTS%S %r,%e",
-[0xac] RM,Ib, "SHRD%S %r,%i,%e",
-[0xad] RM,0, "SHRD%S %r,CL,%e",
-[0xaf] RM,0, "IMUL%S %e,%r",
-[0xb2] RMM,0, "LSS %e,%r",
-[0xb3] RM,0, "BTR%S %r,%e",
-[0xb4] RMM,0, "LFS %e,%r",
-[0xb5] RMM,0, "LGS %e,%r",
-[0xb6] RMB,0, "MOVBZX %e,%R",
-[0xb7] RM,0, "MOVWZX %e,%R",
-[0xba] RMOP,0, optab0FBA,
-[0xbb] RM,0, "BTC%S %e,%r",
-[0xbc] RM,0, "BSF%S %e,%r",
-[0xbd] RM,0, "BSR%S %e,%r",
-[0xbe] RMB,0, "MOVBSX %e,%R",
-[0xbf] RM,0, "MOVWSX %e,%R",
-[0xc7] RMOP,0, optab0FC7,
+[0x00] = { RMOP,0, optab0F00 },
+[0x01] = { RMOP,0, optab0F01 },
+[0x02] = { RM,0, "LAR %e,%r" },
+[0x03] = { RM,0, "LSL %e,%r" },
+[0x05] = { 0,0, "SYSCALL" },
+[0x06] = { 0,0, "CLTS" },
+[0x07] = { 0,0, "SYSRET" },
+[0x08] = { 0,0, "INVD" },
+[0x09] = { 0,0, "WBINVD" },
+[0x0B] = { 0,0, "UD2" },
+[0x0F] = { RM,AUX, optab0F0F }, /* 3DNow! */
+[0x10] = { RM,0, "MOVU%s %x,%X" },
+[0x11] = { RM,0, "MOVU%s %X,%x" },
+[0x12] = { RM,0, "MOV[H]L%s %x,%X" }, /* TO DO: H if source is XMM */
+[0x13] = { RM,0, "MOVL%s %X,%e" },
+[0x14] = { RM,0, "UNPCKL%s %x,%X" },
+[0x15] = { RM,0, "UNPCKH%s %x,%X" },
+[0x16] = { RM,0, "MOV[L]H%s %x,%X" }, /* TO DO: L if source is XMM */
+[0x17] = { RM,0, "MOVH%s %X,%x" },
+[0x20] = { RMR,0, "MOVL %C,%e" },
+[0x21] = { RMR,0, "MOVL %D,%e" },
+[0x22] = { RMR,0, "MOVL %e,%C" },
+[0x23] = { RMR,0, "MOVL %e,%D" },
+[0x24] = { RMR,0, "MOVL %T,%e" },
+[0x26] = { RMR,0, "MOVL %e,%T" },
+[0x28] = { RM,0, "MOVA%s %x,%X" },
+[0x29] = { RM,0, "MOVA%s %X,%x" },
+[0x2A] = { RM,0, "CVTPL2%s %m*,%X" },
+[0x2B] = { RM,0, "MOVNT%s %X,%e" },
+[0x2C] = { RM,0, "CVTT%s2PL %x,%M" },
+[0x2D] = { RM,0, "CVT%s2PL %x,%M" },
+[0x2E] = { RM,0, "UCOMISS %x,%X" },
+[0x2F] = { RM,0, "COMISS %x,%X" },
+[0x30] = { 0,0, "WRMSR" },
+[0x31] = { 0,0, "RDTSC" },
+[0x32] = { 0,0, "RDMSR" },
+[0x33] = { 0,0, "RDPMC" },
+[0x42] = { RM,0, "CMOVC %e,%r" }, /* CF */
+[0x43] = { RM,0, "CMOVNC %e,%r" }, /* ¬ CF */
+[0x44] = { RM,0, "CMOVZ %e,%r" }, /* ZF */
+[0x45] = { RM,0, "CMOVNZ %e,%r" }, /* ¬ ZF */
+[0x46] = { RM,0, "CMOVBE %e,%r" }, /* CF ∨ ZF */
+[0x47] = { RM,0, "CMOVA %e,%r" }, /* ¬CF ∧ ¬ZF */
+[0x48] = { RM,0, "CMOVS %e,%r" }, /* SF */
+[0x49] = { RM,0, "CMOVNS %e,%r" }, /* ¬ SF */
+[0x4A] = { RM,0, "CMOVP %e,%r" }, /* PF */
+[0x4B] = { RM,0, "CMOVNP %e,%r" }, /* ¬ PF */
+[0x4C] = { RM,0, "CMOVLT %e,%r" }, /* LT ≡ OF ≠ SF */
+[0x4D] = { RM,0, "CMOVGE %e,%r" }, /* GE ≡ ZF ∨ SF */
+[0x4E] = { RM,0, "CMOVLE %e,%r" }, /* LE ≡ ZF ∨ LT */
+[0x4F] = { RM,0, "CMOVGT %e,%r" }, /* GT ≡ ¬ZF ∧ GE */
+[0x50] = { RM,0, "MOVMSK%s %X,%r" }, /* TO DO: check */
+[0x51] = { RM,0, "SQRT%s %x,%X" },
+[0x52] = { RM,0, "RSQRT%s %x,%X" },
+[0x53] = { RM,0, "RCP%s %x,%X" },
+[0x54] = { RM,0, "AND%s %x,%X" },
+[0x55] = { RM,0, "ANDN%s %x,%X" },
+[0x56] = { RM,0, "OR%s %x,%X" }, /* TO DO: S/D */
+[0x57] = { RM,0, "XOR%s %x,%X" }, /* S/D */
+[0x58] = { RM,0, "ADD%s %x,%X" }, /* S/P S/D */
+[0x59] = { RM,0, "MUL%s %x,%X" },
+[0x5A] = { RM,0, "CVTPS2PD %x,%X" },
+[0x5B] = { RM,0, "CVTPL2PS %x,%X" },
+[0x5C] = { RM,0, "SUB%s %x,%X" },
+[0x5D] = { RM,0, "MIN%s %x,%X" },
+[0x5E] = { RM,0, "DIV%s %x,%X" }, /* TO DO: S/P S/D */
+[0x5F] = { RM,0, "MAX%s %x,%X" },
+[0x60] = { RM,0, "PUNPCKLBW %m,%M" },
+[0x61] = { RM,0, "PUNPCKLWL %m,%M" },
+[0x62] = { RM,0, "PUNPCKLLQ %m,%M" },
+[0x63] = { RM,0, "PACKSSWB %m,%M" },
+[0x64] = { RM,0, "PCMPGTB %m,%M" },
+[0x65] = { RM,0, "PCMPGTW %m,%M" },
+[0x66] = { RM,0, "PCMPGTL %m,%M" },
+[0x67] = { RM,0, "PACKUSWB %m,%M" },
+[0x68] = { RM,0, "PUNPCKHBW %m,%M" },
+[0x69] = { RM,0, "PUNPCKHWL %m,%M" },
+[0x6A] = { RM,0, "PUNPCKHLQ %m,%M" },
+[0x6B] = { RM,0, "PACKSSLW %m,%M" },
+[0x6E] = { RM,0, "MOV%S %e,%M" },
+[0x6F] = { RM,0, "MOVQ %m,%M" },
+[0x70] = { RM,Ib, "PSHUFW %i,%m,%M" },
+[0x74] = { RM,0, "PCMPEQB %m,%M" },
+[0x75] = { RM,0, "PCMPEQW %m,%M" },
+[0x76] = { RM,0, "PCMPEQL %m,%M" },
+[0x7E] = { RM,0, "MOV%S %M,%e" },
+[0x7F] = { RM,0, "MOVQ %M,%m" },
+[0xAE] = { RMOP,0, optab0FAE },
+[0xAA] = { 0,0, "RSM" },
+[0xB0] = { RM,0, "CMPXCHGB %r,%e" },
+[0xB1] = { RM,0, "CMPXCHG%S %r,%e" },
+[0xC0] = { RMB,0, "XADDB %r,%e" },
+[0xC1] = { RM,0, "XADD%S %r,%e" },
+[0xC2] = { RM,Ib, "CMP%s %x,%X,%#i" },
+[0xC3] = { RM,0, "MOVNTI%S %r,%e" },
+[0xC6] = { RM,Ib, "SHUF%s %i,%x,%X" },
+[0xC8] = { 0,0, "BSWAP AX" },
+[0xC9] = { 0,0, "BSWAP CX" },
+[0xCA] = { 0,0, "BSWAP DX" },
+[0xCB] = { 0,0, "BSWAP BX" },
+[0xCC] = { 0,0, "BSWAP SP" },
+[0xCD] = { 0,0, "BSWAP BP" },
+[0xCE] = { 0,0, "BSWAP SI" },
+[0xCF] = { 0,0, "BSWAP DI" },
+[0xD1] = { RM,0, "PSRLW %m,%M" },
+[0xD2] = { RM,0, "PSRLL %m,%M" },
+[0xD3] = { RM,0, "PSRLQ %m,%M" },
+[0xD5] = { RM,0, "PMULLW %m,%M" },
+[0xD6] = { RM,0, "MOVQOZX %m*,%X" },
+[0xD7] = { RM,0, "PMOVMSKB %m,%r" },
+[0xD8] = { RM,0, "PSUBUSB %m,%M" },
+[0xD9] = { RM,0, "PSUBUSW %m,%M" },
+[0xDA] = { RM,0, "PMINUB %m,%M" },
+[0xDB] = { RM,0, "PAND %m,%M" },
+[0xDC] = { RM,0, "PADDUSB %m,%M" },
+[0xDD] = { RM,0, "PADDUSW %m,%M" },
+[0xDE] = { RM,0, "PMAXUB %m,%M" },
+[0xDF] = { RM,0, "PANDN %m,%M" },
+[0xE0] = { RM,0, "PAVGB %m,%M" },
+[0xE1] = { RM,0, "PSRAW %m,%M" },
+[0xE2] = { RM,0, "PSRAL %m,%M" },
+[0xE3] = { RM,0, "PAVGW %m,%M" },
+[0xE4] = { RM,0, "PMULHUW %m,%M" },
+[0xE5] = { RM,0, "PMULHW %m,%M" },
+[0xE7] = { RM,0, "MOVNTQ %M,%e" },
+[0xE8] = { RM,0, "PSUBSB %m,%M" },
+[0xE9] = { RM,0, "PSUBSW %m,%M" },
+[0xEA] = { RM,0, "PMINSW %m,%M" },
+[0xEB] = { RM,0, "POR %m,%M" },
+[0xEC] = { RM,0, "PADDSB %m,%M" },
+[0xED] = { RM,0, "PADDSW %m,%M" },
+[0xEE] = { RM,0, "PMAXSW %m,%M" },
+[0xEF] = { RM,0, "PXOR %m,%M" },
+[0xF1] = { RM,0, "PSLLW %m,%M" },
+[0xF2] = { RM,0, "PSLLL %m,%M" },
+[0xF3] = { RM,0, "PSLLQ %m,%M" },
+[0xF4] = { RM,0, "PMULULQ %m,%M" },
+[0xF5] = { RM,0, "PMADDWL %m,%M" },
+[0xF6] = { RM,0, "PSADBW %m,%M" },
+[0xF7] = { RMR,0, "MASKMOVQ %m,%M" },
+[0xF8] = { RM,0, "PSUBB %m,%M" },
+[0xF9] = { RM,0, "PSUBW %m,%M" },
+[0xFA] = { RM,0, "PSUBL %m,%M" },
+[0xFC] = { RM,0, "PADDB %m,%M" },
+[0xFD] = { RM,0, "PADDW %m,%M" },
+[0xFE] = { RM,0, "PADDL %m,%M" },
+
+[0x80] = { Iwds,0, "JOS %p" },
+[0x81] = { Iwds,0, "JOC %p" },
+[0x82] = { Iwds,0, "JCS %p" },
+[0x83] = { Iwds,0, "JCC %p" },
+[0x84] = { Iwds,0, "JEQ %p" },
+[0x85] = { Iwds,0, "JNE %p" },
+[0x86] = { Iwds,0, "JLS %p" },
+[0x87] = { Iwds,0, "JHI %p" },
+[0x88] = { Iwds,0, "JMI %p" },
+[0x89] = { Iwds,0, "JPL %p" },
+[0x8a] = { Iwds,0, "JPS %p" },
+[0x8b] = { Iwds,0, "JPC %p" },
+[0x8c] = { Iwds,0, "JLT %p" },
+[0x8d] = { Iwds,0, "JGE %p" },
+[0x8e] = { Iwds,0, "JLE %p" },
+[0x8f] = { Iwds,0, "JGT %p" },
+[0x90] = { RMB,0, "SETOS %e" },
+[0x91] = { RMB,0, "SETOC %e" },
+[0x92] = { RMB,0, "SETCS %e" },
+[0x93] = { RMB,0, "SETCC %e" },
+[0x94] = { RMB,0, "SETEQ %e" },
+[0x95] = { RMB,0, "SETNE %e" },
+[0x96] = { RMB,0, "SETLS %e" },
+[0x97] = { RMB,0, "SETHI %e" },
+[0x98] = { RMB,0, "SETMI %e" },
+[0x99] = { RMB,0, "SETPL %e" },
+[0x9a] = { RMB,0, "SETPS %e" },
+[0x9b] = { RMB,0, "SETPC %e" },
+[0x9c] = { RMB,0, "SETLT %e" },
+[0x9d] = { RMB,0, "SETGE %e" },
+[0x9e] = { RMB,0, "SETLE %e" },
+[0x9f] = { RMB,0, "SETGT %e" },
+[0xa0] = { 0,0, "PUSHL FS" },
+[0xa1] = { 0,0, "POPL FS" },
+[0xa2] = { 0,0, "CPUID" },
+[0xa3] = { RM,0, "BT%S %r,%e" },
+[0xa4] = { RM,Ib, "SHLD%S %r,%i,%e" },
+[0xa5] = { RM,0, "SHLD%S %r,CL,%e" },
+[0xa8] = { 0,0, "PUSHL GS" },
+[0xa9] = { 0,0, "POPL GS" },
+[0xab] = { RM,0, "BTS%S %r,%e" },
+[0xac] = { RM,Ib, "SHRD%S %r,%i,%e" },
+[0xad] = { RM,0, "SHRD%S %r,CL,%e" },
+[0xaf] = { RM,0, "IMUL%S %e,%r" },
+[0xb2] = { RMM,0, "LSS %e,%r" },
+[0xb3] = { RM,0, "BTR%S %r,%e" },
+[0xb4] = { RMM,0, "LFS %e,%r" },
+[0xb5] = { RMM,0, "LGS %e,%r" },
+[0xb6] = { RMB,0, "MOVBZX %e,%R" },
+[0xb7] = { RM,0, "MOVWZX %e,%R" },
+[0xba] = { RMOP,0, optab0FBA },
+[0xbb] = { RM,0, "BTC%S %e,%r" },
+[0xbc] = { RM,0, "BSF%S %e,%r" },
+[0xbd] = { RM,0, "BSR%S %e,%r" },
+[0xbe] = { RMB,0, "MOVBSX %e,%R" },
+[0xbf] = { RM,0, "MOVWSX %e,%R" },
+[0xc7] = { RMOP,0, optab0FC7 },
};
static Optable optab80[8]=
{
-[0x00] Ib,0, "ADDB %i,%e",
-[0x01] Ib,0, "ORB %i,%e",
-[0x02] Ib,0, "ADCB %i,%e",
-[0x03] Ib,0, "SBBB %i,%e",
-[0x04] Ib,0, "ANDB %i,%e",
-[0x05] Ib,0, "SUBB %i,%e",
-[0x06] Ib,0, "XORB %i,%e",
-[0x07] Ib,0, "CMPB %e,%i",
+[0x00] = { Ib,0, "ADDB %i,%e" },
+[0x01] = { Ib,0, "ORB %i,%e" },
+[0x02] = { Ib,0, "ADCB %i,%e" },
+[0x03] = { Ib,0, "SBBB %i,%e" },
+[0x04] = { Ib,0, "ANDB %i,%e" },
+[0x05] = { Ib,0, "SUBB %i,%e" },
+[0x06] = { Ib,0, "XORB %i,%e" },
+[0x07] = { Ib,0, "CMPB %e,%i" },
};
static Optable optab81[8]=
{
-[0x00] Iwd,0, "ADD%S %i,%e",
-[0x01] Iwd,0, "OR%S %i,%e",
-[0x02] Iwd,0, "ADC%S %i,%e",
-[0x03] Iwd,0, "SBB%S %i,%e",
-[0x04] Iwd,0, "AND%S %i,%e",
-[0x05] Iwd,0, "SUB%S %i,%e",
-[0x06] Iwd,0, "XOR%S %i,%e",
-[0x07] Iwd,0, "CMP%S %e,%i",
+[0x00] = { Iwd,0, "ADD%S %i,%e" },
+[0x01] = { Iwd,0, "OR%S %i,%e" },
+[0x02] = { Iwd,0, "ADC%S %i,%e" },
+[0x03] = { Iwd,0, "SBB%S %i,%e" },
+[0x04] = { Iwd,0, "AND%S %i,%e" },
+[0x05] = { Iwd,0, "SUB%S %i,%e" },
+[0x06] = { Iwd,0, "XOR%S %i,%e" },
+[0x07] = { Iwd,0, "CMP%S %e,%i" },
};
static Optable optab83[8]=
{
-[0x00] Ibs,0, "ADD%S %i,%e",
-[0x01] Ibs,0, "OR%S %i,%e",
-[0x02] Ibs,0, "ADC%S %i,%e",
-[0x03] Ibs,0, "SBB%S %i,%e",
-[0x04] Ibs,0, "AND%S %i,%e",
-[0x05] Ibs,0, "SUB%S %i,%e",
-[0x06] Ibs,0, "XOR%S %i,%e",
-[0x07] Ibs,0, "CMP%S %e,%i",
+[0x00] = { Ibs,0, "ADD%S %i,%e" },
+[0x01] = { Ibs,0, "OR%S %i,%e" },
+[0x02] = { Ibs,0, "ADC%S %i,%e" },
+[0x03] = { Ibs,0, "SBB%S %i,%e" },
+[0x04] = { Ibs,0, "AND%S %i,%e" },
+[0x05] = { Ibs,0, "SUB%S %i,%e" },
+[0x06] = { Ibs,0, "XOR%S %i,%e" },
+[0x07] = { Ibs,0, "CMP%S %e,%i" },
};
static Optable optabC0[8] =
{
-[0x00] Ib,0, "ROLB %i,%e",
-[0x01] Ib,0, "RORB %i,%e",
-[0x02] Ib,0, "RCLB %i,%e",
-[0x03] Ib,0, "RCRB %i,%e",
-[0x04] Ib,0, "SHLB %i,%e",
-[0x05] Ib,0, "SHRB %i,%e",
-[0x07] Ib,0, "SARB %i,%e",
+[0x00] = { Ib,0, "ROLB %i,%e" },
+[0x01] = { Ib,0, "RORB %i,%e" },
+[0x02] = { Ib,0, "RCLB %i,%e" },
+[0x03] = { Ib,0, "RCRB %i,%e" },
+[0x04] = { Ib,0, "SHLB %i,%e" },
+[0x05] = { Ib,0, "SHRB %i,%e" },
+[0x07] = { Ib,0, "SARB %i,%e" },
};
static Optable optabC1[8] =
{
-[0x00] Ib,0, "ROL%S %i,%e",
-[0x01] Ib,0, "ROR%S %i,%e",
-[0x02] Ib,0, "RCL%S %i,%e",
-[0x03] Ib,0, "RCR%S %i,%e",
-[0x04] Ib,0, "SHL%S %i,%e",
-[0x05] Ib,0, "SHR%S %i,%e",
-[0x07] Ib,0, "SAR%S %i,%e",
+[0x00] = { Ib,0, "ROL%S %i,%e" },
+[0x01] = { Ib,0, "ROR%S %i,%e" },
+[0x02] = { Ib,0, "RCL%S %i,%e" },
+[0x03] = { Ib,0, "RCR%S %i,%e" },
+[0x04] = { Ib,0, "SHL%S %i,%e" },
+[0x05] = { Ib,0, "SHR%S %i,%e" },
+[0x07] = { Ib,0, "SAR%S %i,%e" },
};
static Optable optabD0[8] =
{
-[0x00] 0,0, "ROLB %e",
-[0x01] 0,0, "RORB %e",
-[0x02] 0,0, "RCLB %e",
-[0x03] 0,0, "RCRB %e",
-[0x04] 0,0, "SHLB %e",
-[0x05] 0,0, "SHRB %e",
-[0x07] 0,0, "SARB %e",
+[0x00] = { 0,0, "ROLB %e" },
+[0x01] = { 0,0, "RORB %e" },
+[0x02] = { 0,0, "RCLB %e" },
+[0x03] = { 0,0, "RCRB %e" },
+[0x04] = { 0,0, "SHLB %e" },
+[0x05] = { 0,0, "SHRB %e" },
+[0x07] = { 0,0, "SARB %e" },
};
static Optable optabD1[8] =
{
-[0x00] 0,0, "ROL%S %e",
-[0x01] 0,0, "ROR%S %e",
-[0x02] 0,0, "RCL%S %e",
-[0x03] 0,0, "RCR%S %e",
-[0x04] 0,0, "SHL%S %e",
-[0x05] 0,0, "SHR%S %e",
-[0x07] 0,0, "SAR%S %e",
+[0x00] = { 0,0, "ROL%S %e" },
+[0x01] = { 0,0, "ROR%S %e" },
+[0x02] = { 0,0, "RCL%S %e" },
+[0x03] = { 0,0, "RCR%S %e" },
+[0x04] = { 0,0, "SHL%S %e" },
+[0x05] = { 0,0, "SHR%S %e" },
+[0x07] = { 0,0, "SAR%S %e" },
};
static Optable optabD2[8] =
{
-[0x00] 0,0, "ROLB CL,%e",
-[0x01] 0,0, "RORB CL,%e",
-[0x02] 0,0, "RCLB CL,%e",
-[0x03] 0,0, "RCRB CL,%e",
-[0x04] 0,0, "SHLB CL,%e",
-[0x05] 0,0, "SHRB CL,%e",
-[0x07] 0,0, "SARB CL,%e",
+[0x00] = { 0,0, "ROLB CL,%e" },
+[0x01] = { 0,0, "RORB CL,%e" },
+[0x02] = { 0,0, "RCLB CL,%e" },
+[0x03] = { 0,0, "RCRB CL,%e" },
+[0x04] = { 0,0, "SHLB CL,%e" },
+[0x05] = { 0,0, "SHRB CL,%e" },
+[0x07] = { 0,0, "SARB CL,%e" },
};
static Optable optabD3[8] =
{
-[0x00] 0,0, "ROL%S CL,%e",
-[0x01] 0,0, "ROR%S CL,%e",
-[0x02] 0,0, "RCL%S CL,%e",
-[0x03] 0,0, "RCR%S CL,%e",
-[0x04] 0,0, "SHL%S CL,%e",
-[0x05] 0,0, "SHR%S CL,%e",
-[0x07] 0,0, "SAR%S CL,%e",
+[0x00] = { 0,0, "ROL%S CL,%e" },
+[0x01] = { 0,0, "ROR%S CL,%e" },
+[0x02] = { 0,0, "RCL%S CL,%e" },
+[0x03] = { 0,0, "RCR%S CL,%e" },
+[0x04] = { 0,0, "SHL%S CL,%e" },
+[0x05] = { 0,0, "SHR%S CL,%e" },
+[0x07] = { 0,0, "SAR%S CL,%e" },
};
static Optable optabD8[8+8] =
{
-[0x00] 0,0, "FADDF %e,F0",
-[0x01] 0,0, "FMULF %e,F0",
-[0x02] 0,0, "FCOMF %e,F0",
-[0x03] 0,0, "FCOMFP %e,F0",
-[0x04] 0,0, "FSUBF %e,F0",
-[0x05] 0,0, "FSUBRF %e,F0",
-[0x06] 0,0, "FDIVF %e,F0",
-[0x07] 0,0, "FDIVRF %e,F0",
-[0x08] 0,0, "FADDD %f,F0",
-[0x09] 0,0, "FMULD %f,F0",
-[0x0a] 0,0, "FCOMD %f,F0",
-[0x0b] 0,0, "FCOMPD %f,F0",
-[0x0c] 0,0, "FSUBD %f,F0",
-[0x0d] 0,0, "FSUBRD %f,F0",
-[0x0e] 0,0, "FDIVD %f,F0",
-[0x0f] 0,0, "FDIVRD %f,F0",
+[0x00] = { 0,0, "FADDF %e,F0" },
+[0x01] = { 0,0, "FMULF %e,F0" },
+[0x02] = { 0,0, "FCOMF %e,F0" },
+[0x03] = { 0,0, "FCOMFP %e,F0" },
+[0x04] = { 0,0, "FSUBF %e,F0" },
+[0x05] = { 0,0, "FSUBRF %e,F0" },
+[0x06] = { 0,0, "FDIVF %e,F0" },
+[0x07] = { 0,0, "FDIVRF %e,F0" },
+[0x08] = { 0,0, "FADDD %f,F0" },
+[0x09] = { 0,0, "FMULD %f,F0" },
+[0x0a] = { 0,0, "FCOMD %f,F0" },
+[0x0b] = { 0,0, "FCOMPD %f,F0" },
+[0x0c] = { 0,0, "FSUBD %f,F0" },
+[0x0d] = { 0,0, "FSUBRD %f,F0" },
+[0x0e] = { 0,0, "FDIVD %f,F0" },
+[0x0f] = { 0,0, "FDIVRD %f,F0" },
};
/*
* optabD9 and optabDB use the following encoding:
@@ -940,455 +940,455 @@ static Optable optabD8[8+8] =
*/
static Optable optabD9[64+8] =
{
-[0x00] 0,0, "FMOVF %e,F0",
-[0x02] 0,0, "FMOVF F0,%e",
-[0x03] 0,0, "FMOVFP F0,%e",
-[0x04] 0,0, "FLDENV%S %e",
-[0x05] 0,0, "FLDCW %e",
-[0x06] 0,0, "FSTENV%S %e",
-[0x07] 0,0, "FSTCW %e",
-[0x08] 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
-[0x09] 0,0, "FMOVD F1,F0",
-[0x0a] 0,0, "FMOVD F2,F0",
-[0x0b] 0,0, "FMOVD F3,F0",
-[0x0c] 0,0, "FMOVD F4,F0",
-[0x0d] 0,0, "FMOVD F5,F0",
-[0x0e] 0,0, "FMOVD F6,F0",
-[0x0f] 0,0, "FMOVD F7,F0",
-[0x10] 0,0, "FXCHD F0,F0",
-[0x11] 0,0, "FXCHD F1,F0",
-[0x12] 0,0, "FXCHD F2,F0",
-[0x13] 0,0, "FXCHD F3,F0",
-[0x14] 0,0, "FXCHD F4,F0",
-[0x15] 0,0, "FXCHD F5,F0",
-[0x16] 0,0, "FXCHD F6,F0",
-[0x17] 0,0, "FXCHD F7,F0",
-[0x18] 0,0, "FNOP",
-[0x28] 0,0, "FCHS",
-[0x29] 0,0, "FABS",
-[0x2c] 0,0, "FTST",
-[0x2d] 0,0, "FXAM",
-[0x30] 0,0, "FLD1",
-[0x31] 0,0, "FLDL2T",
-[0x32] 0,0, "FLDL2E",
-[0x33] 0,0, "FLDPI",
-[0x34] 0,0, "FLDLG2",
-[0x35] 0,0, "FLDLN2",
-[0x36] 0,0, "FLDZ",
-[0x38] 0,0, "F2XM1",
-[0x39] 0,0, "FYL2X",
-[0x3a] 0,0, "FPTAN",
-[0x3b] 0,0, "FPATAN",
-[0x3c] 0,0, "FXTRACT",
-[0x3d] 0,0, "FPREM1",
-[0x3e] 0,0, "FDECSTP",
-[0x3f] 0,0, "FNCSTP",
-[0x40] 0,0, "FPREM",
-[0x41] 0,0, "FYL2XP1",
-[0x42] 0,0, "FSQRT",
-[0x43] 0,0, "FSINCOS",
-[0x44] 0,0, "FRNDINT",
-[0x45] 0,0, "FSCALE",
-[0x46] 0,0, "FSIN",
-[0x47] 0,0, "FCOS",
+[0x00] = { 0,0, "FMOVF %e,F0" },
+[0x02] = { 0,0, "FMOVF F0,%e" },
+[0x03] = { 0,0, "FMOVFP F0,%e" },
+[0x04] = { 0,0, "FLDENV%S %e" },
+[0x05] = { 0,0, "FLDCW %e" },
+[0x06] = { 0,0, "FSTENV%S %e" },
+[0x07] = { 0,0, "FSTCW %e" },
+[0x08] = { 0,0, "FMOVD F0,F0" }, /* Mod R/M = 11xx xxxx*/
+[0x09] = { 0,0, "FMOVD F1,F0" },
+[0x0a] = { 0,0, "FMOVD F2,F0" },
+[0x0b] = { 0,0, "FMOVD F3,F0" },
+[0x0c] = { 0,0, "FMOVD F4,F0" },
+[0x0d] = { 0,0, "FMOVD F5,F0" },
+[0x0e] = { 0,0, "FMOVD F6,F0" },
+[0x0f] = { 0,0, "FMOVD F7,F0" },
+[0x10] = { 0,0, "FXCHD F0,F0" },
+[0x11] = { 0,0, "FXCHD F1,F0" },
+[0x12] = { 0,0, "FXCHD F2,F0" },
+[0x13] = { 0,0, "FXCHD F3,F0" },
+[0x14] = { 0,0, "FXCHD F4,F0" },
+[0x15] = { 0,0, "FXCHD F5,F0" },
+[0x16] = { 0,0, "FXCHD F6,F0" },
+[0x17] = { 0,0, "FXCHD F7,F0" },
+[0x18] = { 0,0, "FNOP" },
+[0x28] = { 0,0, "FCHS" },
+[0x29] = { 0,0, "FABS" },
+[0x2c] = { 0,0, "FTST" },
+[0x2d] = { 0,0, "FXAM" },
+[0x30] = { 0,0, "FLD1" },
+[0x31] = { 0,0, "FLDL2T" },
+[0x32] = { 0,0, "FLDL2E" },
+[0x33] = { 0,0, "FLDPI" },
+[0x34] = { 0,0, "FLDLG2" },
+[0x35] = { 0,0, "FLDLN2" },
+[0x36] = { 0,0, "FLDZ" },
+[0x38] = { 0,0, "F2XM1" },
+[0x39] = { 0,0, "FYL2X" },
+[0x3a] = { 0,0, "FPTAN" },
+[0x3b] = { 0,0, "FPATAN" },
+[0x3c] = { 0,0, "FXTRACT" },
+[0x3d] = { 0,0, "FPREM1" },
+[0x3e] = { 0,0, "FDECSTP" },
+[0x3f] = { 0,0, "FNCSTP" },
+[0x40] = { 0,0, "FPREM" },
+[0x41] = { 0,0, "FYL2XP1" },
+[0x42] = { 0,0, "FSQRT" },
+[0x43] = { 0,0, "FSINCOS" },
+[0x44] = { 0,0, "FRNDINT" },
+[0x45] = { 0,0, "FSCALE" },
+[0x46] = { 0,0, "FSIN" },
+[0x47] = { 0,0, "FCOS" },
};
static Optable optabDA[8+8] =
{
-[0x00] 0,0, "FADDL %e,F0",
-[0x01] 0,0, "FMULL %e,F0",
-[0x02] 0,0, "FCOML %e,F0",
-[0x03] 0,0, "FCOMLP %e,F0",
-[0x04] 0,0, "FSUBL %e,F0",
-[0x05] 0,0, "FSUBRL %e,F0",
-[0x06] 0,0, "FDIVL %e,F0",
-[0x07] 0,0, "FDIVRL %e,F0",
-[0x08] 0,0, "FCMOVCS %f,F0",
-[0x09] 0,0, "FCMOVEQ %f,F0",
-[0x0a] 0,0, "FCMOVLS %f,F0",
-[0x0b] 0,0, "FCMOVUN %f,F0",
-[0x0d] Op_R1,0, "FUCOMPP",
+[0x00] = { 0,0, "FADDL %e,F0" },
+[0x01] = { 0,0, "FMULL %e,F0" },
+[0x02] = { 0,0, "FCOML %e,F0" },
+[0x03] = { 0,0, "FCOMLP %e,F0" },
+[0x04] = { 0,0, "FSUBL %e,F0" },
+[0x05] = { 0,0, "FSUBRL %e,F0" },
+[0x06] = { 0,0, "FDIVL %e,F0" },
+[0x07] = { 0,0, "FDIVRL %e,F0" },
+[0x08] = { 0,0, "FCMOVCS %f,F0" },
+[0x09] = { 0,0, "FCMOVEQ %f,F0" },
+[0x0a] = { 0,0, "FCMOVLS %f,F0" },
+[0x0b] = { 0,0, "FCMOVUN %f,F0" },
+[0x0d] = { Op_R1,0, "FUCOMPP" },
};
static Optable optabDB[8+64] =
{
-[0x00] 0,0, "FMOVL %e,F0",
-[0x02] 0,0, "FMOVL F0,%e",
-[0x03] 0,0, "FMOVLP F0,%e",
-[0x05] 0,0, "FMOVX %e,F0",
-[0x07] 0,0, "FMOVXP F0,%e",
-[0x08] 0,0, "FCMOVCC %f,F0",
-[0x09] 0,0, "FCMOVNE %f,F0",
-[0x0a] 0,0, "FCMOVHI %f,F0",
-[0x0b] 0,0, "FCMOVNU %f,F0",
-[0x0d] 0,0, "FUCOMI F0,%f",
-[0x0e] 0,0, "FCOMI F0,%f",
-[0x2a] 0,0, "FCLEX",
-[0x2b] 0,0, "FINIT",
+[0x00] = { 0,0, "FMOVL %e,F0" },
+[0x02] = { 0,0, "FMOVL F0,%e" },
+[0x03] = { 0,0, "FMOVLP F0,%e" },
+[0x05] = { 0,0, "FMOVX %e,F0" },
+[0x07] = { 0,0, "FMOVXP F0,%e" },
+[0x08] = { 0,0, "FCMOVCC %f,F0" },
+[0x09] = { 0,0, "FCMOVNE %f,F0" },
+[0x0a] = { 0,0, "FCMOVHI %f,F0" },
+[0x0b] = { 0,0, "FCMOVNU %f,F0" },
+[0x0d] = { 0,0, "FUCOMI F0,%f" },
+[0x0e] = { 0,0, "FCOMI F0,%f" },
+[0x2a] = { 0,0, "FCLEX" },
+[0x2b] = { 0,0, "FINIT" },
};
static Optable optabDC[8+8] =
{
-[0x00] 0,0, "FADDD %e,F0",
-[0x01] 0,0, "FMULD %e,F0",
-[0x02] 0,0, "FCOMD %e,F0",
-[0x03] 0,0, "FCOMDP %e,F0",
-[0x04] 0,0, "FSUBD %e,F0",
-[0x05] 0,0, "FSUBRD %e,F0",
-[0x06] 0,0, "FDIVD %e,F0",
-[0x07] 0,0, "FDIVRD %e,F0",
-[0x08] 0,0, "FADDD F0,%f",
-[0x09] 0,0, "FMULD F0,%f",
-[0x0c] 0,0, "FSUBRD F0,%f",
-[0x0d] 0,0, "FSUBD F0,%f",
-[0x0e] 0,0, "FDIVRD F0,%f",
-[0x0f] 0,0, "FDIVD F0,%f",
+[0x00] = { 0,0, "FADDD %e,F0" },
+[0x01] = { 0,0, "FMULD %e,F0" },
+[0x02] = { 0,0, "FCOMD %e,F0" },
+[0x03] = { 0,0, "FCOMDP %e,F0" },
+[0x04] = { 0,0, "FSUBD %e,F0" },
+[0x05] = { 0,0, "FSUBRD %e,F0" },
+[0x06] = { 0,0, "FDIVD %e,F0" },
+[0x07] = { 0,0, "FDIVRD %e,F0" },
+[0x08] = { 0,0, "FADDD F0,%f" },
+[0x09] = { 0,0, "FMULD F0,%f" },
+[0x0c] = { 0,0, "FSUBRD F0,%f" },
+[0x0d] = { 0,0, "FSUBD F0,%f" },
+[0x0e] = { 0,0, "FDIVRD F0,%f" },
+[0x0f] = { 0,0, "FDIVD F0,%f" },
};
static Optable optabDD[8+8] =
{
-[0x00] 0,0, "FMOVD %e,F0",
-[0x02] 0,0, "FMOVD F0,%e",
-[0x03] 0,0, "FMOVDP F0,%e",
-[0x04] 0,0, "FRSTOR%S %e",
-[0x06] 0,0, "FSAVE%S %e",
-[0x07] 0,0, "FSTSW %e",
-[0x08] 0,0, "FFREED %f",
-[0x0a] 0,0, "FMOVD %f,F0",
-[0x0b] 0,0, "FMOVDP %f,F0",
-[0x0c] 0,0, "FUCOMD %f,F0",
-[0x0d] 0,0, "FUCOMDP %f,F0",
+[0x00] = { 0,0, "FMOVD %e,F0" },
+[0x02] = { 0,0, "FMOVD F0,%e" },
+[0x03] = { 0,0, "FMOVDP F0,%e" },
+[0x04] = { 0,0, "FRSTOR%S %e" },
+[0x06] = { 0,0, "FSAVE%S %e" },
+[0x07] = { 0,0, "FSTSW %e" },
+[0x08] = { 0,0, "FFREED %f" },
+[0x0a] = { 0,0, "FMOVD %f,F0" },
+[0x0b] = { 0,0, "FMOVDP %f,F0" },
+[0x0c] = { 0,0, "FUCOMD %f,F0" },
+[0x0d] = { 0,0, "FUCOMDP %f,F0" },
};
static Optable optabDE[8+8] =
{
-[0x00] 0,0, "FADDW %e,F0",
-[0x01] 0,0, "FMULW %e,F0",
-[0x02] 0,0, "FCOMW %e,F0",
-[0x03] 0,0, "FCOMWP %e,F0",
-[0x04] 0,0, "FSUBW %e,F0",
-[0x05] 0,0, "FSUBRW %e,F0",
-[0x06] 0,0, "FDIVW %e,F0",
-[0x07] 0,0, "FDIVRW %e,F0",
-[0x08] 0,0, "FADDDP F0,%f",
-[0x09] 0,0, "FMULDP F0,%f",
-[0x0b] Op_R1,0, "FCOMPDP",
-[0x0c] 0,0, "FSUBRDP F0,%f",
-[0x0d] 0,0, "FSUBDP F0,%f",
-[0x0e] 0,0, "FDIVRDP F0,%f",
-[0x0f] 0,0, "FDIVDP F0,%f",
+[0x00] = { 0,0, "FADDW %e,F0" },
+[0x01] = { 0,0, "FMULW %e,F0" },
+[0x02] = { 0,0, "FCOMW %e,F0" },
+[0x03] = { 0,0, "FCOMWP %e,F0" },
+[0x04] = { 0,0, "FSUBW %e,F0" },
+[0x05] = { 0,0, "FSUBRW %e,F0" },
+[0x06] = { 0,0, "FDIVW %e,F0" },
+[0x07] = { 0,0, "FDIVRW %e,F0" },
+[0x08] = { 0,0, "FADDDP F0,%f" },
+[0x09] = { 0,0, "FMULDP F0,%f" },
+[0x0b] = { Op_R1,0, "FCOMPDP" },
+[0x0c] = { 0,0, "FSUBRDP F0,%f" },
+[0x0d] = { 0,0, "FSUBDP F0,%f" },
+[0x0e] = { 0,0, "FDIVRDP F0,%f" },
+[0x0f] = { 0,0, "FDIVDP F0,%f" },
};
static Optable optabDF[8+8] =
{
-[0x00] 0,0, "FMOVW %e,F0",
-[0x02] 0,0, "FMOVW F0,%e",
-[0x03] 0,0, "FMOVWP F0,%e",
-[0x04] 0,0, "FBLD %e",
-[0x05] 0,0, "FMOVL %e,F0",
-[0x06] 0,0, "FBSTP %e",
-[0x07] 0,0, "FMOVLP F0,%e",
-[0x0c] Op_R0,0, "FSTSW %OAX",
-[0x0d] 0,0, "FUCOMIP F0,%f",
-[0x0e] 0,0, "FCOMIP F0,%f",
+[0x00] = { 0,0, "FMOVW %e,F0" },
+[0x02] = { 0,0, "FMOVW F0,%e" },
+[0x03] = { 0,0, "FMOVWP F0,%e" },
+[0x04] = { 0,0, "FBLD %e" },
+[0x05] = { 0,0, "FMOVL %e,F0" },
+[0x06] = { 0,0, "FBSTP %e" },
+[0x07] = { 0,0, "FMOVLP F0,%e" },
+[0x0c] = { Op_R0,0, "FSTSW %OAX" },
+[0x0d] = { 0,0, "FUCOMIP F0,%f" },
+[0x0e] = { 0,0, "FCOMIP F0,%f" },
};
static Optable optabF6[8] =
{
-[0x00] Ib,0, "TESTB %i,%e",
-[0x02] 0,0, "NOTB %e",
-[0x03] 0,0, "NEGB %e",
-[0x04] 0,0, "MULB AL,%e",
-[0x05] 0,0, "IMULB AL,%e",
-[0x06] 0,0, "DIVB AL,%e",
-[0x07] 0,0, "IDIVB AL,%e",
+[0x00] = { Ib,0, "TESTB %i,%e" },
+[0x02] = { 0,0, "NOTB %e" },
+[0x03] = { 0,0, "NEGB %e" },
+[0x04] = { 0,0, "MULB AL,%e" },
+[0x05] = { 0,0, "IMULB AL,%e" },
+[0x06] = { 0,0, "DIVB AL,%e" },
+[0x07] = { 0,0, "IDIVB AL,%e" },
};
static Optable optabF7[8] =
{
-[0x00] Iwd,0, "TEST%S %i,%e",
-[0x02] 0,0, "NOT%S %e",
-[0x03] 0,0, "NEG%S %e",
-[0x04] 0,0, "MUL%S %OAX,%e",
-[0x05] 0,0, "IMUL%S %OAX,%e",
-[0x06] 0,0, "DIV%S %OAX,%e",
-[0x07] 0,0, "IDIV%S %OAX,%e",
+[0x00] = { Iwd,0, "TEST%S %i,%e" },
+[0x02] = { 0,0, "NOT%S %e" },
+[0x03] = { 0,0, "NEG%S %e" },
+[0x04] = { 0,0, "MUL%S %OAX,%e" },
+[0x05] = { 0,0, "IMUL%S %OAX,%e" },
+[0x06] = { 0,0, "DIV%S %OAX,%e" },
+[0x07] = { 0,0, "IDIV%S %OAX,%e" },
};
static Optable optabFE[8] =
{
-[0x00] 0,0, "INCB %e",
-[0x01] 0,0, "DECB %e",
+[0x00] = { 0,0, "INCB %e" },
+[0x01] = { 0,0, "DECB %e" },
};
static Optable optabFF[8] =
{
-[0x00] 0,0, "INC%S %e",
-[0x01] 0,0, "DEC%S %e",
-[0x02] JUMP,0, "CALL* %e",
-[0x03] JUMP,0, "CALLF* %e",
-[0x04] JUMP,0, "JMP* %e",
-[0x05] JUMP,0, "JMPF* %e",
-[0x06] 0,0, "PUSHL %e",
+[0x00] = { 0,0, "INC%S %e" },
+[0x01] = { 0,0, "DEC%S %e" },
+[0x02] = { JUMP,0, "CALL* %e" },
+[0x03] = { JUMP,0, "CALLF* %e" },
+[0x04] = { JUMP,0, "JMP* %e" },
+[0x05] = { JUMP,0, "JMPF* %e" },
+[0x06] = { 0,0, "PUSHL %e" },
};
static Optable optable[256+2] =
{
-[0x00] RMB,0, "ADDB %r,%e",
-[0x01] RM,0, "ADD%S %r,%e",
-[0x02] RMB,0, "ADDB %e,%r",
-[0x03] RM,0, "ADD%S %e,%r",
-[0x04] Ib,0, "ADDB %i,AL",
-[0x05] Iwd,0, "ADD%S %i,%OAX",
-[0x06] 0,0, "PUSHL ES",
-[0x07] 0,0, "POPL ES",
-[0x08] RMB,0, "ORB %r,%e",
-[0x09] RM,0, "OR%S %r,%e",
-[0x0a] RMB,0, "ORB %e,%r",
-[0x0b] RM,0, "OR%S %e,%r",
-[0x0c] Ib,0, "ORB %i,AL",
-[0x0d] Iwd,0, "OR%S %i,%OAX",
-[0x0e] 0,0, "PUSHL CS",
-[0x0f] AUXMM,0, optab0F,
-[0x10] RMB,0, "ADCB %r,%e",
-[0x11] RM,0, "ADC%S %r,%e",
-[0x12] RMB,0, "ADCB %e,%r",
-[0x13] RM,0, "ADC%S %e,%r",
-[0x14] Ib,0, "ADCB %i,AL",
-[0x15] Iwd,0, "ADC%S %i,%OAX",
-[0x16] 0,0, "PUSHL SS",
-[0x17] 0,0, "POPL SS",
-[0x18] RMB,0, "SBBB %r,%e",
-[0x19] RM,0, "SBB%S %r,%e",
-[0x1a] RMB,0, "SBBB %e,%r",
-[0x1b] RM,0, "SBB%S %e,%r",
-[0x1c] Ib,0, "SBBB %i,AL",
-[0x1d] Iwd,0, "SBB%S %i,%OAX",
-[0x1e] 0,0, "PUSHL DS",
-[0x1f] 0,0, "POPL DS",
-[0x20] RMB,0, "ANDB %r,%e",
-[0x21] RM,0, "AND%S %r,%e",
-[0x22] RMB,0, "ANDB %e,%r",
-[0x23] RM,0, "AND%S %e,%r",
-[0x24] Ib,0, "ANDB %i,AL",
-[0x25] Iwd,0, "AND%S %i,%OAX",
-[0x26] SEG,0, "ES:",
-[0x27] 0,0, "DAA",
-[0x28] RMB,0, "SUBB %r,%e",
-[0x29] RM,0, "SUB%S %r,%e",
-[0x2a] RMB,0, "SUBB %e,%r",
-[0x2b] RM,0, "SUB%S %e,%r",
-[0x2c] Ib,0, "SUBB %i,AL",
-[0x2d] Iwd,0, "SUB%S %i,%OAX",
-[0x2e] SEG,0, "CS:",
-[0x2f] 0,0, "DAS",
-[0x30] RMB,0, "XORB %r,%e",
-[0x31] RM,0, "XOR%S %r,%e",
-[0x32] RMB,0, "XORB %e,%r",
-[0x33] RM,0, "XOR%S %e,%r",
-[0x34] Ib,0, "XORB %i,AL",
-[0x35] Iwd,0, "XOR%S %i,%OAX",
-[0x36] SEG,0, "SS:",
-[0x37] 0,0, "AAA",
-[0x38] RMB,0, "CMPB %r,%e",
-[0x39] RM,0, "CMP%S %r,%e",
-[0x3a] RMB,0, "CMPB %e,%r",
-[0x3b] RM,0, "CMP%S %e,%r",
-[0x3c] Ib,0, "CMPB %i,AL",
-[0x3d] Iwd,0, "CMP%S %i,%OAX",
-[0x3e] SEG,0, "DS:",
-[0x3f] 0,0, "AAS",
-[0x40] 0,0, "INC%S %OAX",
-[0x41] 0,0, "INC%S %OCX",
-[0x42] 0,0, "INC%S %ODX",
-[0x43] 0,0, "INC%S %OBX",
-[0x44] 0,0, "INC%S %OSP",
-[0x45] 0,0, "INC%S %OBP",
-[0x46] 0,0, "INC%S %OSI",
-[0x47] 0,0, "INC%S %ODI",
-[0x48] 0,0, "DEC%S %OAX",
-[0x49] 0,0, "DEC%S %OCX",
-[0x4a] 0,0, "DEC%S %ODX",
-[0x4b] 0,0, "DEC%S %OBX",
-[0x4c] 0,0, "DEC%S %OSP",
-[0x4d] 0,0, "DEC%S %OBP",
-[0x4e] 0,0, "DEC%S %OSI",
-[0x4f] 0,0, "DEC%S %ODI",
-[0x50] 0,0, "PUSH%S %OAX",
-[0x51] 0,0, "PUSH%S %OCX",
-[0x52] 0,0, "PUSH%S %ODX",
-[0x53] 0,0, "PUSH%S %OBX",
-[0x54] 0,0, "PUSH%S %OSP",
-[0x55] 0,0, "PUSH%S %OBP",
-[0x56] 0,0, "PUSH%S %OSI",
-[0x57] 0,0, "PUSH%S %ODI",
-[0x58] 0,0, "POP%S %OAX",
-[0x59] 0,0, "POP%S %OCX",
-[0x5a] 0,0, "POP%S %ODX",
-[0x5b] 0,0, "POP%S %OBX",
-[0x5c] 0,0, "POP%S %OSP",
-[0x5d] 0,0, "POP%S %OBP",
-[0x5e] 0,0, "POP%S %OSI",
-[0x5f] 0,0, "POP%S %ODI",
-[0x60] 0,0, "PUSHA%S",
-[0x61] 0,0, "POPA%S",
-[0x62] RMM,0, "BOUND %e,%r",
-[0x63] RM,0, "ARPL %r,%e",
-[0x64] SEG,0, "FS:",
-[0x65] SEG,0, "GS:",
-[0x66] OPOVER,0, "",
-[0x67] ADDOVER,0, "",
-[0x68] Iwd,0, "PUSH%S %i",
-[0x69] RM,Iwd, "IMUL%S %e,%i,%r",
-[0x6a] Ib,0, "PUSH%S %i",
-[0x6b] RM,Ibs, "IMUL%S %e,%i,%r",
-[0x6c] 0,0, "INSB DX,(%ODI)",
-[0x6d] 0,0, "INS%S DX,(%ODI)",
-[0x6e] 0,0, "OUTSB (%ASI),DX",
-[0x6f] 0,0, "OUTS%S (%ASI),DX",
-[0x70] Jbs,0, "JOS %p",
-[0x71] Jbs,0, "JOC %p",
-[0x72] Jbs,0, "JCS %p",
-[0x73] Jbs,0, "JCC %p",
-[0x74] Jbs,0, "JEQ %p",
-[0x75] Jbs,0, "JNE %p",
-[0x76] Jbs,0, "JLS %p",
-[0x77] Jbs,0, "JHI %p",
-[0x78] Jbs,0, "JMI %p",
-[0x79] Jbs,0, "JPL %p",
-[0x7a] Jbs,0, "JPS %p",
-[0x7b] Jbs,0, "JPC %p",
-[0x7c] Jbs,0, "JLT %p",
-[0x7d] Jbs,0, "JGE %p",
-[0x7e] Jbs,0, "JLE %p",
-[0x7f] Jbs,0, "JGT %p",
-[0x80] RMOPB,0, optab80,
-[0x81] RMOP,0, optab81,
-[0x83] RMOP,0, optab83,
-[0x84] RMB,0, "TESTB %r,%e",
-[0x85] RM,0, "TEST%S %r,%e",
-[0x86] RMB,0, "XCHGB %r,%e",
-[0x87] RM,0, "XCHG%S %r,%e",
-[0x88] RMB,0, "MOVB %r,%e",
-[0x89] RM,0, "MOV%S %r,%e",
-[0x8a] RMB,0, "MOVB %e,%r",
-[0x8b] RM,0, "MOV%S %e,%r",
-[0x8c] RM,0, "MOVW %g,%e",
-[0x8d] RM,0, "LEA%S %e,%r",
-[0x8e] RM,0, "MOVW %e,%g",
-[0x8f] RM,0, "POP%S %e",
-[0x90] 0,0, "NOP",
-[0x91] 0,0, "XCHG %OCX,%OAX",
-[0x92] 0,0, "XCHG %ODX,%OAX",
-[0x93] 0,0, "XCHG %OBX,%OAX",
-[0x94] 0,0, "XCHG %OSP,%OAX",
-[0x95] 0,0, "XCHG %OBP,%OAX",
-[0x96] 0,0, "XCHG %OSI,%OAX",
-[0x97] 0,0, "XCHG %ODI,%OAX",
-[0x98] 0,0, "%W", /* miserable CBW or CWDE */
-[0x99] 0,0, "%w", /* idiotic CWD or CDQ */
-[0x9a] PTR,0, "CALL%S %d",
-[0x9b] 0,0, "WAIT",
-[0x9c] 0,0, "PUSHF",
-[0x9d] 0,0, "POPF",
-[0x9e] 0,0, "SAHF",
-[0x9f] 0,0, "LAHF",
-[0xa0] Awd,0, "MOVB %i,AL",
-[0xa1] Awd,0, "MOV%S %i,%OAX",
-[0xa2] Awd,0, "MOVB AL,%i",
-[0xa3] Awd,0, "MOV%S %OAX,%i",
-[0xa4] 0,0, "MOVSB (%ASI),(%ADI)",
-[0xa5] 0,0, "MOVS%S (%ASI),(%ADI)",
-[0xa6] 0,0, "CMPSB (%ASI),(%ADI)",
-[0xa7] 0,0, "CMPS%S (%ASI),(%ADI)",
-[0xa8] Ib,0, "TESTB %i,AL",
-[0xa9] Iwd,0, "TEST%S %i,%OAX",
-[0xaa] 0,0, "STOSB AL,(%ADI)",
-[0xab] 0,0, "STOS%S %OAX,(%ADI)",
-[0xac] 0,0, "LODSB (%ASI),AL",
-[0xad] 0,0, "LODS%S (%ASI),%OAX",
-[0xae] 0,0, "SCASB (%ADI),AL",
-[0xaf] 0,0, "SCAS%S (%ADI),%OAX",
-[0xb0] Ib,0, "MOVB %i,AL",
-[0xb1] Ib,0, "MOVB %i,CL",
-[0xb2] Ib,0, "MOVB %i,DL",
-[0xb3] Ib,0, "MOVB %i,BL",
-[0xb4] Ib,0, "MOVB %i,AH",
-[0xb5] Ib,0, "MOVB %i,CH",
-[0xb6] Ib,0, "MOVB %i,DH",
-[0xb7] Ib,0, "MOVB %i,BH",
-[0xb8] Iwdq,0, "MOV%S %i,%OAX",
-[0xb9] Iwdq,0, "MOV%S %i,%OCX",
-[0xba] Iwdq,0, "MOV%S %i,%ODX",
-[0xbb] Iwdq,0, "MOV%S %i,%OBX",
-[0xbc] Iwdq,0, "MOV%S %i,%OSP",
-[0xbd] Iwdq,0, "MOV%S %i,%OBP",
-[0xbe] Iwdq,0, "MOV%S %i,%OSI",
-[0xbf] Iwdq,0, "MOV%S %i,%ODI",
-[0xc0] RMOPB,0, optabC0,
-[0xc1] RMOP,0, optabC1,
-[0xc2] Iw,0, "RET %i",
-[0xc3] RET,0, "RET",
-[0xc4] RM,0, "LES %e,%r",
-[0xc5] RM,0, "LDS %e,%r",
-[0xc6] RMB,Ib, "MOVB %i,%e",
-[0xc7] RM,Iwd, "MOV%S %i,%e",
-[0xc8] Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
-[0xc9] RET,0, "LEAVE", /* bizarre LEAVE */
-[0xca] Iw,0, "RETF %i",
-[0xcb] RET,0, "RETF",
-[0xcc] 0,0, "INT 3",
-[0xcd] Ib,0, "INTB %i",
-[0xce] 0,0, "INTO",
-[0xcf] 0,0, "IRET",
-[0xd0] RMOPB,0, optabD0,
-[0xd1] RMOP,0, optabD1,
-[0xd2] RMOPB,0, optabD2,
-[0xd3] RMOP,0, optabD3,
-[0xd4] OA,0, "AAM",
-[0xd5] OA,0, "AAD",
-[0xd7] 0,0, "XLAT",
-[0xd8] FRMOP,0, optabD8,
-[0xd9] FRMEX,0, optabD9,
-[0xda] FRMOP,0, optabDA,
-[0xdb] FRMEX,0, optabDB,
-[0xdc] FRMOP,0, optabDC,
-[0xdd] FRMOP,0, optabDD,
-[0xde] FRMOP,0, optabDE,
-[0xdf] FRMOP,0, optabDF,
-[0xe0] Jbs,0, "LOOPNE %p",
-[0xe1] Jbs,0, "LOOPE %p",
-[0xe2] Jbs,0, "LOOP %p",
-[0xe3] Jbs,0, "JCXZ %p",
-[0xe4] Ib,0, "INB %i,AL",
-[0xe5] Ib,0, "IN%S %i,%OAX",
-[0xe6] Ib,0, "OUTB AL,%i",
-[0xe7] Ib,0, "OUT%S %OAX,%i",
-[0xe8] Iwds,0, "CALL %p",
-[0xe9] Iwds,0, "JMP %p",
-[0xea] PTR,0, "JMP %d",
-[0xeb] Jbs,0, "JMP %p",
-[0xec] 0,0, "INB DX,AL",
-[0xed] 0,0, "IN%S DX,%OAX",
-[0xee] 0,0, "OUTB AL,DX",
-[0xef] 0,0, "OUT%S %OAX,DX",
-[0xf0] PRE,0, "LOCK",
-[0xf2] OPRE,0, "REPNE",
-[0xf3] OPRE,0, "REP",
-[0xf4] 0,0, "HLT",
-[0xf5] 0,0, "CMC",
-[0xf6] RMOPB,0, optabF6,
-[0xf7] RMOP,0, optabF7,
-[0xf8] 0,0, "CLC",
-[0xf9] 0,0, "STC",
-[0xfa] 0,0, "CLI",
-[0xfb] 0,0, "STI",
-[0xfc] 0,0, "CLD",
-[0xfd] 0,0, "STD",
-[0xfe] RMOPB,0, optabFE,
-[0xff] RMOP,0, optabFF,
-[0x100] RM,0, "MOVLQSX %e,%r",
-[0x101] RM,0, "MOVLQZX %e,%r",
+[0x00] = { RMB,0, "ADDB %r,%e" },
+[0x01] = { RM,0, "ADD%S %r,%e" },
+[0x02] = { RMB,0, "ADDB %e,%r" },
+[0x03] = { RM,0, "ADD%S %e,%r" },
+[0x04] = { Ib,0, "ADDB %i,AL" },
+[0x05] = { Iwd,0, "ADD%S %i,%OAX" },
+[0x06] = { 0,0, "PUSHL ES" },
+[0x07] = { 0,0, "POPL ES" },
+[0x08] = { RMB,0, "ORB %r,%e" },
+[0x09] = { RM,0, "OR%S %r,%e" },
+[0x0a] = { RMB,0, "ORB %e,%r" },
+[0x0b] = { RM,0, "OR%S %e,%r" },
+[0x0c] = { Ib,0, "ORB %i,AL" },
+[0x0d] = { Iwd,0, "OR%S %i,%OAX" },
+[0x0e] = { 0,0, "PUSHL CS" },
+[0x0f] = { AUXMM,0, optab0F },
+[0x10] = { RMB,0, "ADCB %r,%e" },
+[0x11] = { RM,0, "ADC%S %r,%e" },
+[0x12] = { RMB,0, "ADCB %e,%r" },
+[0x13] = { RM,0, "ADC%S %e,%r" },
+[0x14] = { Ib,0, "ADCB %i,AL" },
+[0x15] = { Iwd,0, "ADC%S %i,%OAX" },
+[0x16] = { 0,0, "PUSHL SS" },
+[0x17] = { 0,0, "POPL SS" },
+[0x18] = { RMB,0, "SBBB %r,%e" },
+[0x19] = { RM,0, "SBB%S %r,%e" },
+[0x1a] = { RMB,0, "SBBB %e,%r" },
+[0x1b] = { RM,0, "SBB%S %e,%r" },
+[0x1c] = { Ib,0, "SBBB %i,AL" },
+[0x1d] = { Iwd,0, "SBB%S %i,%OAX" },
+[0x1e] = { 0,0, "PUSHL DS" },
+[0x1f] = { 0,0, "POPL DS" },
+[0x20] = { RMB,0, "ANDB %r,%e" },
+[0x21] = { RM,0, "AND%S %r,%e" },
+[0x22] = { RMB,0, "ANDB %e,%r" },
+[0x23] = { RM,0, "AND%S %e,%r" },
+[0x24] = { Ib,0, "ANDB %i,AL" },
+[0x25] = { Iwd,0, "AND%S %i,%OAX" },
+[0x26] = { SEG,0, "ES:" },
+[0x27] = { 0,0, "DAA" },
+[0x28] = { RMB,0, "SUBB %r,%e" },
+[0x29] = { RM,0, "SUB%S %r,%e" },
+[0x2a] = { RMB,0, "SUBB %e,%r" },
+[0x2b] = { RM,0, "SUB%S %e,%r" },
+[0x2c] = { Ib,0, "SUBB %i,AL" },
+[0x2d] = { Iwd,0, "SUB%S %i,%OAX" },
+[0x2e] = { SEG,0, "CS:" },
+[0x2f] = { 0,0, "DAS" },
+[0x30] = { RMB,0, "XORB %r,%e" },
+[0x31] = { RM,0, "XOR%S %r,%e" },
+[0x32] = { RMB,0, "XORB %e,%r" },
+[0x33] = { RM,0, "XOR%S %e,%r" },
+[0x34] = { Ib,0, "XORB %i,AL" },
+[0x35] = { Iwd,0, "XOR%S %i,%OAX" },
+[0x36] = { SEG,0, "SS:" },
+[0x37] = { 0,0, "AAA" },
+[0x38] = { RMB,0, "CMPB %r,%e" },
+[0x39] = { RM,0, "CMP%S %r,%e" },
+[0x3a] = { RMB,0, "CMPB %e,%r" },
+[0x3b] = { RM,0, "CMP%S %e,%r" },
+[0x3c] = { Ib,0, "CMPB %i,AL" },
+[0x3d] = { Iwd,0, "CMP%S %i,%OAX" },
+[0x3e] = { SEG,0, "DS:" },
+[0x3f] = { 0,0, "AAS" },
+[0x40] = { 0,0, "INC%S %OAX" },
+[0x41] = { 0,0, "INC%S %OCX" },
+[0x42] = { 0,0, "INC%S %ODX" },
+[0x43] = { 0,0, "INC%S %OBX" },
+[0x44] = { 0,0, "INC%S %OSP" },
+[0x45] = { 0,0, "INC%S %OBP" },
+[0x46] = { 0,0, "INC%S %OSI" },
+[0x47] = { 0,0, "INC%S %ODI" },
+[0x48] = { 0,0, "DEC%S %OAX" },
+[0x49] = { 0,0, "DEC%S %OCX" },
+[0x4a] = { 0,0, "DEC%S %ODX" },
+[0x4b] = { 0,0, "DEC%S %OBX" },
+[0x4c] = { 0,0, "DEC%S %OSP" },
+[0x4d] = { 0,0, "DEC%S %OBP" },
+[0x4e] = { 0,0, "DEC%S %OSI" },
+[0x4f] = { 0,0, "DEC%S %ODI" },
+[0x50] = { 0,0, "PUSH%S %OAX" },
+[0x51] = { 0,0, "PUSH%S %OCX" },
+[0x52] = { 0,0, "PUSH%S %ODX" },
+[0x53] = { 0,0, "PUSH%S %OBX" },
+[0x54] = { 0,0, "PUSH%S %OSP" },
+[0x55] = { 0,0, "PUSH%S %OBP" },
+[0x56] = { 0,0, "PUSH%S %OSI" },
+[0x57] = { 0,0, "PUSH%S %ODI" },
+[0x58] = { 0,0, "POP%S %OAX" },
+[0x59] = { 0,0, "POP%S %OCX" },
+[0x5a] = { 0,0, "POP%S %ODX" },
+[0x5b] = { 0,0, "POP%S %OBX" },
+[0x5c] = { 0,0, "POP%S %OSP" },
+[0x5d] = { 0,0, "POP%S %OBP" },
+[0x5e] = { 0,0, "POP%S %OSI" },
+[0x5f] = { 0,0, "POP%S %ODI" },
+[0x60] = { 0,0, "PUSHA%S" },
+[0x61] = { 0,0, "POPA%S" },
+[0x62] = { RMM,0, "BOUND %e,%r" },
+[0x63] = { RM,0, "ARPL %r,%e" },
+[0x64] = { SEG,0, "FS:" },
+[0x65] = { SEG,0, "GS:" },
+[0x66] = { OPOVER,0, "" },
+[0x67] = { ADDOVER,0, "" },
+[0x68] = { Iwd,0, "PUSH%S %i" },
+[0x69] = { RM,Iwd, "IMUL%S %e,%i,%r" },
+[0x6a] = { Ib,0, "PUSH%S %i" },
+[0x6b] = { RM,Ibs, "IMUL%S %e,%i,%r" },
+[0x6c] = { 0,0, "INSB DX,(%ODI)" },
+[0x6d] = { 0,0, "INS%S DX,(%ODI)" },
+[0x6e] = { 0,0, "OUTSB (%ASI),DX" },
+[0x6f] = { 0,0, "OUTS%S (%ASI),DX" },
+[0x70] = { Jbs,0, "JOS %p" },
+[0x71] = { Jbs,0, "JOC %p" },
+[0x72] = { Jbs,0, "JCS %p" },
+[0x73] = { Jbs,0, "JCC %p" },
+[0x74] = { Jbs,0, "JEQ %p" },
+[0x75] = { Jbs,0, "JNE %p" },
+[0x76] = { Jbs,0, "JLS %p" },
+[0x77] = { Jbs,0, "JHI %p" },
+[0x78] = { Jbs,0, "JMI %p" },
+[0x79] = { Jbs,0, "JPL %p" },
+[0x7a] = { Jbs,0, "JPS %p" },
+[0x7b] = { Jbs,0, "JPC %p" },
+[0x7c] = { Jbs,0, "JLT %p" },
+[0x7d] = { Jbs,0, "JGE %p" },
+[0x7e] = { Jbs,0, "JLE %p" },
+[0x7f] = { Jbs,0, "JGT %p" },
+[0x80] = { RMOPB,0, optab80 },
+[0x81] = { RMOP,0, optab81 },
+[0x83] = { RMOP,0, optab83 },
+[0x84] = { RMB,0, "TESTB %r,%e" },
+[0x85] = { RM,0, "TEST%S %r,%e" },
+[0x86] = { RMB,0, "XCHGB %r,%e" },
+[0x87] = { RM,0, "XCHG%S %r,%e" },
+[0x88] = { RMB,0, "MOVB %r,%e" },
+[0x89] = { RM,0, "MOV%S %r,%e" },
+[0x8a] = { RMB,0, "MOVB %e,%r" },
+[0x8b] = { RM,0, "MOV%S %e,%r" },
+[0x8c] = { RM,0, "MOVW %g,%e" },
+[0x8d] = { RM,0, "LEA%S %e,%r" },
+[0x8e] = { RM,0, "MOVW %e,%g" },
+[0x8f] = { RM,0, "POP%S %e" },
+[0x90] = { 0,0, "NOP" },
+[0x91] = { 0,0, "XCHG %OCX,%OAX" },
+[0x92] = { 0,0, "XCHG %ODX,%OAX" },
+[0x93] = { 0,0, "XCHG %OBX,%OAX" },
+[0x94] = { 0,0, "XCHG %OSP,%OAX" },
+[0x95] = { 0,0, "XCHG %OBP,%OAX" },
+[0x96] = { 0,0, "XCHG %OSI,%OAX" },
+[0x97] = { 0,0, "XCHG %ODI,%OAX" },
+[0x98] = { 0,0, "%W" }, /* miserable CBW or CWDE */
+[0x99] = { 0,0, "%w" }, /* idiotic CWD or CDQ */
+[0x9a] = { PTR,0, "CALL%S %d" },
+[0x9b] = { 0,0, "WAIT" },
+[0x9c] = { 0,0, "PUSHF" },
+[0x9d] = { 0,0, "POPF" },
+[0x9e] = { 0,0, "SAHF" },
+[0x9f] = { 0,0, "LAHF" },
+[0xa0] = { Awd,0, "MOVB %i,AL" },
+[0xa1] = { Awd,0, "MOV%S %i,%OAX" },
+[0xa2] = { Awd,0, "MOVB AL,%i" },
+[0xa3] = { Awd,0, "MOV%S %OAX,%i" },
+[0xa4] = { 0,0, "MOVSB (%ASI),(%ADI)" },
+[0xa5] = { 0,0, "MOVS%S (%ASI),(%ADI)" },
+[0xa6] = { 0,0, "CMPSB (%ASI),(%ADI)" },
+[0xa7] = { 0,0, "CMPS%S (%ASI),(%ADI)" },
+[0xa8] = { Ib,0, "TESTB %i,AL" },
+[0xa9] = { Iwd,0, "TEST%S %i,%OAX" },
+[0xaa] = { 0,0, "STOSB AL,(%ADI)" },
+[0xab] = { 0,0, "STOS%S %OAX,(%ADI)" },
+[0xac] = { 0,0, "LODSB (%ASI),AL" },
+[0xad] = { 0,0, "LODS%S (%ASI),%OAX" },
+[0xae] = { 0,0, "SCASB (%ADI),AL" },
+[0xaf] = { 0,0, "SCAS%S (%ADI),%OAX" },
+[0xb0] = { Ib,0, "MOVB %i,AL" },
+[0xb1] = { Ib,0, "MOVB %i,CL" },
+[0xb2] = { Ib,0, "MOVB %i,DL" },
+[0xb3] = { Ib,0, "MOVB %i,BL" },
+[0xb4] = { Ib,0, "MOVB %i,AH" },
+[0xb5] = { Ib,0, "MOVB %i,CH" },
+[0xb6] = { Ib,0, "MOVB %i,DH" },
+[0xb7] = { Ib,0, "MOVB %i,BH" },
+[0xb8] = { Iwdq,0, "MOV%S %i,%OAX" },
+[0xb9] = { Iwdq,0, "MOV%S %i,%OCX" },
+[0xba] = { Iwdq,0, "MOV%S %i,%ODX" },
+[0xbb] = { Iwdq,0, "MOV%S %i,%OBX" },
+[0xbc] = { Iwdq,0, "MOV%S %i,%OSP" },
+[0xbd] = { Iwdq,0, "MOV%S %i,%OBP" },
+[0xbe] = { Iwdq,0, "MOV%S %i,%OSI" },
+[0xbf] = { Iwdq,0, "MOV%S %i,%ODI" },
+[0xc0] = { RMOPB,0, optabC0 },
+[0xc1] = { RMOP,0, optabC1 },
+[0xc2] = { Iw,0, "RET %i" },
+[0xc3] = { RET,0, "RET" },
+[0xc4] = { RM,0, "LES %e,%r" },
+[0xc5] = { RM,0, "LDS %e,%r" },
+[0xc6] = { RMB,Ib, "MOVB %i,%e" },
+[0xc7] = { RM,Iwd, "MOV%S %i,%e" },
+[0xc8] = { Iw2,Ib, "ENTER %i,%I" }, /* loony ENTER */
+[0xc9] = { RET,0, "LEAVE" }, /* bizarre LEAVE */
+[0xca] = { Iw,0, "RETF %i" },
+[0xcb] = { RET,0, "RETF" },
+[0xcc] = { 0,0, "INT 3" },
+[0xcd] = { Ib,0, "INTB %i" },
+[0xce] = { 0,0, "INTO" },
+[0xcf] = { 0,0, "IRET" },
+[0xd0] = { RMOPB,0, optabD0 },
+[0xd1] = { RMOP,0, optabD1 },
+[0xd2] = { RMOPB,0, optabD2 },
+[0xd3] = { RMOP,0, optabD3 },
+[0xd4] = { OA,0, "AAM" },
+[0xd5] = { OA,0, "AAD" },
+[0xd7] = { 0,0, "XLAT" },
+[0xd8] = { FRMOP,0, optabD8 },
+[0xd9] = { FRMEX,0, optabD9 },
+[0xda] = { FRMOP,0, optabDA },
+[0xdb] = { FRMEX,0, optabDB },
+[0xdc] = { FRMOP,0, optabDC },
+[0xdd] = { FRMOP,0, optabDD },
+[0xde] = { FRMOP,0, optabDE },
+[0xdf] = { FRMOP,0, optabDF },
+[0xe0] = { Jbs,0, "LOOPNE %p" },
+[0xe1] = { Jbs,0, "LOOPE %p" },
+[0xe2] = { Jbs,0, "LOOP %p" },
+[0xe3] = { Jbs,0, "JCXZ %p" },
+[0xe4] = { Ib,0, "INB %i,AL" },
+[0xe5] = { Ib,0, "IN%S %i,%OAX" },
+[0xe6] = { Ib,0, "OUTB AL,%i" },
+[0xe7] = { Ib,0, "OUT%S %OAX,%i" },
+[0xe8] = { Iwds,0, "CALL %p" },
+[0xe9] = { Iwds,0, "JMP %p" },
+[0xea] = { PTR,0, "JMP %d" },
+[0xeb] = { Jbs,0, "JMP %p" },
+[0xec] = { 0,0, "INB DX,AL" },
+[0xed] = { 0,0, "IN%S DX,%OAX" },
+[0xee] = { 0,0, "OUTB AL,DX" },
+[0xef] = { 0,0, "OUT%S %OAX,DX" },
+[0xf0] = { PRE,0, "LOCK" },
+[0xf2] = { OPRE,0, "REPNE" },
+[0xf3] = { OPRE,0, "REP" },
+[0xf4] = { 0,0, "HLT" },
+[0xf5] = { 0,0, "CMC" },
+[0xf6] = { RMOPB,0, optabF6 },
+[0xf7] = { RMOP,0, optabF7 },
+[0xf8] = { 0,0, "CLC" },
+[0xf9] = { 0,0, "STC" },
+[0xfa] = { 0,0, "CLI" },
+[0xfb] = { 0,0, "STI" },
+[0xfc] = { 0,0, "CLD" },
+[0xfd] = { 0,0, "STD" },
+[0xfe] = { RMOPB,0, optabFE },
+[0xff] = { RMOP,0, optabFF },
+[0x100] = { RM,0, "MOVLQSX %e,%r" },
+[0x101] = { RM,0, "MOVLQZX %e,%r" },
};
/*
@@ -1894,24 +1894,24 @@ bprint(Instr *ip, char *fmt, ...)
#define ONAME(ip) ""
static char *reg[] = {
-[AX] "AX",
-[CX] "CX",
-[DX] "DX",
-[BX] "BX",
-[SP] "SP",
-[BP] "BP",
-[SI] "SI",
-[DI] "DI",
+[AX] = "AX",
+[CX] = "CX",
+[DX] = "DX",
+[BX] = "BX",
+[SP] = "SP",
+[BP] = "BP",
+[SI] = "SI",
+[DI] = "DI",
/* amd64 */
-[AMD64_R8] "R8",
-[AMD64_R9] "R9",
-[AMD64_R10] "R10",
-[AMD64_R11] "R11",
-[AMD64_R12] "R12",
-[AMD64_R13] "R13",
-[AMD64_R14] "R14",
-[AMD64_R15] "R15",
+[AMD64_R8] = "R8",
+[AMD64_R9] = "R9",
+[AMD64_R10] = "R10",
+[AMD64_R11] = "R11",
+[AMD64_R12] = "R12",
+[AMD64_R13] = "R13",
+[AMD64_R14] = "R14",
+[AMD64_R15] = "R15",
};
static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
diff --git a/src/libmach/obj.c b/src/libmach/obj.c
index 7d660787b..7999f24c6 100644
--- a/src/libmach/obj.c
+++ b/src/libmach/obj.c
@@ -81,17 +81,17 @@ struct Obj /* functions to handle each intermediate (.$O) file */
static Obj obj[] =
{ /* functions to identify and parse each type of obj */
- [Obj68020] "68020 .2", _is2, _read2,
- [ObjAmd64] "amd64 .6", _is6, _read6,
- [ObjArm] "arm .5", _is5, _read5,
- [ObjAlpha] "alpha .7", _is7, _read7,
- [Obj386] "386 .8", _is8, _read8,
- [ObjSparc] "sparc .k", _isk, _readk,
- [ObjPower] "power .q", _isq, _readq,
- [ObjMips] "mips .v", _isv, _readv,
- [ObjSparc64] "sparc64 .u", _isu, _readu,
- [ObjPower64] "power64 .9", _is9, _read9,
- [Maxobjtype] 0, 0
+ [Obj68020] = { "68020 .2", _is2, _read2 },
+ [ObjAmd64] = { "amd64 .6", _is6 , _read6 },
+ [ObjArm] = { "arm .5", _is5, _read5 },
+ [ObjAlpha] = { "alpha .7", _is7, _read7 },
+ [Obj386] = { "386 .8", _is8, _read8 },
+ [ObjSparc] = { "sparc .k", _isk, _readk },
+ [ObjPower] = { "power .q", _isq, _readq },
+ [ObjMips] = { "mips .v", _isv, _readv },
+ [ObjSparc64] = { "sparc64 .u", _isu, _readu },
+ [ObjPower64] = { "power64 .9", _is9, _read9 },
+ [Maxobjtype] = { 0, 0, 0 }
};
struct Symtab
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index fc5548e98..2d6b3d014 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -59,7 +59,7 @@ DIRS=\
crypto/tls\
crypto/twofish\
crypto/x509\
- crypto/x509/crl\
+ crypto/x509/pkix\
crypto/xtea\
debug/dwarf\
debug/macho\
@@ -77,13 +77,14 @@ DIRS=\
encoding/pem\
exec\
exp/datafmt\
- exp/draw\
- exp/draw/x11\
exp/eval\
+ exp/gui\
+ exp/gui/x11\
expvar\
flag\
fmt\
go/ast\
+ go/build\
go/doc\
go/parser\
go/printer\
@@ -106,6 +107,7 @@ DIRS=\
http/spdy\
image\
image/bmp\
+ image/draw\
image/gif\
image/jpeg\
image/png\
@@ -182,8 +184,10 @@ endif
NOTEST+=\
crypto\
crypto/openpgp/error\
+ crypto/x509/pkix\
debug/proc\
- exp/draw/x11\
+ exp/gui\
+ exp/gui/x11\
go/ast\
go/doc\
go/token\
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index e66c34a83..22bdf8d2f 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -816,13 +816,13 @@ func (z *Int) Not(x *Int) *Int {
// Gob codec version. Permits backward-compatible changes to the encoding.
-const version byte = 1
+const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
func (z *Int) GobEncode() ([]byte, os.Error) {
- buf := make([]byte, len(z.abs)*_S+1) // extra byte for version and sign bit
+ buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
i := z.abs.bytes(buf) - 1 // i >= 0
- b := version << 1 // make space for sign bit
+ b := intGobVersion << 1 // make space for sign bit
if z.neg {
b |= 1
}
@@ -837,7 +837,7 @@ func (z *Int) GobDecode(buf []byte) os.Error {
return os.ErrorString("Int.GobDecode: no data")
}
b := buf[0]
- if b>>1 != version {
+ if b>>1 != intGobVersion {
return os.ErrorString(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
}
z.neg = b&1 != 0
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
index 1a492925b..58a55030d 100755
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/big/int_test.go
@@ -1303,6 +1303,7 @@ func TestModInverse(t *testing.T) {
}
+// used by TestIntGobEncoding and TestRatGobEncoding
var gobEncodingTests = []string{
"0",
"1",
@@ -1313,7 +1314,7 @@ var gobEncodingTests = []string{
"298472983472983471903246121093472394872319615612417471234712061",
}
-func TestGobEncoding(t *testing.T) {
+func TestIntGobEncoding(t *testing.T) {
var medium bytes.Buffer
enc := gob.NewEncoder(&medium)
dec := gob.NewDecoder(&medium)
@@ -1321,7 +1322,8 @@ func TestGobEncoding(t *testing.T) {
for j := 0; j < 2; j++ {
medium.Reset() // empty buffer for each test case (in case of failures)
stest := test
- if j == 0 {
+ if j != 0 {
+ // negative numbers
stest = "-" + test
}
var tx Int
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index fa09d6531..734568e06 100755
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -615,6 +615,7 @@ func (x nat) bitLen() int {
// MaxBase is the largest number base accepted for string conversions.
const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
+
func hexValue(ch int) Word {
d := MaxBase + 1 // illegal base
switch {
@@ -733,46 +734,136 @@ const (
uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+ return x.string(lowercaseDigits[0:10])
+}
+
+
// string converts x to a string using digits from a charset; a digit with
// value d is represented by charset[d]. The conversion base is determined
// by len(charset), which must be >= 2.
func (x nat) string(charset string) string {
- base := len(charset)
+ b := Word(len(charset))
// special cases
switch {
- case base < 2:
+ case b < 2 || b > 256:
panic("illegal base")
case len(x) == 0:
return string(charset[0])
}
// allocate buffer for conversion
- i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+ i := x.bitLen()/log2(b) + 1 // +1: round up
s := make([]byte, i)
- // don't destroy x
+ // special case: power of two bases can avoid divisions completely
+ if b == b&-b {
+ // shift is base-b digit size in bits
+ shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
+ mask := Word(1)<<shift - 1
+ w := x[0]
+ nbits := uint(_W) // number of unprocessed bits in w
+
+ // convert less-significant words
+ for k := 1; k < len(x); k++ {
+ // convert full digits
+ for nbits >= shift {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ // convert any partial leading digit and advance to next word
+ if nbits == 0 {
+ // no partial digit remaining, just advance
+ w = x[k]
+ nbits = _W
+ } else {
+ // partial digit in current (k-1) and next (k) word
+ w |= x[k] << nbits
+ i--
+ s[i] = charset[w&mask]
+
+ // advance
+ w = x[k] >> (shift - nbits)
+ nbits = _W - (shift - nbits)
+ }
+ }
+
+ // convert digits of most-significant word (omit leading zeros)
+ for nbits >= 0 && w != 0 {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ return string(s[i:])
+ }
+
+ // general case: extract groups of digits by multiprecision division
+
+ // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits
+ bb := Word(1)
+ ndigits := 0
+ for max := Word(_M / b); bb <= max; bb *= b {
+ ndigits++
+ }
+
+ // preserve x, create local copy for use in repeated divisions
q := nat(nil).set(x)
+ var r Word
// convert
- for len(q) > 0 {
- i--
- var r Word
- q, r = q.divW(q, Word(base))
- s[i] = charset[r]
+ if b == 10 { // hard-coding for 10 here speeds this up by 1.25x
+ for len(q) > 0 {
+ // extract least significant, base bb "digit"
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ }
+ }
+ } else {
+ for len(q) > 0 {
+ // extract least significant group of digits
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ }
+ }
}
return string(s[i:])
}
-// decimalString returns a decimal representation of x.
-// It calls x.string with the charset "0123456789".
-func (x nat) decimalString() string {
- return x.string(lowercaseDigits[0:10])
-}
-
-
const deBruijn32 = 0x077CB531
var deBruijn32Lookup = []byte{
@@ -789,6 +880,7 @@ var deBruijn64Lookup = []byte{
54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
}
+
// trailingZeroBits returns the number of consecutive zero bits on the right
// side of the given Word.
// See Knuth, volume 4, section 7.3.1
@@ -960,7 +1052,9 @@ func (z nat) xor(x, y nat) nat {
// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
-func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
+func greaterThan(x1, x2, y1, y2 Word) bool {
+ return x1 > y1 || x1 == y1 && x2 > y2
+}
// modW returns x % d.
diff --git a/src/pkg/big/nat_test.go b/src/pkg/big/nat_test.go
index 50ea469be..fd93592dd 100755
--- a/src/pkg/big/nat_test.go
+++ b/src/pkg/big/nat_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "fmt"
"os"
"strings"
"testing"
@@ -171,6 +172,36 @@ func BenchmarkMul(b *testing.B) {
}
+func toString(x nat, charset string) string {
+ base := len(charset)
+
+ // special cases
+ switch {
+ case base < 2:
+ panic("illegal base")
+ case len(x) == 0:
+ return string(charset[0])
+ }
+
+ // allocate buffer for conversion
+ i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+ s := make([]byte, i)
+
+ // don't destroy x
+ q := nat(nil).set(x)
+
+ // convert
+ for len(q) > 0 {
+ i--
+ var r Word
+ q, r = q.divW(q, Word(base))
+ s[i] = charset[r]
+ }
+
+ return string(s[i:])
+}
+
+
var strTests = []struct {
x nat // nat value to be converted
c string // conversion charset
@@ -360,6 +391,187 @@ func BenchmarkScanPi(b *testing.B) {
}
+const (
+ // 314**271
+ // base 2: 2249 digits
+ // base 8: 751 digits
+ // base 10: 678 digits
+ // base 16: 563 digits
+ shortBase = 314
+ shortExponent = 271
+
+ // 3141**2178
+ // base 2: 31577 digits
+ // base 8: 10527 digits
+ // base 10: 9507 digits
+ // base 16: 7895 digits
+ mediumBase = 3141
+ mediumExponent = 2718
+
+ // 3141**2178
+ // base 2: 406078 digits
+ // base 8: 135360 digits
+ // base 10: 122243 digits
+ // base 16: 101521 digits
+ longBase = 31415
+ longExponent = 27182
+)
+
+
+func BenchmarkScanShort2(b *testing.B) {
+ ScanHelper(b, 2, shortBase, shortExponent)
+}
+
+
+func BenchmarkScanShort8(b *testing.B) {
+ ScanHelper(b, 8, shortBase, shortExponent)
+}
+
+
+func BenchmarkScanSort10(b *testing.B) {
+ ScanHelper(b, 10, shortBase, shortExponent)
+}
+
+
+func BenchmarkScanShort16(b *testing.B) {
+ ScanHelper(b, 16, shortBase, shortExponent)
+}
+
+
+func BenchmarkScanMedium2(b *testing.B) {
+ ScanHelper(b, 2, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkScanMedium8(b *testing.B) {
+ ScanHelper(b, 8, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkScanMedium10(b *testing.B) {
+ ScanHelper(b, 10, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkScanMedium16(b *testing.B) {
+ ScanHelper(b, 16, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkScanLong2(b *testing.B) {
+ ScanHelper(b, 2, longBase, longExponent)
+}
+
+
+func BenchmarkScanLong8(b *testing.B) {
+ ScanHelper(b, 8, longBase, longExponent)
+}
+
+
+func BenchmarkScanLong10(b *testing.B) {
+ ScanHelper(b, 10, longBase, longExponent)
+}
+
+
+func BenchmarkScanLong16(b *testing.B) {
+ ScanHelper(b, 16, longBase, longExponent)
+}
+
+
+func ScanHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+
+ var s string
+ s = z.string(lowercaseDigits[0:base])
+ if t := toString(z, lowercaseDigits[0:base]); t != s {
+ panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ x.scan(strings.NewReader(s), base)
+ }
+}
+
+
+func BenchmarkStringShort2(b *testing.B) {
+ StringHelper(b, 2, shortBase, shortExponent)
+}
+
+
+func BenchmarkStringShort8(b *testing.B) {
+ StringHelper(b, 8, shortBase, shortExponent)
+}
+
+
+func BenchmarkStringShort10(b *testing.B) {
+ StringHelper(b, 10, shortBase, shortExponent)
+}
+
+
+func BenchmarkStringShort16(b *testing.B) {
+ StringHelper(b, 16, shortBase, shortExponent)
+}
+
+
+func BenchmarkStringMedium2(b *testing.B) {
+ StringHelper(b, 2, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkStringMedium8(b *testing.B) {
+ StringHelper(b, 8, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkStringMedium10(b *testing.B) {
+ StringHelper(b, 10, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkStringMedium16(b *testing.B) {
+ StringHelper(b, 16, mediumBase, mediumExponent)
+}
+
+
+func BenchmarkStringLong2(b *testing.B) {
+ StringHelper(b, 2, longBase, longExponent)
+}
+
+
+func BenchmarkStringLong8(b *testing.B) {
+ StringHelper(b, 8, longBase, longExponent)
+}
+
+
+func BenchmarkStringLong10(b *testing.B) {
+ StringHelper(b, 10, longBase, longExponent)
+}
+
+
+func BenchmarkStringLong16(b *testing.B) {
+ StringHelper(b, 16, longBase, longExponent)
+}
+
+
+func StringHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ z.string(lowercaseDigits[0:base])
+ }
+}
+
+
func TestLeadingZeros(t *testing.T) {
var x Word = _B >> 1
for i := 0; i <= _W; i++ {
@@ -479,7 +691,6 @@ func TestTrailingZeroBits(t *testing.T) {
}
}
-
var expNNTests = []struct {
x, y, m string
out string
diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go
index f11c27425..1fbf8c459 100644
--- a/src/pkg/big/rat.go
+++ b/src/pkg/big/rat.go
@@ -7,6 +7,7 @@
package big
import (
+ "encoding/binary"
"fmt"
"os"
"strings"
@@ -314,7 +315,11 @@ func (z *Rat) RatString() string {
// digits of precision after the decimal point and the last digit rounded.
func (z *Rat) FloatString(prec int) string {
if z.IsInt() {
- return z.a.String()
+ s := z.a.String()
+ if prec > 0 {
+ s += "." + strings.Repeat("0", prec)
+ }
+ return s
}
q, r := nat{}.div(nat{}, z.a.abs, z.b)
@@ -350,3 +355,45 @@ func (z *Rat) FloatString(prec int) string {
return s
}
+
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Rat) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+ i := z.b.bytes(buf)
+ j := z.a.abs.bytes(buf[0:i])
+ n := i - j
+ if int(uint32(n)) != n {
+ // this should never happen
+ return nil, os.ErrorString("Rat.GobEncode: numerator too large")
+ }
+ binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+ j -= 1 + 4
+ b := ratGobVersion << 1 // make space for sign bit
+ if z.a.neg {
+ b |= 1
+ }
+ buf[j] = b
+ return buf[j:], nil
+}
+
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.ErrorString("Rat.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != ratGobVersion {
+ return os.ErrorString(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+ }
+ const j = 1 + 4
+ i := j + binary.BigEndian.Uint32(buf[j-4:j])
+ z.a.neg = b&1 != 0
+ z.a.abs = z.a.abs.setBytes(buf[j:i])
+ z.b = z.b.setBytes(buf[i:])
+ return nil
+}
diff --git a/src/pkg/big/rat_test.go b/src/pkg/big/rat_test.go
index ae5c7c993..e64505ea3 100644
--- a/src/pkg/big/rat_test.go
+++ b/src/pkg/big/rat_test.go
@@ -7,6 +7,7 @@ package big
import (
"bytes"
"fmt"
+ "gob"
"testing"
)
@@ -86,12 +87,13 @@ var floatStringTests = []struct {
out string
}{
{"0", 0, "0"},
- {"0", 4, "0"},
+ {"0", 4, "0.0000"},
{"1", 0, "1"},
- {"1", 2, "1"},
+ {"1", 2, "1.00"},
{"-1", 0, "-1"},
{".25", 2, "0.25"},
{".25", 1, "0.3"},
+ {".25", 3, "0.250"},
{"-1/3", 3, "-0.333"},
{"-2/3", 4, "-0.6667"},
{"0.96", 1, "1.0"},
@@ -307,3 +309,36 @@ func TestRatSetFrac64Rat(t *testing.T) {
}
}
}
+
+
+func TestRatGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 4; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j&1 != 0 {
+ // negative numbers
+ stest = "-" + test
+ }
+ if j%2 != 0 {
+ // fractions
+ stest = stest + "." + test
+ }
+ var tx Rat
+ tx.SetString(stest)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Rat
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index a1cd2abc0..21231c8e5 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -32,13 +32,49 @@ const (
MSB
)
+const (
+ maxWidth = 12
+ decoderInvalidCode = 0xffff
+ flushBuffer = 1 << maxWidth
+)
+
// decoder is the state from which the readXxx method converts a byte
// stream into a code stream.
type decoder struct {
- r io.ByteReader
- bits uint32
- nBits uint
- width uint
+ r io.ByteReader
+ bits uint32
+ nBits uint
+ width uint
+ read func(*decoder) (uint16, os.Error) // readLSB or readMSB
+ litWidth int // width in bits of literal codes
+ err os.Error
+
+ // The first 1<<litWidth codes are literal codes.
+ // The next two codes mean clear and EOF.
+ // Other valid codes are in the range [lo, hi] where lo := clear + 2,
+ // with the upper bound incrementing on each code seen.
+ // overflow is the code at which hi overflows the code width.
+ // last is the most recently seen code, or decoderInvalidCode.
+ clear, eof, hi, overflow, last uint16
+
+ // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
+ // suffix[c] is the last of these bytes.
+ // prefix[c] is the code for all but the last byte.
+ // This code can either be a literal code or another code in [lo, c).
+ // The c == hi case is a special case.
+ suffix [1 << maxWidth]uint8
+ prefix [1 << maxWidth]uint16
+
+ // output is the temporary output buffer.
+ // Literal codes are accumulated from the start of the buffer.
+ // Non-literal codes decode to a sequence of suffixes that are first
+ // written right-to-left from the end of the buffer before being copied
+ // to the start of the buffer.
+ // It is flushed when it contains >= 1<<maxWidth bytes,
+ // so that there is always room to decode an entire code.
+ output [2 * 1 << maxWidth]byte
+ o int // write index into output
+ toRead []byte // bytes to return from Read
}
// readLSB returns the next code for "Least Significant Bits first" data.
@@ -73,119 +109,113 @@ func (d *decoder) readMSB() (uint16, os.Error) {
return code, nil
}
-// decode decompresses bytes from r and writes them to pw.
-// read specifies how to decode bytes into codes.
-// litWidth is the width in bits of literal codes.
-func decode(r io.Reader, read func(*decoder) (uint16, os.Error), litWidth int, pw *io.PipeWriter) {
- br, ok := r.(io.ByteReader)
- if !ok {
- br = bufio.NewReader(r)
+func (d *decoder) Read(b []byte) (int, os.Error) {
+ for {
+ if len(d.toRead) > 0 {
+ n := copy(b, d.toRead)
+ d.toRead = d.toRead[n:]
+ return n, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+ d.decode()
}
- pw.CloseWithError(decode1(pw, br, read, uint(litWidth)))
+ panic("unreachable")
}
-func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os.Error), litWidth uint) os.Error {
- const (
- maxWidth = 12
- invalidCode = 0xffff
- )
- d := decoder{r, 0, 0, 1 + litWidth}
- w := bufio.NewWriter(pw)
- // The first 1<<litWidth codes are literal codes.
- // The next two codes mean clear and EOF.
- // Other valid codes are in the range [lo, hi] where lo := clear + 2,
- // with the upper bound incrementing on each code seen.
- clear := uint16(1) << litWidth
- eof, hi := clear+1, clear+1
- // overflow is the code at which hi overflows the code width.
- overflow := uint16(1) << d.width
- var (
- // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
- // suffix[c] is the last of these bytes.
- // prefix[c] is the code for all but the last byte.
- // This code can either be a literal code or another code in [lo, c).
- // The c == hi case is a special case.
- suffix [1 << maxWidth]uint8
- prefix [1 << maxWidth]uint16
- // buf is a scratch buffer for reconstituting the bytes that a code expands to.
- // Code suffixes are written right-to-left from the end of the buffer.
- buf [1 << maxWidth]byte
- )
-
+// decode decompresses bytes from r and leaves them in d.toRead.
+// read specifies how to decode bytes into codes.
+// litWidth is the width in bits of literal codes.
+func (d *decoder) decode() {
// Loop over the code stream, converting codes into decompressed bytes.
- last := uint16(invalidCode)
for {
- code, err := read(&d)
+ code, err := d.read(d)
if err != nil {
if err == os.EOF {
err = io.ErrUnexpectedEOF
}
- return err
+ d.err = err
+ return
}
switch {
- case code < clear:
+ case code < d.clear:
// We have a literal code.
- if err := w.WriteByte(uint8(code)); err != nil {
- return err
- }
- if last != invalidCode {
+ d.output[d.o] = uint8(code)
+ d.o++
+ if d.last != decoderInvalidCode {
// Save what the hi code expands to.
- suffix[hi] = uint8(code)
- prefix[hi] = last
+ d.suffix[d.hi] = uint8(code)
+ d.prefix[d.hi] = d.last
}
- case code == clear:
- d.width = 1 + litWidth
- hi = eof
- overflow = 1 << d.width
- last = invalidCode
+ case code == d.clear:
+ d.width = 1 + uint(d.litWidth)
+ d.hi = d.eof
+ d.overflow = 1 << d.width
+ d.last = decoderInvalidCode
continue
- case code == eof:
- return w.Flush()
- case code <= hi:
- c, i := code, len(buf)-1
- if code == hi {
+ case code == d.eof:
+ d.flush()
+ d.err = os.EOF
+ return
+ case code <= d.hi:
+ c, i := code, len(d.output)-1
+ if code == d.hi {
// code == hi is a special case which expands to the last expansion
// followed by the head of the last expansion. To find the head, we walk
// the prefix chain until we find a literal code.
- c = last
- for c >= clear {
- c = prefix[c]
+ c = d.last
+ for c >= d.clear {
+ c = d.prefix[c]
}
- buf[i] = uint8(c)
+ d.output[i] = uint8(c)
i--
- c = last
+ c = d.last
}
- // Copy the suffix chain into buf and then write that to w.
- for c >= clear {
- buf[i] = suffix[c]
+ // Copy the suffix chain into output and then write that to w.
+ for c >= d.clear {
+ d.output[i] = d.suffix[c]
i--
- c = prefix[c]
+ c = d.prefix[c]
}
- buf[i] = uint8(c)
- if _, err := w.Write(buf[i:]); err != nil {
- return err
- }
- if last != invalidCode {
+ d.output[i] = uint8(c)
+ d.o += copy(d.output[d.o:], d.output[i:])
+ if d.last != decoderInvalidCode {
// Save what the hi code expands to.
- suffix[hi] = uint8(c)
- prefix[hi] = last
+ d.suffix[d.hi] = uint8(c)
+ d.prefix[d.hi] = d.last
}
default:
- return os.NewError("lzw: invalid code")
+ d.err = os.NewError("lzw: invalid code")
+ return
}
- last, hi = code, hi+1
- if hi >= overflow {
+ d.last, d.hi = code, d.hi+1
+ if d.hi >= d.overflow {
if d.width == maxWidth {
- last = invalidCode
- continue
+ d.last = decoderInvalidCode
+ } else {
+ d.width++
+ d.overflow <<= 1
}
- d.width++
- overflow <<= 1
+ }
+ if d.o >= flushBuffer {
+ d.flush()
+ return
}
}
panic("unreachable")
}
+func (d *decoder) flush() {
+ d.toRead = d.output[:d.o]
+ d.o = 0
+}
+
+func (d *decoder) Close() os.Error {
+ d.err = os.EINVAL // in case any Reads come along
+ return nil
+}
+
// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
// the data read from r.
// It is the caller's responsibility to call Close on the ReadCloser when
@@ -193,21 +223,31 @@ func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os
// The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8.
func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
- pr, pw := io.Pipe()
- var read func(*decoder) (uint16, os.Error)
+ d := new(decoder)
switch order {
case LSB:
- read = (*decoder).readLSB
+ d.read = (*decoder).readLSB
case MSB:
- read = (*decoder).readMSB
+ d.read = (*decoder).readMSB
default:
- pw.CloseWithError(os.NewError("lzw: unknown order"))
- return pr
+ d.err = os.NewError("lzw: unknown order")
+ return d
}
if litWidth < 2 || 8 < litWidth {
- pw.CloseWithError(fmt.Errorf("lzw: litWidth %d out of range", litWidth))
- return pr
+ d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
+ return d
}
- go decode(r, read, litWidth, pw)
- return pr
+ if br, ok := r.(io.ByteReader); ok {
+ d.r = br
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+ d.litWidth = litWidth
+ d.width = 1 + uint(litWidth)
+ d.clear = uint16(1) << uint(litWidth)
+ d.eof, d.hi = d.clear+1, d.clear+1
+ d.overflow = uint16(1) << d.width
+ d.last = decoderInvalidCode
+
+ return d
}
diff --git a/src/pkg/compress/lzw/writer_test.go b/src/pkg/compress/lzw/writer_test.go
index 82464ecd1..4c5e522f9 100644
--- a/src/pkg/compress/lzw/writer_test.go
+++ b/src/pkg/compress/lzw/writer_test.go
@@ -77,13 +77,13 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
return
}
- if len(b0) != len(b1) {
- t.Errorf("%s (order=%d litWidth=%d): length mismatch %d versus %d", fn, order, litWidth, len(b0), len(b1))
+ if len(b1) != len(b0) {
+ t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0))
return
}
for i := 0; i < len(b0); i++ {
- if b0[i] != b1[i] {
- t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, order, litWidth, i, b0[i], b1[i])
+ if b1[i] != b0[i] {
+ t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i])
return
}
}
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
index acd75b8b0..57dbe7d2d 100644
--- a/src/pkg/crypto/ocsp/ocsp.go
+++ b/src/pkg/crypto/ocsp/ocsp.go
@@ -13,6 +13,7 @@ import (
"crypto/rsa"
_ "crypto/sha1"
"crypto/x509"
+ "crypto/x509/pkix"
"os"
"time"
)
@@ -32,21 +33,9 @@ const (
ocspUnauthorized = 5
)
-type rdnSequence []relativeDistinguishedNameSET
-
-type relativeDistinguishedNameSET []attributeTypeAndValue
-
-type attributeTypeAndValue struct {
- Type asn1.ObjectIdentifier
- Value interface{}
-}
-
-type algorithmIdentifier struct {
- Algorithm asn1.ObjectIdentifier
-}
type certID struct {
- HashAlgorithm algorithmIdentifier
+ HashAlgorithm pkix.AlgorithmIdentifier
NameHash []byte
IssuerKeyHash []byte
SerialNumber asn1.RawValue
@@ -64,16 +53,16 @@ type responseBytes struct {
type basicResponse struct {
TBSResponseData responseData
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.AlgorithmIdentifier
Signature asn1.BitString
Certificates []asn1.RawValue "explicit,tag:0,optional"
}
type responseData struct {
Raw asn1.RawContent
- Version int "optional,default:1,explicit,tag:0"
- RequestorName rdnSequence "optional,explicit,tag:1"
- KeyHash []byte "optional,explicit,tag:2"
+ Version int "optional,default:1,explicit,tag:0"
+ RequestorName pkix.RDNSequence "optional,explicit,tag:1"
+ KeyHash []byte "optional,explicit,tag:2"
ProducedAt *time.Time
Responses []singleResponse
}
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index 6bfe6c4e5..380f71570 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -64,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error {
// easy for an attack to generate composites that pass this test.
for _, prime := range priv.Primes {
if !big.ProbablyPrime(prime, 20) {
- return os.ErrorString("Prime factor is composite")
+ return os.ErrorString("prime factor is composite")
}
}
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 7d0bb9f34..9e5c9270a 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -159,7 +159,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
if err != nil {
- err = os.ErrorString("crypto/tls: failed to parse key")
+ err = os.ErrorString("crypto/tls: failed to parse key: " + err.String())
return
}
diff --git a/src/pkg/crypto/twofish/twofish.go b/src/pkg/crypto/twofish/twofish.go
index 9303f03ff..1a1aac9b9 100644
--- a/src/pkg/crypto/twofish/twofish.go
+++ b/src/pkg/crypto/twofish/twofish.go
@@ -116,7 +116,7 @@ func (c *Cipher) Reset() {
c.k[i] = 0
}
for i := range c.s {
- for j := 0; j < 265; j++ {
+ for j := 0; j < 256; j++ {
c.s[i][j] = 0
}
}
diff --git a/src/pkg/crypto/x509/cert_pool.go b/src/pkg/crypto/x509/cert_pool.go
index c295fd97e..16cd92efc 100644
--- a/src/pkg/crypto/x509/cert_pool.go
+++ b/src/pkg/crypto/x509/cert_pool.go
@@ -5,6 +5,7 @@
package x509
import (
+ "crypto/x509/pkix"
"encoding/pem"
"strings"
)
@@ -25,7 +26,7 @@ func NewCertPool() *CertPool {
}
}
-func nameToKey(name *Name) string {
+func nameToKey(name *pkix.Name) string {
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
diff --git a/src/pkg/crypto/x509/crl/crl.go b/src/pkg/crypto/x509/crl/crl.go
deleted file mode 100644
index c79c797c7..000000000
--- a/src/pkg/crypto/x509/crl/crl.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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 crl exposes low-level details of PKIX Certificate Revocation Lists
-// as specified in RFC 5280, section 5.
-package crl
-
-import (
- "asn1"
- "bytes"
- "encoding/pem"
- "os"
- "time"
-)
-
-// CertificateList represents the ASN.1 structure of the same name. See RFC
-// 5280, section 5.1. Use crypto/x509/Certificate.CheckCRLSignature to verify
-// the signature.
-type CertificateList struct {
- TBSCertList TBSCertificateList
- SignatureAlgorithm AlgorithmIdentifier
- SignatureValue asn1.BitString
-}
-
-// HasExpired returns true iff currentTimeSeconds is past the expiry time of
-// certList.
-func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
- return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
-}
-
-// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
-// 5280, section 5.1.
-type TBSCertificateList struct {
- Raw asn1.RawContent
- Version int "optional,default:2"
- Signature AlgorithmIdentifier
- Issuer asn1.RawValue
- ThisUpdate *time.Time
- NextUpdate *time.Time
- RevokedCertificates []RevokedCertificate "optional"
- Extensions []Extension "tag:0,optional,explicit"
-}
-
-// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
-// 5280, section 4.1.1.2.
-type AlgorithmIdentifier struct {
- Algo asn1.ObjectIdentifier
- Params asn1.RawValue "optional"
-}
-
-// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
-// 5280, section 5.1.
-type RevokedCertificate struct {
- SerialNumber asn1.RawValue
- RevocationTime *time.Time
- Extensions []Extension "optional"
-}
-
-// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
-// 5280, section 4.2.
-type Extension struct {
- Id asn1.ObjectIdentifier
- IsCritial bool "optional"
- Value []byte
-}
-
-// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
-// CRL.
-var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
-// pemType is the type of a PEM encoded CRL.
-var pemType = "X509 CRL"
-
-// Parse parses a CRL from the given bytes. It's often the case that PEM
-// encoded CRLs will appear where they should be DER encoded, so this function
-// will transparently handle PEM encoding as long as there isn't any leading
-// garbage.
-func Parse(crlBytes []byte) (certList *CertificateList, err os.Error) {
- if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
- block, _ := pem.Decode(crlBytes)
- if block != nil && block.Type == pemType {
- crlBytes = block.Bytes
- }
- }
- return ParseDER(crlBytes)
-}
-
-// ParseDER parses a DER encoded CRL from the given bytes.
-func ParseDER(derBytes []byte) (certList *CertificateList, err os.Error) {
- certList = new(CertificateList)
- _, err = asn1.Unmarshal(derBytes, certList)
- if err != nil {
- certList = nil
- }
- return
-}
diff --git a/src/pkg/crypto/x509/crl/crl_test.go b/src/pkg/crypto/x509/crl/crl_test.go
deleted file mode 100644
index 62d8dc195..000000000
--- a/src/pkg/crypto/x509/crl/crl_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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 crl
-
-import (
- "encoding/base64"
- "testing"
-)
-
-func fromBase64(in string) []byte {
- out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
- _, err := base64.StdEncoding.Decode(out, []byte(in))
- if err != nil {
- panic("failed to base64 decode")
- }
- return out
-}
-
-func TestParseDER(t *testing.T) {
- derBytes := fromBase64(derCRLBase64)
- certList, err := ParseDER(derBytes)
- if err != nil {
- t.Errorf("error parsing: %s", err)
- return
- }
- numCerts := len(certList.TBSCertList.RevokedCertificates)
- expected := 88
- if numCerts != expected {
- t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
- }
-
- if certList.HasExpired(1302517272) {
- t.Errorf("CRL has expired (but shouldn't have)")
- }
-
- // Can't check the signature here without a package cycle.
-}
-
-func TestParsePEM(t *testing.T) {
- pemBytes := fromBase64(pemCRLBase64)
- certList, err := Parse(pemBytes)
- if err != nil {
- t.Errorf("error parsing: %s", err)
- return
- }
- numCerts := len(certList.TBSCertList.RevokedCertificates)
- expected := 2
- if numCerts != expected {
- t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
- }
-
- if certList.HasExpired(1302517272) {
- t.Errorf("CRL has expired (but shouldn't have)")
- }
-
- // Can't check the signature here without a package cycle.
-}
-
-const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
-
-const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
diff --git a/src/pkg/crypto/x509/crl/Makefile b/src/pkg/crypto/x509/pkix/Makefile
index d780af38e..e29b74c01 100644
--- a/src/pkg/crypto/x509/crl/Makefile
+++ b/src/pkg/crypto/x509/pkix/Makefile
@@ -4,8 +4,8 @@
include ../../../../Make.inc
-TARG=crypto/x509/crl
+TARG=crypto/x509/pkix
GOFILES=\
- crl.go\
+ pkix.go\
include ../../../../Make.pkg
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
new file mode 100644
index 000000000..7806b2a2e
--- /dev/null
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -0,0 +1,167 @@
+// 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 pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+ "asn1"
+ "big"
+ "time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue "optional"
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool "optional"
+ Value []byte
+}
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Additional elements in the name are ignored.
+type Name struct {
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
+}
+
+func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+ atv := rdn[0]
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
+ }
+ }
+}
+
+var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ oidSerialNumber = []int{2, 5, 4, 5}
+ oidLocality = []int{2, 5, 4, 7}
+ oidProvince = []int{2, 5, 4, 8}
+ oidStreetAddress = []int{2, 5, 4, 9}
+ oidPostalCode = []int{2, 5, 4, 17}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+ if len(values) == 0 {
+ return in
+ }
+
+ s := make([]AttributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
+ }
+
+ return append(in, s)
+}
+
+func (n Name) ToRDNSequence() (ret RDNSequence) {
+ ret = appendRDNs(ret, n.Country, oidCountry)
+ ret = appendRDNs(ret, n.Organization, oidOrganization)
+ ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ ret = appendRDNs(ret, n.Locality, oidLocality)
+ ret = appendRDNs(ret, n.Province, oidProvince)
+ ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+ if len(n.CommonName) > 0 {
+ ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+ }
+ if len(n.SerialNumber) > 0 {
+ ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+ }
+
+ return ret
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+type CertificateList struct {
+ TBSCertList TBSCertificateList
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// HasExpired returns true iff currentTimeSeconds is past the expiry time of
+// certList.
+func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
+ return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type TBSCertificateList struct {
+ Raw asn1.RawContent
+ Version int "optional,default:2"
+ Signature AlgorithmIdentifier
+ Issuer RDNSequence
+ ThisUpdate *time.Time
+ NextUpdate *time.Time
+ RevokedCertificates []RevokedCertificate "optional"
+ Extensions []Extension "tag:0,optional,explicit"
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+ SerialNumber *big.Int
+ RevocationTime *time.Time
+ Extensions []Extension "optional"
+}
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 6ae1f8e39..b10ffb0a2 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -14,7 +14,8 @@ import (
"crypto/dsa"
"crypto/rsa"
"crypto/sha1"
- "crypto/x509/crl"
+ "crypto/x509/pkix"
+ "encoding/pem"
"io"
"os"
"time"
@@ -23,30 +24,25 @@ import (
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
type pkcs1PrivateKey struct {
Version int
- N asn1.RawValue
+ N *big.Int
E int
- D asn1.RawValue
- P asn1.RawValue
- Q asn1.RawValue
+ D *big.Int
+ P *big.Int
+ Q *big.Int
// We ignore these values, if present, because rsa will calculate them.
- Dp asn1.RawValue "optional"
- Dq asn1.RawValue "optional"
- Qinv asn1.RawValue "optional"
+ Dp *big.Int "optional"
+ Dq *big.Int "optional"
+ Qinv *big.Int "optional"
AdditionalPrimes []pkcs1AdditionalRSAPrime "optional"
}
type pkcs1AdditionalRSAPrime struct {
- Prime asn1.RawValue
+ Prime *big.Int
// We ignore these values because rsa will calculate them.
- Exp asn1.RawValue
- Coeff asn1.RawValue
-}
-
-// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type.
-func rawValueIsInteger(raw *asn1.RawValue) bool {
- return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false
+ Exp *big.Int
+ Coeff *big.Int
}
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
@@ -65,29 +61,25 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return nil, os.ErrorString("x509: unsupported private key version")
}
- if !rawValueIsInteger(&priv.N) ||
- !rawValueIsInteger(&priv.D) ||
- !rawValueIsInteger(&priv.P) ||
- !rawValueIsInteger(&priv.Q) {
- err = asn1.StructuralError{"tags don't match"}
- return
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, os.ErrorString("private key contains zero or negative value")
}
key = new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
- N: new(big.Int).SetBytes(priv.N.Bytes),
+ N: priv.N,
}
- key.D = new(big.Int).SetBytes(priv.D.Bytes)
+ key.D = priv.D
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
- key.Primes[0] = new(big.Int).SetBytes(priv.P.Bytes)
- key.Primes[1] = new(big.Int).SetBytes(priv.Q.Bytes)
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
for i, a := range priv.AdditionalPrimes {
- if !rawValueIsInteger(&a.Prime) {
- return nil, asn1.StructuralError{"tags don't match"}
+ if a.Prime.Sign() <= 0 {
+ return nil, os.ErrorString("private key contains zero or negative prime")
}
- key.Primes[i+2] = new(big.Int).SetBytes(a.Prime.Bytes)
+ key.Primes[i+2] = a.Prime
// We ignore the other two values because rsa will calculate
// them as needed.
}
@@ -101,19 +93,6 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return
}
-// rawValueForBig returns an asn1.RawValue which represents the given integer.
-func rawValueForBig(n *big.Int) asn1.RawValue {
- b := n.Bytes()
- if n.Sign() >= 0 && len(b) > 0 && b[0]&0x80 != 0 {
- // This positive number would be interpreted as a negative
- // number in ASN.1 because the MSB is set.
- padded := make([]byte, len(b)+1)
- copy(padded[1:], b)
- b = padded
- }
- return asn1.RawValue{Tag: 2, Bytes: b}
-}
-
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
key.Precompute()
@@ -125,21 +104,21 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
priv := pkcs1PrivateKey{
Version: version,
- N: rawValueForBig(key.N),
+ N: key.N,
E: key.PublicKey.E,
- D: rawValueForBig(key.D),
- P: rawValueForBig(key.Primes[0]),
- Q: rawValueForBig(key.Primes[1]),
- Dp: rawValueForBig(key.Precomputed.Dp),
- Dq: rawValueForBig(key.Precomputed.Dq),
- Qinv: rawValueForBig(key.Precomputed.Qinv),
+ D: key.D,
+ P: key.Primes[0],
+ Q: key.Primes[1],
+ Dp: key.Precomputed.Dp,
+ Dq: key.Precomputed.Dq,
+ Qinv: key.Precomputed.Qinv,
}
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
for i, values := range key.Precomputed.CRTValues {
- priv.AdditionalPrimes[i].Prime = rawValueForBig(key.Primes[2+i])
- priv.AdditionalPrimes[i].Exp = rawValueForBig(values.Exp)
- priv.AdditionalPrimes[i].Coeff = rawValueForBig(values.Coeff)
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
}
b, _ := asn1.Marshal(priv)
@@ -151,44 +130,30 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int "optional,explicit,default:1,tag:0"
- SerialNumber asn1.RawValue
- SignatureAlgorithm algorithmIdentifier
- Issuer rdnSequence
+ SerialNumber *big.Int
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Issuer pkix.RDNSequence
Validity validity
- Subject rdnSequence
+ Subject pkix.RDNSequence
PublicKey publicKeyInfo
- UniqueId asn1.BitString "optional,tag:1"
- SubjectUniqueId asn1.BitString "optional,tag:2"
- Extensions []extension "optional,explicit,tag:3"
+ UniqueId asn1.BitString "optional,tag:1"
+ SubjectUniqueId asn1.BitString "optional,tag:2"
+ Extensions []pkix.Extension "optional,explicit,tag:3"
}
type dsaAlgorithmParameters struct {
- P, Q, G asn1.RawValue
+ P, Q, G *big.Int
}
type dsaSignature struct {
- R, S asn1.RawValue
-}
-
-type algorithmIdentifier struct {
- Algorithm asn1.ObjectIdentifier
- Parameters asn1.RawValue "optional"
-}
-
-type rdnSequence []relativeDistinguishedNameSET
-
-type relativeDistinguishedNameSET []attributeTypeAndValue
-
-type attributeTypeAndValue struct {
- Type asn1.ObjectIdentifier
- Value interface{}
+ R, S *big.Int
}
type validity struct {
@@ -197,16 +162,10 @@ type validity struct {
type publicKeyInfo struct {
Raw asn1.RawContent
- Algorithm algorithmIdentifier
+ Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
-type extension struct {
- Id asn1.ObjectIdentifier
- Critical bool "optional"
- Value []byte
-}
-
// RFC 5280, 4.2.1.1
type authKeyId struct {
Id []byte "optional,tag:0"
@@ -234,100 +193,6 @@ const (
DSA
)
-// Name represents an X.509 distinguished name. This only includes the common
-// elements of a DN. Additional elements in the name are ignored.
-type Name struct {
- Country, Organization, OrganizationalUnit []string
- Locality, Province []string
- StreetAddress, PostalCode []string
- SerialNumber, CommonName string
-}
-
-func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
- for _, rdn := range *rdns {
- if len(rdn) == 0 {
- continue
- }
- atv := rdn[0]
- value, ok := atv.Value.(string)
- if !ok {
- continue
- }
-
- t := atv.Type
- if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
- switch t[3] {
- case 3:
- n.CommonName = value
- case 5:
- n.SerialNumber = value
- case 6:
- n.Country = append(n.Country, value)
- case 7:
- n.Locality = append(n.Locality, value)
- case 8:
- n.Province = append(n.Province, value)
- case 9:
- n.StreetAddress = append(n.StreetAddress, value)
- case 10:
- n.Organization = append(n.Organization, value)
- case 11:
- n.OrganizationalUnit = append(n.OrganizationalUnit, value)
- case 17:
- n.PostalCode = append(n.PostalCode, value)
- }
- }
- }
-}
-
-var (
- oidCountry = []int{2, 5, 4, 6}
- oidOrganization = []int{2, 5, 4, 10}
- oidOrganizationalUnit = []int{2, 5, 4, 11}
- oidCommonName = []int{2, 5, 4, 3}
- oidSerialNumber = []int{2, 5, 4, 5}
- oidLocality = []int{2, 5, 4, 7}
- oidProvince = []int{2, 5, 4, 8}
- oidStreetAddress = []int{2, 5, 4, 9}
- oidPostalCode = []int{2, 5, 4, 17}
-)
-
-// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
-// and returns the new value. The relativeDistinguishedNameSET contains an
-// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
-// search for AttributeTypeAndValue.
-func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
- if len(values) == 0 {
- return in
- }
-
- s := make([]attributeTypeAndValue, len(values))
- for i, value := range values {
- s[i].Type = oid
- s[i].Value = value
- }
-
- return append(in, s)
-}
-
-func (n Name) toRDNSequence() (ret rdnSequence) {
- ret = appendRDNs(ret, n.Country, oidCountry)
- ret = appendRDNs(ret, n.Organization, oidOrganization)
- ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
- ret = appendRDNs(ret, n.Locality, oidLocality)
- ret = appendRDNs(ret, n.Province, oidProvince)
- ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
- ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
- if len(n.CommonName) > 0 {
- ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
- }
- if len(n.SerialNumber) > 0 {
- ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
- }
-
- return ret
-}
-
// OIDs for signature algorithms
//
// pkcs-1 OBJECT IDENTIFIER ::= {
@@ -483,9 +348,9 @@ type Certificate struct {
PublicKey interface{}
Version int
- SerialNumber []byte
- Issuer Name
- Subject Name
+ SerialNumber *big.Int
+ Issuer pkix.Name
+ Subject pkix.Name
NotBefore, NotAfter *time.Time // Validity bounds.
KeyUsage KeyUsage
@@ -591,12 +456,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
return err
}
- if !rawValueIsInteger(&dsaSig.R) || !rawValueIsInteger(&dsaSig.S) {
- return asn1.StructuralError{"tags don't match"}
+ if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
+ return os.ErrorString("DSA signature contained zero or negative values")
}
- r := new(big.Int).SetBytes(dsaSig.R.Bytes)
- s := new(big.Int).SetBytes(dsaSig.S.Bytes)
- if !dsa.Verify(pub, digest, r, s) {
+ if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
return os.ErrorString("DSA verification failure")
}
return
@@ -605,8 +468,8 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
}
// CheckCRLSignature checks that the signature in crl is from c.
-func (c *Certificate) CheckCRLSignature(crl *crl.CertificateList) (err os.Error) {
- algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algo)
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) {
+ algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
@@ -622,7 +485,7 @@ type basicConstraints struct {
}
type rsaPublicKey struct {
- N asn1.RawValue
+ N *big.Int
E int
}
@@ -654,42 +517,33 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
return nil, err
}
- if !rawValueIsInteger(&p.N) {
- return nil, asn1.StructuralError{"tags don't match"}
- }
-
pub := &rsa.PublicKey{
E: p.E,
- N: new(big.Int).SetBytes(p.N.Bytes),
+ N: p.N,
}
return pub, nil
case DSA:
- p := new(asn1.RawValue)
- _, err := asn1.Unmarshal(asn1Data, p)
+ var p *big.Int
+ _, err := asn1.Unmarshal(asn1Data, &p)
if err != nil {
return nil, err
}
- if !rawValueIsInteger(p) {
- return nil, asn1.StructuralError{"tags don't match"}
- }
paramsData := keyData.Algorithm.Parameters.FullBytes
params := new(dsaAlgorithmParameters)
_, err = asn1.Unmarshal(paramsData, params)
if err != nil {
return nil, err
}
- if !rawValueIsInteger(&params.P) ||
- !rawValueIsInteger(&params.Q) ||
- !rawValueIsInteger(&params.G) {
- return nil, asn1.StructuralError{"tags don't match"}
+ if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
+ return nil, os.ErrorString("zero or negative DSA parameter")
}
pub := &dsa.PublicKey{
Parameters: dsa.Parameters{
- P: new(big.Int).SetBytes(params.P.Bytes),
- Q: new(big.Int).SetBytes(params.Q.Bytes),
- G: new(big.Int).SetBytes(params.G.Bytes),
+ P: params.P,
+ Q: params.Q,
+ G: params.G,
},
- Y: new(big.Int).SetBytes(p.Bytes),
+ Y: p,
}
return pub, nil
default:
@@ -716,10 +570,14 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
return nil, err
}
+ if in.TBSCertificate.SerialNumber.Sign() < 0 {
+ return nil, os.ErrorString("negative serial number")
+ }
+
out.Version = in.TBSCertificate.Version + 1
- out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
- out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
- out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
+ out.SerialNumber = in.TBSCertificate.SerialNumber
+ out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer)
+ out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject)
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
@@ -977,8 +835,8 @@ var (
oidExtensionNameConstraints = []int{2, 5, 29, 30}
)
-func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
- ret = make([]extension, 7 /* maximum number of elements. */ )
+func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) {
+ ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )
n := 0
if template.KeyUsage != 0 {
@@ -1095,7 +953,7 @@ var (
// The returned slice is the certificate in DER encoding.
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
- N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
+ N: pub.N,
E: pub.E,
})
if err != nil {
@@ -1114,12 +972,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
c := tbsCertificate{
Version: 2,
- SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
- SignatureAlgorithm: algorithmIdentifier{Algorithm: oidSHA1WithRSA},
- Issuer: parent.Subject.toRDNSequence(),
+ SerialNumber: template.SerialNumber,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ Issuer: parent.Subject.ToRDNSequence(),
Validity: validity{template.NotBefore, template.NotAfter},
- Subject: template.Subject.toRDNSequence(),
- PublicKey: publicKeyInfo{nil, algorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
+ Subject: template.Subject.ToRDNSequence(),
+ PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
Extensions: extensions,
}
@@ -1142,8 +1000,75 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
cert, err = asn1.Marshal(certificate{
nil,
c,
- algorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
return
}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+ block, _ := pem.Decode(crlBytes)
+ if block != nil && block.Type == pemType {
+ crlBytes = block.Bytes
+ }
+ }
+ return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ certList = new(pkix.CertificateList)
+ _, err = asn1.Unmarshal(derBytes, certList)
+ if err != nil {
+ certList = nil
+ }
+ return
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) {
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 2,
+ Signature: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ Issuer: c.Subject.ToRDNSequence(),
+ ThisUpdate: now,
+ NextUpdate: expiry,
+ RevokedCertificates: revokedCerts,
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return
+ }
+
+ h := sha1.New()
+ h.Write(tbsCertListContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index fd137a6f5..dc216505e 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -10,6 +10,8 @@ import (
"crypto/dsa"
"crypto/rand"
"crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/base64"
"encoding/hex"
"encoding/pem"
"testing"
@@ -207,8 +209,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}
template := Certificate{
- SerialNumber: []byte{1},
- Subject: Name{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
CommonName: "test.example.com",
Organization: []string{"Acme Co"},
},
@@ -331,3 +333,99 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
t.Fatalf("DSA Certificate verfication failed: %s", err)
}
}
+
+const pemCertificate = `-----BEGIN CERTIFICATE-----
+MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
+AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
+BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
+SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
+fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
+/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
+ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
+YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
+0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+-----END CERTIFICATE-----`
+
+func TestCRLCreation(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, _ := ParsePKCS1PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(pemCertificate))
+ cert, _ := ParseCertificate(block.Bytes)
+
+ now := time.SecondsToUTC(1000)
+ expiry := time.SecondsToUTC(10000)
+
+ revokedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: now,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ RevocationTime: now,
+ },
+ }
+
+ crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry)
+ if err != nil {
+ t.Errorf("error creating CRL: %s", err)
+ }
+
+ _, err = ParseDERCRL(crlBytes)
+ if err != nil {
+ t.Errorf("error reparsing CRL: %s", err)
+ }
+}
+
+func fromBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ _, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ panic("failed to base64 decode")
+ }
+ return out
+}
+
+func TestParseDERCRL(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestParsePEMCRL(t *testing.T) {
+ pemBytes := fromBase64(pemCRLBase64)
+ certList, err := ParseCRL(pemBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 2
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
+
+const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go
index 964e1c1b0..661afdd35 100644
--- a/src/pkg/ebnf/ebnf.go
+++ b/src/pkg/ebnf/ebnf.go
@@ -8,7 +8,7 @@
// Production = name "=" [ Expression ] "." .
// Expression = Alternative { "|" Alternative } .
// Alternative = Term { Term } .
-// Term = name | token [ "..." token ] | Group | Option | Repetition .
+// Term = name | token [ "…" token ] | Group | Option | Repetition .
// Group = "(" Expression ")" .
// Option = "[" Expression "]" .
// Repetition = "{" Expression "}" .
@@ -82,6 +82,12 @@ type (
Body Expression // {body}
}
+ // A Bad node stands for pieces of source code that lead to a parse error.
+ Bad struct {
+ TokPos token.Pos
+ Error string // parser error message
+ }
+
// A Production node represents an EBNF production.
Production struct {
Name *Name
@@ -103,6 +109,7 @@ func (x *Range) Pos() token.Pos { return x.Begin.Pos() }
func (x *Group) Pos() token.Pos { return x.Lparen }
func (x *Option) Pos() token.Pos { return x.Lbrack }
func (x *Repetition) Pos() token.Pos { return x.Lbrace }
+func (x *Bad) Pos() token.Pos { return x.TokPos }
func (x *Production) Pos() token.Pos { return x.Name.Pos() }
diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go
index 2055f872a..30301748d 100644
--- a/src/pkg/ebnf/ebnf_test.go
+++ b/src/pkg/ebnf/ebnf_test.go
@@ -14,7 +14,7 @@ import (
var fset = token.NewFileSet()
-var grammars = []string{
+var goodGrammars = []string{
`Program = .`,
`Program = foo .
@@ -38,7 +38,19 @@ var grammars = []string{
}
-func check(t *testing.T, filename string, src []byte) {
+var badGrammars = []string{
+ `Program = | .`,
+ `Program = | b .`,
+ `Program = a … b .`,
+ `Program = "a" … .`,
+ `Program = … "b" .`,
+ `Program = () .`,
+ `Program = [] .`,
+ `Program = {} .`,
+}
+
+
+func checkGood(t *testing.T, filename string, src []byte) {
grammar, err := Parse(fset, filename, src)
if err != nil {
t.Errorf("Parse(%s) failed: %v", src, err)
@@ -49,9 +61,20 @@ func check(t *testing.T, filename string, src []byte) {
}
+func checkBad(t *testing.T, filename string, src []byte) {
+ _, err := Parse(fset, filename, src)
+ if err == nil {
+ t.Errorf("Parse(%s) should have failed", src)
+ }
+}
+
+
func TestGrammars(t *testing.T) {
- for _, src := range grammars {
- check(t, "", []byte(src))
+ for _, src := range goodGrammars {
+ checkGood(t, "", []byte(src))
+ }
+ for _, src := range badGrammars {
+ checkBad(t, "", []byte(src))
}
}
@@ -67,6 +90,6 @@ func TestFiles(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- check(t, filename, src)
+ checkGood(t, filename, src)
}
}
diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go
index 166412f99..ede4f7073 100644
--- a/src/pkg/ebnf/parser.go
+++ b/src/pkg/ebnf/parser.go
@@ -85,6 +85,7 @@ func (p *parser) parseToken() *Token {
}
+// ParseTerm returns nil if no term was found.
func (p *parser) parseTerm() (x Expression) {
pos := p.pos
@@ -131,7 +132,8 @@ func (p *parser) parseSequence() Expression {
// no need for a sequence if list.Len() < 2
switch len(list) {
case 0:
- return nil
+ p.errorExpected(p.pos, "term")
+ return &Bad{p.pos, "term expected"}
case 1:
return list[0]
}
@@ -144,20 +146,16 @@ func (p *parser) parseExpression() Expression {
var list Alternative
for {
- if x := p.parseSequence(); x != nil {
- list = append(list, x)
- }
+ list = append(list, p.parseSequence())
if p.tok != token.OR {
break
}
p.next()
}
+ // len(list) > 0
// no need for an Alternative node if list.Len() < 2
- switch len(list) {
- case 0:
- return nil
- case 1:
+ if len(list) == 1 {
return list[0]
}
@@ -168,7 +166,10 @@ func (p *parser) parseExpression() Expression {
func (p *parser) parseProduction() *Production {
name := p.parseIdentifier()
p.expect(token.ASSIGN)
- expr := p.parseExpression()
+ var expr Expression
+ if p.tok != token.PERIOD {
+ expr = p.parseExpression()
+ }
p.expect(token.PERIOD)
return &Production{name, expr}
}
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index c6a5e06bb..935f24c21 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -62,9 +62,11 @@ type Cmd struct {
Stdout io.Writer
Stderr io.Writer
+ // Process is the underlying process, once started.
+ Process *os.Process
+
err os.Error // last error (from LookPath, stdin, stdout, stderr)
- process *os.Process
- finished bool // when Wait was called
+ finished bool // when Wait was called
childFiles []*os.File
closeAfterStart []io.Closer
closeAfterWait []io.Closer
@@ -205,7 +207,7 @@ func (c *Cmd) Start() os.Error {
if c.err != nil {
return c.err
}
- if c.process != nil {
+ if c.Process != nil {
return os.NewError("exec: already started")
}
@@ -219,7 +221,7 @@ func (c *Cmd) Start() os.Error {
}
var err os.Error
- c.process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
+ c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
Dir: c.Dir,
Files: c.childFiles,
Env: c.envv(),
@@ -253,14 +255,14 @@ func (c *Cmd) Start() os.Error {
// error is of type *os.Waitmsg. Other error types may be
// returned for I/O problems.
func (c *Cmd) Wait() os.Error {
- if c.process == nil {
+ if c.Process == nil {
return os.NewError("exec: not started")
}
if c.finished {
return os.NewError("exec: Wait was already called")
}
c.finished = true
- msg, err := c.process.Wait(0)
+ msg, err := c.Process.Wait(0)
var copyError os.Error
for _ = range c.goroutine {
@@ -315,7 +317,7 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
if c.Stdin != nil {
return nil, os.NewError("exec: Stdin already set")
}
- if c.process != nil {
+ if c.Process != nil {
return nil, os.NewError("exec: StdinPipe after process started")
}
pr, pw, err := os.Pipe()
@@ -334,7 +336,7 @@ func (c *Cmd) StdoutPipe() (io.Reader, os.Error) {
if c.Stdout != nil {
return nil, os.NewError("exec: Stdout already set")
}
- if c.process != nil {
+ if c.Process != nil {
return nil, os.NewError("exec: StdoutPipe after process started")
}
pr, pw, err := os.Pipe()
@@ -353,7 +355,7 @@ func (c *Cmd) StderrPipe() (io.Reader, os.Error) {
if c.Stderr != nil {
return nil, os.NewError("exec: Stderr already set")
}
- if c.process != nil {
+ if c.Process != nil {
return nil, os.NewError("exec: StderrPipe after process started")
}
pr, pw, err := os.Pipe()
diff --git a/src/pkg/exp/gui/Makefile b/src/pkg/exp/gui/Makefile
new file mode 100644
index 000000000..af065e4a5
--- /dev/null
+++ b/src/pkg/exp/gui/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=exp/gui
+GOFILES=\
+ gui.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/draw/event.go b/src/pkg/exp/gui/gui.go
index b777d912e..171499186 100644
--- a/src/pkg/exp/draw/event.go
+++ b/src/pkg/exp/gui/gui.go
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package draw
+// Package gui defines a basic graphical user interface programming model.
+package gui
import (
"image"
+ "image/draw"
"os"
)
// A Window represents a single graphics window.
type Window interface {
// Screen returns an editable Image for the window.
- Screen() Image
+ Screen() draw.Image
// FlushImage flushes changes made to Screen() back to screen.
FlushImage()
// EventChan returns a channel carrying UI events such as key presses,
diff --git a/src/pkg/exp/draw/x11/Makefile b/src/pkg/exp/gui/x11/Makefile
index 205b3a65b..88cc1e23b 100644
--- a/src/pkg/exp/draw/x11/Makefile
+++ b/src/pkg/exp/gui/x11/Makefile
@@ -4,7 +4,7 @@
include ../../../../Make.inc
-TARG=exp/draw/x11
+TARG=exp/gui/x11
GOFILES=\
auth.go\
conn.go\
diff --git a/src/pkg/exp/draw/x11/auth.go b/src/pkg/exp/gui/x11/auth.go
index d48936ac1..d48936ac1 100644
--- a/src/pkg/exp/draw/x11/auth.go
+++ b/src/pkg/exp/gui/x11/auth.go
diff --git a/src/pkg/exp/draw/x11/conn.go b/src/pkg/exp/gui/x11/conn.go
index 23edc2c63..bc7ca63db 100644
--- a/src/pkg/exp/draw/x11/conn.go
+++ b/src/pkg/exp/gui/x11/conn.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package x11 implements an X11 backend for the exp/draw package.
+// Package x11 implements an X11 backend for the exp/gui package.
//
// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
// A summary of the wire format can be found in XCB's xproto.xml.
@@ -10,8 +10,9 @@ package x11
import (
"bufio"
- "exp/draw"
+ "exp/gui"
"image"
+ "image/draw"
"io"
"log"
"net"
@@ -43,7 +44,7 @@ type conn struct {
img *image.RGBA
eventc chan interface{}
- mouseState draw.MouseEvent
+ mouseState gui.MouseEvent
buf [256]byte // General purpose scratch buffer.
@@ -53,7 +54,7 @@ type conn struct {
}
// writeSocket runs in its own goroutine, serving both FlushImage calls
-// directly from the exp/draw client and indirectly from X expose events.
+// directly from the exp/gui client and indirectly from X expose events.
// It paints c.img to the X server via PutImage requests.
func (c *conn) writeSocket() {
defer c.c.Close()
@@ -143,7 +144,7 @@ func (c *conn) Close() os.Error {
func (c *conn) EventChan() <-chan interface{} { return c.eventc }
-// readSocket runs in its own goroutine, reading X events and sending draw
+// readSocket runs in its own goroutine, reading X events and sending gui
// events on c's EventChan.
func (c *conn) readSocket() {
var (
@@ -155,7 +156,7 @@ func (c *conn) readSocket() {
// X events are always 32 bytes long.
if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
if err != os.EOF {
- c.eventc <- draw.ErrEvent{err}
+ c.eventc <- gui.ErrEvent{err}
}
return
}
@@ -165,7 +166,7 @@ func (c *conn) readSocket() {
if cookie != 1 {
// We issued only one request (GetKeyboardMapping) with a cookie of 1,
// so we shouldn't get any other reply from the X server.
- c.eventc <- draw.ErrEvent{os.NewError("x11: unexpected cookie")}
+ c.eventc <- gui.ErrEvent{os.NewError("x11: unexpected cookie")}
return
}
keysymsPerKeycode = int(c.buf[1])
@@ -179,7 +180,7 @@ func (c *conn) readSocket() {
u, err := readU32LE(c.r, c.buf[0:4])
if err != nil {
if err != os.EOF {
- c.eventc <- draw.ErrEvent{err}
+ c.eventc <- gui.ErrEvent{err}
}
return
}
@@ -204,11 +205,11 @@ func (c *conn) readSocket() {
// TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
// the same int down the channel as the sent on just the A key?
// TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
- // is that outside the scope of the draw.Window interface?
+ // is that outside the scope of the gui.Window interface?
if c.buf[0] == 0x03 {
keysym = -keysym
}
- c.eventc <- draw.KeyEvent{keysym}
+ c.eventc <- gui.KeyEvent{keysym}
case 0x04, 0x05: // Button press, button release.
mask := 1 << (c.buf[1] - 1)
if c.buf[0] == 0x04 {
@@ -551,7 +552,7 @@ func (c *conn) handshake() os.Error {
}
// NewWindow calls NewWindowDisplay with $DISPLAY.
-func NewWindow() (draw.Window, os.Error) {
+func NewWindow() (gui.Window, os.Error) {
display := os.Getenv("DISPLAY")
if len(display) == 0 {
return nil, os.NewError("$DISPLAY not set")
@@ -559,10 +560,10 @@ func NewWindow() (draw.Window, os.Error) {
return NewWindowDisplay(display)
}
-// NewWindowDisplay returns a new draw.Window, backed by a newly created and
+// NewWindowDisplay returns a new gui.Window, backed by a newly created and
// mapped X11 window. The X server to connect to is specified by the display
// string, such as ":1".
-func NewWindowDisplay(display string) (draw.Window, os.Error) {
+func NewWindowDisplay(display string) (gui.Window, os.Error) {
socket, displayStr, err := connect(display)
if err != nil {
return nil, err
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index caecb6fb8..122b9516b 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -132,15 +132,15 @@ var fmttests = []struct {
{"%q", `"`, `"\""`},
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
{"%q", "abc\xffdef", `"abc\xffdef"`},
- {"%q", "\u263a", `"\u263a"`},
+ {"%q", "\u263a", `"☺"`},
{"%q", "\U0010ffff", `"\U0010ffff"`},
// escaped characters
{"%q", 'x', `'x'`},
{"%q", 0, `'\x00'`},
{"%q", '\n', `'\n'`},
- {"%q", '\u1234', `'\u1234'`},
- {"%q", '\U00012345', `'\U00012345'`},
+ {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
+ {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
{"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
{"%q", '"', `'"'`},
@@ -148,7 +148,7 @@ var fmttests = []struct {
// width
{"%5s", "abc", " abc"},
- {"%2s", "\u263a", " \u263a"},
+ {"%2s", "\u263a", " ☺"},
{"%-5s", "abc", "abc "},
{"%-8q", "abc", `"abc" `},
{"%05s", "abc", "00abc"},
@@ -158,9 +158,9 @@ var fmttests = []struct {
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
- {"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`},
- {"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`},
- {"%10.1q", "日本語日本語", ` "\u65e5"`},
+ {"%.3q", "日本語日本語", `"日本語"`},
+ {"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%10.1q", "日本語日本語", ` "日"`},
// integers
{"%d", 12345, "12345"},
diff --git a/src/pkg/go/build/Makefile b/src/pkg/go/build/Makefile
new file mode 100644
index 000000000..4411940ae
--- /dev/null
+++ b/src/pkg/go/build/Makefile
@@ -0,0 +1,22 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/build
+GOFILES=\
+ build.go\
+ dir.go\
+ path.go\
+ syslist.go\
+
+CLEANFILES+=syslist.go
+
+include ../../../Make.pkg
+
+syslist.go: ../../../Make.inc Makefile
+ echo '// Generated automatically by make.' >$@
+ echo 'package build' >>$@
+ echo 'const goosList = "$(GOOS_LIST)"' >>$@
+ echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
new file mode 100644
index 000000000..3cb8efe47
--- /dev/null
+++ b/src/pkg/go/build/build.go
@@ -0,0 +1,272 @@
+// 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 build provides tools for building Go packages.
+package build
+
+import (
+ "bytes"
+ "exec"
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
+ b := &build{obj: "_obj/"}
+
+ goarch := runtime.GOARCH
+ if g := os.Getenv("GOARCH"); g != "" {
+ goarch = g
+ }
+ var err os.Error
+ b.arch, err = ArchChar(goarch)
+ if err != nil {
+ return nil, err
+ }
+
+ var gofiles = d.GoFiles // .go files to be built with gc
+ var ofiles []string // *.GOARCH files to be linked or packed
+
+ // make build directory
+ b.mkdir(b.obj)
+
+ // cgo
+ if len(d.CgoFiles) > 0 {
+ outGo, outObj := b.cgo(d.CgoFiles)
+ gofiles = append(gofiles, outGo...)
+ ofiles = append(ofiles, outObj...)
+ }
+
+ // compile
+ if len(gofiles) > 0 {
+ ofile := b.obj + "_go_." + b.arch
+ b.gc(ofile, gofiles...)
+ ofiles = append(ofiles, ofile)
+ }
+
+ // assemble
+ for _, sfile := range d.SFiles {
+ ofile := b.obj + sfile[:len(sfile)-1] + b.arch
+ b.asm(ofile, sfile)
+ ofiles = append(ofiles, ofile)
+ }
+
+ if len(ofiles) == 0 {
+ return nil, os.NewError("make: no object files to build")
+ }
+
+ if d.IsCommand() {
+ b.ld(targ, ofiles...)
+ } else {
+ b.gopack(targ, ofiles...)
+ }
+
+ return b.cmds, nil
+}
+
+type Cmd struct {
+ Args []string // command-line
+ Stdout string // write standard output to this file, "" is passthrough
+ Input []string // file paths (dependencies)
+ Output []string // file paths
+}
+
+func (c *Cmd) String() string {
+ return strings.Join(c.Args, " ")
+}
+
+func (c *Cmd) Run(dir string) os.Error {
+ out := new(bytes.Buffer)
+ cmd := exec.Command(c.Args[0], c.Args[1:]...)
+ cmd.Dir = dir
+ cmd.Stdout = out
+ cmd.Stderr = out
+ if c.Stdout != "" {
+ f, err := os.Create(filepath.Join(dir, c.Stdout))
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ cmd.Stdout = f
+ }
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("command %q: %v\n%v", c, err, out)
+ }
+ return nil
+}
+
+func (c *Cmd) Clean(dir string) (err os.Error) {
+ for _, fn := range c.Output {
+ if e := os.RemoveAll(fn); err == nil {
+ err = e
+ }
+ }
+ return
+}
+
+// ArchChar returns the architecture character for the given goarch.
+// For example, ArchChar("amd64") returns "6".
+func ArchChar(goarch string) (string, os.Error) {
+ switch goarch {
+ case "386":
+ return "8", nil
+ case "amd64":
+ return "6", nil
+ case "arm":
+ return "5", nil
+ }
+ return "", os.NewError("unsupported GOARCH " + goarch)
+}
+
+type build struct {
+ cmds []*Cmd
+ obj string
+ arch string
+}
+
+func (b *build) add(c Cmd) {
+ b.cmds = append(b.cmds, &c)
+}
+
+func (b *build) mkdir(name string) {
+ b.add(Cmd{
+ Args: []string{"mkdir", "-p", name},
+ Output: []string{name},
+ })
+}
+
+func (b *build) gc(ofile string, gofiles ...string) {
+ gc := b.arch + "g"
+ args := append([]string{gc, "-o", ofile}, gcImportArgs...)
+ args = append(args, gofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: gofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) asm(ofile string, sfile string) {
+ asm := b.arch + "a"
+ b.add(Cmd{
+ Args: []string{asm, "-o", ofile, sfile},
+ Input: []string{sfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) ld(targ string, ofiles ...string) {
+ ld := b.arch + "l"
+ args := append([]string{ld, "-o", targ}, ldImportArgs...)
+ args = append(args, ofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) gopack(targ string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append([]string{"gopack", "grc", targ}, ofiles...),
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) cc(ofile string, cfiles ...string) {
+ cc := b.arch + "c"
+ dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
+ inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
+ args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
+ b.add(Cmd{
+ Args: append(args, cfiles...),
+ Input: cfiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccCompile(ofile, cfile string) {
+ b.add(Cmd{
+ Args: gccArgs(b.arch, "-o", ofile, "-c", cfile),
+ Input: []string{cfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccLink(ofile string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append(gccArgs(b.arch, "-o", ofile), ofiles...),
+ Input: ofiles,
+ Output: []string{ofile},
+ })
+}
+
+func gccArgs(arch string, args ...string) []string {
+ // TODO(adg): HOST_CC
+ m := "-m32"
+ if arch == "6" {
+ m = "-m64"
+ }
+ return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args...)
+}
+
+func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
+ // cgo
+ // TODO(adg): CGOPKGPATH
+ // TODO(adg): CGO_FLAGS
+ gofiles := []string{b.obj + "_cgo_gotypes.go"}
+ cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
+ for _, fn := range cgofiles {
+ f := b.obj + fn[:len(fn)-2]
+ gofiles = append(gofiles, f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := b.obj + "_cgo_defun.c"
+ output := append([]string{defunC}, gofiles...)
+ output = append(output, cfiles...)
+ b.add(Cmd{
+ Args: append([]string{"cgo", "--"}, cgofiles...),
+ Input: cgofiles,
+ Output: output,
+ })
+ outGo = append(outGo, gofiles...)
+
+ // cc _cgo_defun.c
+ defunObj := b.obj + "_cgo_defun." + b.arch
+ b.cc(defunObj, defunC)
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ linkobj := make([]string, 0, len(cfiles))
+ for _, cfile := range cfiles {
+ ofile := cfile[:len(cfile)-1] + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ }
+ }
+ dynObj := b.obj + "_cgo1_.o"
+ b.gccLink(dynObj, linkobj...)
+
+ // cgo -dynimport
+ importC := b.obj + "_cgo_import.c"
+ b.add(Cmd{
+ Args: []string{"cgo", "-dynimport", dynObj},
+ Stdout: importC,
+ Input: []string{dynObj},
+ Output: []string{importC},
+ })
+
+ // cc _cgo_import.ARCH
+ importObj := b.obj + "_cgo_import." + b.arch
+ b.cc(importObj, importC)
+ outObj = append(outObj, importObj)
+
+ return
+}
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
new file mode 100644
index 000000000..c543eddbd
--- /dev/null
+++ b/src/pkg/go/build/build_test.go
@@ -0,0 +1,57 @@
+// 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 build
+
+import (
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var buildDirs = []string{
+ "pkg/path",
+ "cmd/gofix",
+ "pkg/big",
+ "pkg/go/build/cgotest",
+}
+
+func TestBuild(t *testing.T) {
+ out, err := filepath.Abs("_test/out")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, d := range buildDirs {
+ if runtime.GOARCH == "arm" && strings.Contains(d, "/cgo") {
+ // no cgo for arm, yet.
+ continue
+ }
+ dir := filepath.Join(runtime.GOROOT(), "src", d)
+ testBuild(t, dir, out)
+ }
+}
+
+func testBuild(t *testing.T, dir, targ string) {
+ d, err := ScanDir(dir, true)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer os.Remove(targ)
+ cmds, err := d.Build(targ)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for _, c := range cmds {
+ t.Log("Run:", c)
+ err = c.Run(dir)
+ if err != nil {
+ t.Error(c, err)
+ return
+ }
+ }
+}
diff --git a/src/pkg/go/build/cgotest/file.go b/src/pkg/go/build/cgotest/file.go
new file mode 100644
index 000000000..3b2a2e7d9
--- /dev/null
+++ b/src/pkg/go/build/cgotest/file.go
@@ -0,0 +1,45 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+A trivial example of wrapping a C library in Go.
+For a more complex example and explanation,
+see ../gmp/gmp.go.
+*/
+
+package stdio
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+char* greeting = "hello, world";
+*/
+import "C"
+import "unsafe"
+
+type File C.FILE
+
+// TODO(brainman): uncomment once stdout and stderr references are working on Windows.
+//var Stdout = (*File)(C.stdout)
+//var Stderr = (*File)(C.stderr)
+
+// Test reference to library symbol.
+// Stdout and stderr are too special to be a reliable test.
+var myerr = C.sys_errlist
+
+func (f *File) WriteString(s string) {
+ p := C.CString(s)
+ C.fputs(p, (*C.FILE)(f))
+ C.free(unsafe.Pointer(p))
+ f.Flush()
+}
+
+func (f *File) Flush() {
+ C.fflush((*C.FILE)(f))
+}
+
+var Greeting = C.GoString(C.greeting)
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
new file mode 100644
index 000000000..77e80bff0
--- /dev/null
+++ b/src/pkg/go/build/dir.go
@@ -0,0 +1,173 @@
+// 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 build
+
+import (
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "runtime"
+)
+
+type DirInfo struct {
+ GoFiles []string // .go files in dir (excluding CgoFiles)
+ CgoFiles []string // .go files that import "C"
+ CFiles []string // .c files in dir
+ SFiles []string // .s files in dir
+ Imports []string // All packages imported by goFiles
+ PkgName string // Name of package in dir
+}
+
+func (d *DirInfo) IsCommand() bool {
+ return d.PkgName == "main"
+}
+
+// ScanDir returns a structure with details about the Go content found
+// in the given directory. The file lists exclude:
+//
+// - files in package main (unless allowMain is true)
+// - files in package documentation
+// - files ending in _test.go
+// - files starting with _ or .
+//
+// Only files that satisfy the goodOSArch function are included.
+func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ return nil, err
+ }
+ dirs, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ var di DirInfo
+ imported := make(map[string]bool)
+ pkgName := ""
+ fset := token.NewFileSet()
+ for i := range dirs {
+ d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") ||
+ strings.HasPrefix(d.Name, ".") {
+ continue
+ }
+ if !goodOSArch(d.Name) {
+ continue
+ }
+
+ switch filepath.Ext(d.Name) {
+ case ".go":
+ if strings.HasSuffix(d.Name, "_test.go") {
+ continue
+ }
+ case ".c":
+ di.CFiles = append(di.CFiles, d.Name)
+ continue
+ case ".s":
+ di.SFiles = append(di.SFiles, d.Name)
+ continue
+ default:
+ continue
+ }
+
+ filename := filepath.Join(dir, d.Name)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
+ if err != nil {
+ return nil, err
+ }
+ s := string(pf.Name.Name)
+ if s == "main" && !allowMain {
+ continue
+ }
+ if s == "documentation" {
+ continue
+ }
+ if pkgName == "" {
+ pkgName = s
+ } else if pkgName != s {
+ // Only if all files in the directory are in package main
+ // do we return pkgName=="main".
+ // A mix of main and another package reverts
+ // to the original (allowMain=false) behaviour.
+ if s == "main" || pkgName == "main" {
+ return ScanDir(dir, false)
+ }
+ return nil, os.ErrorString("multiple package names in " + dir)
+ }
+ isCgo := false
+ for _, spec := range pf.Imports {
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ imported[path] = true
+ if path == "C" {
+ isCgo = true
+ }
+ }
+ if isCgo {
+ di.CgoFiles = append(di.CgoFiles, d.Name)
+ } else {
+ di.GoFiles = append(di.GoFiles, d.Name)
+ }
+ }
+ di.Imports = make([]string, len(imported))
+ i := 0
+ for p := range imported {
+ di.Imports[i] = p
+ i++
+ }
+ return &di, nil
+}
+
+// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized filename formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+//
+func goodOSArch(filename string) bool {
+ if dot := strings.Index(filename, "."); dot != -1 {
+ filename = filename[:dot]
+ }
+ l := strings.Split(filename, "_", -1)
+ n := len(l)
+ if n == 0 {
+ return true
+ }
+ if good, known := goodOS[l[n-1]]; known {
+ return good
+ }
+ if good, known := goodArch[l[n-1]]; known {
+ if !good || n < 2 {
+ return false
+ }
+ good, known = goodOS[l[n-2]]
+ return good || !known
+ }
+ return true
+}
+
+var goodOS = make(map[string]bool)
+var goodArch = make(map[string]bool)
+
+func init() {
+ goodOS = make(map[string]bool)
+ goodArch = make(map[string]bool)
+ for _, v := range strings.Fields(goosList) {
+ goodOS[v] = v == runtime.GOOS
+ }
+ for _, v := range strings.Fields(goarchList) {
+ goodArch[v] = v == runtime.GOARCH
+ }
+}
diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
new file mode 100644
index 000000000..8ad39fb0f
--- /dev/null
+++ b/src/pkg/go/build/path.go
@@ -0,0 +1,163 @@
+// 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 build
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+// Path is a validated list of Trees derived from $GOPATH at init.
+var Path []*Tree
+
+// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
+type Tree struct {
+ Path string
+ Goroot bool
+}
+
+func newTree(p string) (*Tree, os.Error) {
+ if !filepath.IsAbs(p) {
+ return nil, os.NewError("must be absolute")
+ }
+ ep, err := filepath.EvalSymlinks(p)
+ if err != nil {
+ return nil, err
+ }
+ return &Tree{Path: ep}, nil
+}
+
+// SrcDir returns the tree's package source directory.
+func (t *Tree) SrcDir() string {
+ if t.Goroot {
+ return filepath.Join(t.Path, "src", "pkg")
+ }
+ return filepath.Join(t.Path, "src")
+}
+
+// PkgDir returns the tree's package object directory.
+func (t *Tree) PkgDir() string {
+ goos, goarch := runtime.GOOS, runtime.GOARCH
+ if e := os.Getenv("GOOS"); e != "" {
+ goos = e
+ }
+ if e := os.Getenv("GOARCH"); e != "" {
+ goarch = e
+ }
+ return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
+}
+
+// BinDir returns the tree's binary executable directory.
+func (t *Tree) BinDir() string {
+ return filepath.Join(t.Path, "bin")
+}
+
+// HasSrc returns whether the given package's
+// source can be found inside this Tree.
+func (t *Tree) HasSrc(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
+ if err != nil {
+ return false
+ }
+ return fi.IsDirectory()
+}
+
+// HasPkg returns whether the given package's
+// object file can be found inside this Tree.
+func (t *Tree) HasPkg(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
+ if err != nil {
+ return false
+ }
+ return fi.IsRegular()
+ // TODO(adg): check object version is consistent
+}
+
+var ErrNotFound = os.NewError("package could not be found locally")
+
+// FindTree takes an import or filesystem path and returns the
+// tree where the package source should be and the package import path.
+func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
+ if isLocalPath(path) {
+ if path, err = filepath.Abs(path); err != nil {
+ return
+ }
+ for _, t := range Path {
+ tpath := t.SrcDir() + string(filepath.Separator)
+ if !strings.HasPrefix(path, tpath) {
+ continue
+ }
+ tree = t
+ pkg = path[len(tpath):]
+ return
+ }
+ err = fmt.Errorf("path %q not inside a GOPATH", path)
+ return
+ }
+ tree = defaultTree
+ pkg = path
+ for _, t := range Path {
+ if t.HasSrc(pkg) {
+ tree = t
+ return
+ }
+ }
+ err = ErrNotFound
+ return
+}
+
+// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
+func isLocalPath(s string) bool {
+ const sep = string(filepath.Separator)
+ return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
+}
+
+var (
+ // argument lists used by the build's gc and ld methods
+ gcImportArgs []string
+ ldImportArgs []string
+
+ // default tree for remote packages
+ defaultTree *Tree
+)
+
+// set up Path: parse and validate GOROOT and GOPATH variables
+func init() {
+ root := runtime.GOROOT()
+ p, err := newTree(root)
+ if err != nil {
+ log.Fatalf("Invalid GOROOT %q: %v", root, err)
+ }
+ p.Goroot = true
+ Path = []*Tree{p}
+
+ for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
+ if p == "" {
+ continue
+ }
+ t, err := newTree(p)
+ if err != nil {
+ log.Printf("Invalid GOPATH %q: %v", p, err)
+ continue
+ }
+ Path = append(Path, t)
+ gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
+ ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
+
+ // select first GOPATH entry as default
+ if defaultTree == nil {
+ defaultTree = t
+ }
+ }
+
+ // use GOROOT if no valid GOPATH specified
+ if defaultTree == nil {
+ defaultTree = Path[0]
+ }
+}
diff --git a/src/pkg/go/build/syslist_test.go b/src/pkg/go/build/syslist_test.go
new file mode 100644
index 000000000..eb0e5dcb6
--- /dev/null
+++ b/src/pkg/go/build/syslist_test.go
@@ -0,0 +1,62 @@
+// 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 build
+
+import (
+ "runtime"
+ "testing"
+)
+
+var (
+ thisOS = runtime.GOOS
+ thisArch = runtime.GOARCH
+ otherOS = anotherOS()
+ otherArch = anotherArch()
+)
+
+func anotherOS() string {
+ if thisOS != "darwin" {
+ return "darwin"
+ }
+ return "linux"
+}
+
+func anotherArch() string {
+ if thisArch != "amd64" {
+ return "amd64"
+ }
+ return "386"
+}
+
+type GoodFileTest struct {
+ name string
+ result bool
+}
+
+var tests = []GoodFileTest{
+ {"file.go", true},
+ {"file.c", true},
+ {"file_foo.go", true},
+ {"file_" + thisArch + ".go", true},
+ {"file_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".go", true},
+ {"file_" + otherOS + ".go", false},
+ {"file_" + thisOS + "_" + thisArch + ".go", true},
+ {"file_" + otherOS + "_" + thisArch + ".go", false},
+ {"file_" + thisOS + "_" + otherArch + ".go", false},
+ {"file_" + otherOS + "_" + otherArch + ".go", false},
+ {"file_foo_" + thisArch + ".go", true},
+ {"file_foo_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".c", true},
+ {"file_" + otherOS + ".c", false},
+}
+
+func TestGoodOSArch(t *testing.T) {
+ for _, test := range tests {
+ if goodOSArch(test.name) != test.result {
+ t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
+ }
+ }
+}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 8af972838..ee1e830a1 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -652,7 +652,7 @@ var errors = []struct {
}{
{"\a", token.ILLEGAL, 0, "illegal character '\\a'"},
{`#`, token.ILLEGAL, 0, "illegal character '#'"},
- {`…`, token.ILLEGAL, 0, "illegal character '\\u2026'"},
+ {`…`, token.ILLEGAL, 0, "illegal character '…'"},
{`' '`, token.CHAR, 0, ""},
{`''`, token.CHAR, 0, "illegal character literal"},
{`'\8'`, token.CHAR, 2, "unknown escape sequence"},
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
index 377c45ad6..2cfed7726 100644
--- a/src/pkg/go/types/gcimporter.go
+++ b/src/pkg/go/types/gcimporter.go
@@ -403,7 +403,7 @@ func (p *gcParser) parseStructType() Type {
}
-// Parameter = ( identifier | "?" ) [ "..." ] Type .
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
//
func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
name := p.parseName()
@@ -415,6 +415,11 @@ func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
isVariadic = true
}
ptyp := p.parseType()
+ // ignore argument tag
+ if p.tok == ':' {
+ p.next()
+ p.expect(scanner.String)
+ }
par = ast.NewObj(ast.Var, name)
par.Type = ptyp
return
diff --git a/src/pkg/html/doc.go b/src/pkg/html/doc.go
index 55135c3d0..5bc063086 100644
--- a/src/pkg/html/doc.go
+++ b/src/pkg/html/doc.go
@@ -4,6 +4,7 @@
/*
Package html implements an HTML5-compliant tokenizer and parser.
+INCOMPLETE.
Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
caller's responsibility to ensure that r provides UTF-8 encoded HTML.
diff --git a/src/pkg/html/token.go b/src/pkg/html/token.go
index 6d8eb604e..23c95ece6 100644
--- a/src/pkg/html/token.go
+++ b/src/pkg/html/token.go
@@ -355,6 +355,33 @@ loop:
return z.buf[i0:i], z.trim(i)
}
+// attrName finds the largest attribute name at the start
+// of z.buf[i:] and returns it lower-cased, as well
+// as the trimmed cursor location after that word.
+//
+// http://dev.w3.org/html5/spec/Overview.html#syntax-attribute-name
+// TODO: unicode characters
+func (z *Tokenizer) attrName(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch c {
+ case '<', '>', '"', '\'', '/', '=':
+ break loop
+ }
+ switch {
+ case 'A' <= c && c <= 'Z':
+ z.buf[i] = c + 'a' - 'A'
+ case c > ' ' && c < 0x7f:
+ // No-op.
+ default:
+ break loop
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
// Text returns the unescaped text of a TextToken or a CommentToken.
// The contents of the returned slice may change on the next call to Next.
func (z *Tokenizer) Text() []byte {
@@ -399,7 +426,7 @@ func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
// attribute for the current tag token and whether there are more attributes.
// The contents of the returned slices may change on the next call to Next.
func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
- key, i := z.word(z.p0, true)
+ key, i := z.attrName(z.p0)
// Check for an empty attribute value.
if i == z.p1 {
z.p0 = i
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
index 6291af600..c17b436aa 100644
--- a/src/pkg/html/token_test.go
+++ b/src/pkg/html/token_test.go
@@ -126,6 +126,11 @@ var tokenTests = []tokenTest{
`<input value="yes" foo="BAR">`,
},
{
+ "Unquoted attribute value, spaces",
+ `<input value = yes FOO = BAR>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
"Unquoted attribute value, trailing space",
`<input value=yes FOO=BAR >`,
`<input value="yes" foo="BAR">`,
@@ -145,6 +150,11 @@ var tokenTests = []tokenTest{
`<input value="I'm an attribute" FOO="BAR">`,
`<input value="I&apos;m an attribute" foo="BAR">`,
},
+ {
+ "Attribute name characters",
+ `<meta http-equiv="content-type">`,
+ `<meta http-equiv="content-type">`,
+ },
}
func TestTokenizer(t *testing.T) {
diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go
index 7e1d65df3..71b037042 100644
--- a/src/pkg/http/client.go
+++ b/src/pkg/http/client.go
@@ -7,7 +7,6 @@
package http
import (
- "bytes"
"encoding/base64"
"fmt"
"io"
@@ -240,7 +239,7 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
// Caller should close r.Body when done reading from it.
//
// PostForm is a wrapper around DefaultClient.PostForm
-func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
+func PostForm(url string, data Values) (r *Response, err os.Error) {
return DefaultClient.PostForm(url, data)
}
@@ -248,17 +247,8 @@ func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
// with data's keys and values urlencoded as the request body.
//
// Caller should close r.Body when done reading from it.
-func (c *Client) PostForm(url string, data map[string]string) (r *Response, err os.Error) {
- return c.Post(url, "application/x-www-form-urlencoded", urlencode(data))
-}
-
-// TODO: remove this function when PostForm takes a multimap.
-func urlencode(data map[string]string) (b *bytes.Buffer) {
- m := make(map[string][]string, len(data))
- for k, v := range data {
- m[k] = []string{v}
- }
- return bytes.NewBuffer([]byte(EncodeQuery(m)))
+func (c *Client) PostForm(url string, data Values) (r *Response, err os.Error) {
+ return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
// Head issues a HEAD to the specified URL. If the response is one of the
diff --git a/src/pkg/http/client_test.go b/src/pkg/http/client_test.go
index 822a8889c..9ef81d9d4 100644
--- a/src/pkg/http/client_test.go
+++ b/src/pkg/http/client_test.go
@@ -109,7 +109,10 @@ func TestPostFormRequestFormat(t *testing.T) {
client := &Client{Transport: tr}
url := "http://dummy.faketld/"
- form := map[string]string{"foo": "bar"}
+ form := make(Values)
+ form.Set("foo", "bar")
+ form.Add("foo", "bar2")
+ form.Set("bar", "baz")
client.PostForm(url, form) // Note: doesn't hit network
if tr.req.Method != "POST" {
@@ -127,10 +130,17 @@ func TestPostFormRequestFormat(t *testing.T) {
if tr.req.Close {
t.Error("got Close true, want false")
}
- if g, e := tr.req.ContentLength, int64(len("foo=bar")); g != e {
+ expectedBody := "foo=bar&foo=bar2&bar=baz"
+ if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
t.Errorf("got ContentLength %d, want %d", g, e)
}
-
+ bodyb, err := ioutil.ReadAll(tr.req.Body)
+ if err != nil {
+ t.Fatalf("ReadAll on req.Body: %v", err)
+ }
+ if g := string(bodyb); g != expectedBody {
+ t.Errorf("got body %q, want %q", g, expectedBody)
+ }
}
func TestRedirects(t *testing.T) {
diff --git a/src/pkg/http/httptest/server.go b/src/pkg/http/httptest/server.go
index 8e385d045..879f04f33 100644
--- a/src/pkg/http/httptest/server.go
+++ b/src/pkg/http/httptest/server.go
@@ -108,29 +108,24 @@ func (s *Server) CloseClientConnections() {
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
-Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
-oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
-nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
-KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
-BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
-EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
-g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
-JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
-kJrLdIhBajcJRYu/YGltHQRaXuVt
+MIIBOTCB5qADAgECAgEAMAsGCSqGSIb3DQEBBTAAMB4XDTcwMDEwMTAwMDAwMFoX
+DTQ5MTIzMTIzNTk1OVowADBaMAsGCSqGSIb3DQEBAQNLADBIAkEAsuA5mAFMj6Q7
+qoBzcvKzIq4kzuT5epSp2AkcQfyBHm7K13Ws7u+0b5Vb9gqTf5cAiIKcrtrXVqkL
+8i1UQF6AzwIDAQABo08wTTAOBgNVHQ8BAf8EBAMCACQwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDAbBgNVHREEFDASggkxMjcuMC4wLjGCBVs6OjFdMAsG
+CSqGSIb3DQEBBQNBAJH30zjLWRztrWpOCgJL8RQWLaKzhK79pVhAx6q/3NrF16C7
++l1BRZstTwIGdoGId8BRpErK1TXkniFb95ZMynM=
-----END CERTIFICATE-----
`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
-Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
-jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
-AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
-YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
-aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
-HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
-jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
-mHRJOWk0jBtXfRft1McH2H51CpXAyw==
+MIIBPQIBAAJBALLgOZgBTI+kO6qAc3LysyKuJM7k+XqUqdgJHEH8gR5uytd1rO7v
+tG+VW/YKk3+XAIiCnK7a11apC/ItVEBegM8CAwEAAQJBAI5sxq7naeR9ahyqRkJi
+SIv2iMxLuPEHaezf5CYOPWjSjBPyVhyRevkhtqEjF/WkgL7C2nWpYHsUcBDBQVF0
+3KECIQDtEGB2ulnkZAahl3WuJziXGLB+p8Wgx7wzSM6bHu1c6QIhAMEp++CaS+SJ
+/TrU0zwY/fW4SvQeb49BPZUF3oqR8Xz3AiEA1rAJHBzBgdOQKdE3ksMUPcnvNJSN
+poCcELmz2clVXtkCIQCLytuLV38XHToTipR4yMl6O+6arzAjZ56uq7m7ZRV0TwIh
+AM65XAOw8Dsg9Kq78aYXiOEDc5DL0sbFUu/SlmRcCg93
-----END RSA PRIVATE KEY-----
`)
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
index 19e2ff774..d93e573f5 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/http/readrequest_test.go
@@ -64,7 +64,7 @@ var reqTests = []reqTest{
Host: "www.techcrunch.com",
Referer: "",
UserAgent: "Fake",
- Form: map[string][]string{},
+ Form: Values{},
},
"abcdef\n",
@@ -99,7 +99,7 @@ var reqTests = []reqTest{
Host: "test",
Referer: "",
UserAgent: "",
- Form: map[string][]string{},
+ Form: Values{},
},
"",
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 2f6b651c3..bdc3a7e4f 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -90,10 +90,10 @@ type Request struct {
//
// then
//
- // Header = map[string]string{
- // "Accept-Encoding": "gzip, deflate",
- // "Accept-Language": "en-us",
- // "Connection": "keep-alive",
+ // Header = map[string][]string{
+ // "Accept-Encoding": {"gzip, deflate"},
+ // "Accept-Language": {"en-us"},
+ // "Connection": {"keep-alive"},
// }
//
// HTTP defines that header names are case-insensitive.
@@ -141,7 +141,7 @@ type Request struct {
UserAgent string
// The parsed form. Only available after ParseForm is called.
- Form map[string][]string
+ Form Values
// The parsed multipart form, including file uploads.
// Only available after ParseMultipartForm is called.
@@ -238,9 +238,9 @@ const defaultUserAgent = "Go http package"
// TransferEncoding
// Body
//
-// If Body is present but Content-Length is <= 0, Write adds
-// "Transfer-Encoding: chunked" to the header. Body is closed after
-// it is sent.
+// If Body is present, Content-Length is <= 0 and TransferEncoding
+// hasn't been set to "identity", Write adds "Transfer-Encoding:
+// chunked" to the header. Body is closed after it is sent.
func (req *Request) Write(w io.Writer) os.Error {
return req.write(w, false)
}
@@ -488,6 +488,11 @@ func NewRequest(method, url string, body io.Reader) (*Request, os.Error) {
default:
req.ContentLength = -1 // chunked
}
+ if req.ContentLength == 0 {
+ // To prevent chunking and disambiguate this
+ // from the default ContentLength zero value.
+ req.TransferEncoding = []string{"identity"}
+ }
}
return req, nil
@@ -597,18 +602,56 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return req, nil
}
+// Values maps a string key to a list of values.
+// It is typically used for query parameters and form values.
+// Unlike in the Header map, the keys in a Values map
+// are case-sensitive.
+type Values map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns
+// the empty string. To access multiple values, use the map
+// directly.
+func (v Values) Get(key string) string {
+ if v == nil {
+ return ""
+ }
+ vs, ok := v[key]
+ if !ok || len(vs) == 0 {
+ return ""
+ }
+ return vs[0]
+}
+
+// Set sets the key to value. It replaces any existing
+// values.
+func (v Values) Set(key, value string) {
+ v[key] = []string{value}
+}
+
+// Add adds the key to value. It appends to any existing
+// values associated with key.
+func (v Values) Add(key, value string) {
+ v[key] = append(v[key], value)
+}
+
+// Del deletes the values associated with key.
+func (v Values) Del(key string) {
+ v[key] = nil, false
+}
+
// ParseQuery parses the URL-encoded query string and returns
// a map listing the values specified for each key.
// ParseQuery always returns a non-nil map containing all the
// valid query parameters found; err describes the first decoding error
// encountered, if any.
-func ParseQuery(query string) (m map[string][]string, err os.Error) {
- m = make(map[string][]string)
+func ParseQuery(query string) (m Values, err os.Error) {
+ m = make(Values)
err = parseQuery(m, query)
return
}
-func parseQuery(m map[string][]string, query string) (err os.Error) {
+func parseQuery(m Values, query string) (err os.Error) {
for _, kv := range strings.Split(query, "&", -1) {
if len(kv) == 0 {
continue
@@ -641,7 +684,7 @@ func (r *Request) ParseForm() (err os.Error) {
return
}
- r.Form = make(map[string][]string)
+ r.Form = make(Values)
if r.URL != nil {
err = parseQuery(r.Form, r.URL.RawQuery)
}
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
index 2889048a9..98fbcf459 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/http/requestwrite_test.go
@@ -274,13 +274,45 @@ func (rc *closeChecker) Close() os.Error {
// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
-// inside a NopCloser.
+// inside a NopCloser, and that it serializes it correctly.
func TestRequestWriteClosesBody(t *testing.T) {
rc := &closeChecker{Reader: strings.NewReader("my body")}
- req, _ := NewRequest("GET", "http://foo.com/", rc)
+ req, _ := NewRequest("POST", "http://foo.com/", rc)
+ if g, e := req.ContentLength, int64(-1); g != e {
+ t.Errorf("got req.ContentLength %d, want %d", g, e)
+ }
buf := new(bytes.Buffer)
req.Write(buf)
if !rc.closed {
t.Error("body not closed after write")
}
+ if g, e := buf.String(), "POST / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n7\r\nmy body\r\n0\r\n\r\n"; g != e {
+ t.Errorf("write:\n got: %s\nwant: %s", g, e)
+ }
+}
+
+func TestZeroLengthNewRequest(t *testing.T) {
+ var buf bytes.Buffer
+
+ // Writing with default identity encoding
+ req, _ := NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
+ if len(req.TransferEncoding) == 0 || req.TransferEncoding[0] != "identity" {
+ t.Fatalf("got req.TransferEncoding of %v, want %v", req.TransferEncoding, []string{"identity"})
+ }
+ if g, e := req.ContentLength, int64(0); g != e {
+ t.Errorf("got req.ContentLength %d, want %d", g, e)
+ }
+ req.Write(&buf)
+ if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nContent-Length: 0\r\n\r\n"; g != e {
+ t.Errorf("identity write:\n got: %s\nwant: %s", g, e)
+ }
+
+ // Overriding identity encoding and forcing chunked.
+ req, _ = NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
+ req.TransferEncoding = nil
+ buf.Reset()
+ req.Write(&buf)
+ if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"; g != e {
+ t.Errorf("chunked write:\n got: %s\nwant: %s", g, e)
+ }
}
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index c923c8a76..dc4594a79 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -12,12 +12,14 @@ import (
"fmt"
. "http"
"http/httptest"
+ "io"
"io/ioutil"
"log"
"os"
"net"
"reflect"
"strings"
+ "syscall"
"testing"
"time"
)
@@ -494,6 +496,12 @@ func TestHeadResponses(t *testing.T) {
if err != ErrBodyNotAllowed {
t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
}
+
+ // Also exercise the ReaderFrom path
+ _, err = io.Copy(w, strings.NewReader("Ignored body"))
+ if err != ErrBodyNotAllowed {
+ t.Errorf("on Copy, expected ErrBodyNotAllowed, got %v", err)
+ }
}))
defer ts.Close()
res, err := Head(ts.URL)
@@ -773,6 +781,42 @@ func TestHandlerPanic(t *testing.T) {
}
}
+type errorListener struct {
+ errs []os.Error
+}
+
+func (l *errorListener) Accept() (c net.Conn, err os.Error) {
+ if len(l.errs) == 0 {
+ return nil, os.EOF
+ }
+ err = l.errs[0]
+ l.errs = l.errs[1:]
+ return
+}
+
+func (l *errorListener) Close() os.Error {
+ return nil
+}
+
+func (l *errorListener) Addr() net.Addr {
+ return dummyAddr("test-address")
+}
+
+func TestAcceptMaxFds(t *testing.T) {
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
+ ln := &errorListener{[]os.Error{
+ &net.OpError{
+ Op: "accept",
+ Error: os.Errno(syscall.EMFILE),
+ }}}
+ err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
+ if err != os.EOF {
+ t.Errorf("got error %v, want EOF", err)
+ }
+}
+
func BenchmarkClientServer(b *testing.B) {
b.StopTimer()
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 93d9d2ff4..d4638f127 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -129,7 +129,7 @@ func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) {
// WriteHeader if it hasn't been called yet, and WriteHeader
// is what sets r.chunking.
r.Flush()
- if !r.chunking {
+ if !r.chunking && r.bodyAllowed() {
if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
n, err = rf.ReadFrom(src)
r.written += n
@@ -335,6 +335,15 @@ func (w *response) WriteHeader(code int) {
io.WriteString(w.conn.buf, "\r\n")
}
+// bodyAllowed returns true if a Write is allowed for this response type.
+// It's illegal to call this before the header has been flushed.
+func (w *response) bodyAllowed() bool {
+ if !w.wroteHeader {
+ panic("")
+ }
+ return w.status != StatusNotModified && w.req.Method != "HEAD"
+}
+
func (w *response) Write(data []byte) (n int, err os.Error) {
if w.conn.hijacked {
log.Print("http: response.Write on hijacked connection")
@@ -346,9 +355,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
if len(data) == 0 {
return 0, nil
}
-
- if w.status == StatusNotModified || w.req.Method == "HEAD" {
- // Must not have body.
+ if !w.bodyAllowed() {
return 0, ErrBodyNotAllowed
}
@@ -860,6 +867,10 @@ func (srv *Server) Serve(l net.Listener) os.Error {
for {
rw, e := l.Accept()
if e != nil {
+ if ne, ok := e.(net.Error); ok && ne.Temporary() {
+ log.Printf("http: Accept error: %v", e)
+ continue
+ }
return e
}
if srv.ReadTimeout != 0 {
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index 062e7a0ff..b54508e7a 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -38,6 +38,9 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ if t.Body != nil && t.ContentLength <= 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+ t.TransferEncoding = []string{"chunked"}
+ }
case *Response:
t.Body = rr.Body
t.ContentLength = rr.ContentLength
@@ -95,7 +98,7 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
if err != nil {
return
}
- } else if t.ContentLength > 0 || t.ResponseToHEAD {
+ } else if t.ContentLength > 0 || t.ResponseToHEAD || (t.ContentLength == 0 && isIdentity(t.TransferEncoding)) {
io.WriteString(w, "Content-Length: ")
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
if err != nil {
@@ -289,6 +292,9 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Checks whether chunked is part of the encodings stack
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+// Checks whether the encoding is explicitly "identity".
+func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
+
// Sanitize transfer encoding
func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
raw, present := header["Transfer-Encoding"]
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index d7ee14ee8..05b1662d3 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -486,10 +486,14 @@ func (url *URL) String() string {
return result
}
-// EncodeQuery encodes the query represented as a multimap.
-func EncodeQuery(m map[string][]string) string {
- parts := make([]string, 0, len(m)) // will be large enough for most uses
- for k, vs := range m {
+// Encode encodes the values into ``URL encoded'' form.
+// e.g. "foo=bar&bar=baz"
+func (v Values) Encode() string {
+ if v == nil {
+ return ""
+ }
+ parts := make([]string, 0, len(v)) // will be large enough for most uses
+ for k, vs := range v {
prefix := URLEscape(k) + "="
for _, v := range vs {
parts = append(parts, prefix+URLEscape(v))
@@ -593,3 +597,9 @@ func (base *URL) ResolveReference(ref *URL) *URL {
url.Raw = url.String()
return url
}
+
+// Query parses RawQuery and returns the corresponding values.
+func (u *URL) Query() Values {
+ v, _ := ParseQuery(u.RawQuery)
+ return v
+}
diff --git a/src/pkg/http/url_test.go b/src/pkg/http/url_test.go
index d8863f3d3..eaec5872a 100644
--- a/src/pkg/http/url_test.go
+++ b/src/pkg/http/url_test.go
@@ -538,23 +538,21 @@ func TestUnescapeUserinfo(t *testing.T) {
}
}
-type qMap map[string][]string
-
type EncodeQueryTest struct {
- m qMap
+ m Values
expected string
expected1 string
}
var encodeQueryTests = []EncodeQueryTest{
{nil, "", ""},
- {qMap{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
- {qMap{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7", "q=dogs&q=%26&q=7"},
+ {Values{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
+ {Values{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7", "q=dogs&q=%26&q=7"},
}
func TestEncodeQuery(t *testing.T) {
for _, tt := range encodeQueryTests {
- if q := EncodeQuery(tt.m); q != tt.expected && q != tt.expected1 {
+ if q := tt.m.Encode(); q != tt.expected && q != tt.expected1 {
t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
}
}
@@ -673,3 +671,28 @@ func TestResolveReference(t *testing.T) {
}
}
+
+func TestQueryValues(t *testing.T) {
+ u, _ := ParseURL("http://x.com?foo=bar&bar=1&bar=2")
+ v := u.Query()
+ if len(v) != 2 {
+ t.Errorf("got %d keys in Query values, want 2", len(v))
+ }
+ if g, e := v.Get("foo"), "bar"; g != e {
+ t.Errorf("Get(foo) = %q, want %q", g, e)
+ }
+ // Case sensitive:
+ if g, e := v.Get("Foo"), ""; g != e {
+ t.Errorf("Get(Foo) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("bar"), "1"; g != e {
+ t.Errorf("Get(bar) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("baz"), ""; g != e {
+ t.Errorf("Get(baz) = %q, want %q", g, e)
+ }
+ v.Del("bar")
+ if g, e := v.Get("bar"), ""; g != e {
+ t.Errorf("second Get(bar) = %q, want %q", g, e)
+ }
+}
diff --git a/src/pkg/exp/draw/Makefile b/src/pkg/image/draw/Makefile
index 6f0f0b2f5..2ba6e7b51 100644
--- a/src/pkg/exp/draw/Makefile
+++ b/src/pkg/image/draw/Makefile
@@ -4,9 +4,8 @@
include ../../../Make.inc
-TARG=exp/draw
+TARG=image/draw
GOFILES=\
draw.go\
- event.go\
include ../../../Make.pkg
diff --git a/src/pkg/image/draw/clip_test.go b/src/pkg/image/draw/clip_test.go
new file mode 100644
index 000000000..db40d82f5
--- /dev/null
+++ b/src/pkg/image/draw/clip_test.go
@@ -0,0 +1,193 @@
+// 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 draw
+
+import (
+ "image"
+ "testing"
+)
+
+type clipTest struct {
+ desc string
+ r, dr, sr, mr image.Rectangle
+ sp, mp image.Point
+ nilMask bool
+ r0 image.Rectangle
+ sp0, mp0 image.Point
+}
+
+var clipTests = []clipTest{
+ // The following tests all have a nil mask.
+ {
+ "basic",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(0, 0, 100, 100),
+ image.ZP,
+ image.ZP,
+ },
+ {
+ "clip dr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(40, 40, 60, 60),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(40, 40, 60, 60),
+ image.Pt(40, 40),
+ image.ZP,
+ },
+ {
+ "clip sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 80, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 50, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (top-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 8),
+ image.ZP,
+ true,
+ image.Rect(5, 12, 50, 72),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (middle-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 66),
+ image.ZP,
+ true,
+ image.Rect(5, 0, 50, 14),
+ image.Pt(20, 66),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (bottom-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ true,
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp inside sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(44, 33),
+ image.ZP,
+ true,
+ image.Rect(0, 0, 36, 47),
+ image.Pt(44, 33),
+ image.ZP,
+ },
+
+ // The following tests all have a non-nil mask.
+ {
+ "basic mask",
+ image.Rect(0, 0, 80, 80),
+ image.Rect(20, 0, 100, 80),
+ image.Rect(0, 0, 50, 49),
+ image.Rect(0, 0, 46, 47),
+ image.ZP,
+ image.ZP,
+ false,
+ image.Rect(20, 0, 46, 47),
+ image.Pt(20, 0),
+ image.Pt(20, 0),
+ },
+ // TODO(nigeltao): write more tests.
+}
+
+func TestClip(t *testing.T) {
+ dst0 := image.NewRGBA(100, 100)
+ src0 := image.NewRGBA(100, 100)
+ mask0 := image.NewRGBA(100, 100)
+ for _, c := range clipTests {
+ dst := dst0.SubImage(c.dr).(*image.RGBA)
+ src := src0.SubImage(c.sr).(*image.RGBA)
+ var mask image.Image
+ if !c.nilMask {
+ mask = mask0.SubImage(c.mr)
+ }
+ r, sp, mp := c.r, c.sp, c.mp
+ clip(dst, &r, src, &sp, mask, &mp)
+
+ // Check that the actual results equal the expected results.
+ if !c.r0.Eq(r) {
+ t.Errorf("%s: clip rectangle want %v got %v", c.desc, c.r0, r)
+ continue
+ }
+ if !c.sp0.Eq(sp) {
+ t.Errorf("%s: sp want %v got %v", c.desc, c.sp0, sp)
+ continue
+ }
+ if !c.nilMask {
+ if !c.mp0.Eq(mp) {
+ t.Errorf("%s: mp want %v got %v", c.desc, c.mp0, mp)
+ continue
+ }
+ }
+
+ // Check that the clipped rectangle is contained by the dst / src / mask
+ // rectangles, in their respective co-ordinate spaces.
+ if !r.In(c.dr) {
+ t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
+ }
+ // sr is r translated into src's co-ordinate space.
+ sr := r.Add(c.sp.Sub(c.dr.Min))
+ if !sr.In(c.sr) {
+ t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
+ }
+ if !c.nilMask {
+ // mr is r translated into mask's co-ordinate space.
+ mr := r.Add(c.mp.Sub(c.dr.Min))
+ if !mr.In(c.mr) {
+ t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
+ }
+ }
+ }
+}
diff --git a/src/pkg/exp/draw/draw.go b/src/pkg/image/draw/draw.go
index f98e24618..618fb4aa6 100644
--- a/src/pkg/exp/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package draw provides basic graphics and drawing primitives,
+// Package draw provides image composition functions
// in the style of the Plan 9 graphics library
// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
// and the X Render extension.
@@ -16,7 +16,7 @@ import (
// m is the maximum color value returned by image.Color.RGBA.
const m = 1<<16 - 1
-// A Porter-Duff compositing operator.
+// Op is a Porter-Duff compositing operator.
type Op int
const (
@@ -39,27 +39,31 @@ func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
DrawMask(dst, r, src, sp, nil, image.ZP, Over)
}
-// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
-// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
-func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
- sb := src.Bounds()
- dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
+// clip clips r against each image's bounds (after translating into the
+// destination image's co-ordinate space) and shifts the points sp and mp by
+// the same amount as the change in r.Min.
+func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
+ orig := r.Min
+ *r = r.Intersect(dst.Bounds())
+ *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
if mask != nil {
- mb := mask.Bounds()
- if dx > mb.Max.X-mp.X {
- dx = mb.Max.X - mp.X
- }
- if dy > mb.Max.Y-mp.Y {
- dy = mb.Max.Y - mp.Y
- }
- }
- if r.Dx() > dx {
- r.Max.X = r.Min.X + dx
+ *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
}
- if r.Dy() > dy {
- r.Max.Y = r.Min.Y + dy
+ dx := r.Min.X - orig.X
+ dy := r.Min.Y - orig.Y
+ if dx == 0 && dy == 0 {
+ return
}
- r = r.Intersect(dst.Bounds())
+ (*sp).X += dx
+ (*sp).Y += dy
+ (*mp).X += dx
+ (*mp).Y += dy
+}
+
+// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
+// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ clip(dst, &r, src, &sp, mask, &mp)
if r.Empty() {
return
}
diff --git a/src/pkg/exp/draw/draw_test.go b/src/pkg/image/draw/draw_test.go
index 873a2f24a..37d630353 100644
--- a/src/pkg/exp/draw/draw_test.go
+++ b/src/pkg/image/draw/draw_test.go
@@ -263,8 +263,8 @@ func TestDrawOverlap(t *testing.T) {
}
}
-// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
-func TestIssue836(t *testing.T) {
+// TestNonZeroSrcPt checks drawing with a non-zero src point parameter.
+func TestNonZeroSrcPt(t *testing.T) {
a := image.NewRGBA(1, 1)
b := image.NewRGBA(2, 2)
b.Set(0, 0, image.RGBAColor{0, 0, 0, 5})
@@ -273,6 +273,6 @@ func TestIssue836(t *testing.T) {
b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
- t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
}
}
diff --git a/src/pkg/image/geom.go b/src/pkg/image/geom.go
index ccfe9cdb0..667aee625 100644
--- a/src/pkg/image/geom.go
+++ b/src/pkg/image/geom.go
@@ -38,6 +38,12 @@ func (p Point) Div(k int) Point {
return Point{p.X / k, p.Y / k}
}
+// In returns whether p is in r.
+func (p Point) In(r Rectangle) bool {
+ return r.Min.X <= p.X && p.X < r.Max.X &&
+ r.Min.Y <= p.Y && p.Y < r.Max.Y
+}
+
// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
// and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
@@ -190,10 +196,15 @@ func (r Rectangle) Overlaps(s Rectangle) bool {
r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}
-// Contains returns whether r contains p.
-func (r Rectangle) Contains(p Point) bool {
- return p.X >= r.Min.X && p.X < r.Max.X &&
- p.Y >= r.Min.Y && p.Y < r.Max.Y
+// In returns whether every point in r is in s.
+func (r Rectangle) In(s Rectangle) bool {
+ if r.Empty() {
+ return true
+ }
+ // Note that r.Max is an exclusive bound for r, so that r.In(s)
+ // does not require that r.Max.In(s).
+ return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
+ s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}
// Canon returns the canonical version of r. The returned rectangle has minimum
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 9f7296a98..26c013b9a 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -274,7 +274,7 @@ func (d *decoder) readExtension() os.Error {
return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
}
if size > 0 {
- if _, err := d.r.Read(d.tmp[0:size]); err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
return err
}
}
@@ -406,8 +406,8 @@ func DecodeAll(r io.Reader) (*GIF, os.Error) {
return gif, nil
}
-// DecodeConfig returns the color model and dimensions of a GIF image without
-// decoding the entire image.
+// DecodeConfig returns the global color model and dimensions of a GIF image
+// without decoding the entire image.
func DecodeConfig(r io.Reader) (image.Config, os.Error) {
var d decoder
if err := d.decode(r, true); err != nil {
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 1bdac36f5..f4c38d28a 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -38,21 +38,21 @@ func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
func (p *RGBA) Bounds() Rectangle { return p.Rect }
func (p *RGBA) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return RGBAColor{}
}
return p.Pix[y*p.Stride+x]
}
func (p *RGBA) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
}
func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -107,21 +107,21 @@ func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
func (p *RGBA64) Bounds() Rectangle { return p.Rect }
func (p *RGBA64) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return RGBA64Color{}
}
return p.Pix[y*p.Stride+x]
}
func (p *RGBA64) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
}
func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -176,21 +176,21 @@ func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
func (p *NRGBA) Bounds() Rectangle { return p.Rect }
func (p *NRGBA) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return NRGBAColor{}
}
return p.Pix[y*p.Stride+x]
}
func (p *NRGBA) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
}
func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -245,21 +245,21 @@ func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
func (p *NRGBA64) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return NRGBA64Color{}
}
return p.Pix[y*p.Stride+x]
}
func (p *NRGBA64) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
}
func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -314,21 +314,21 @@ func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
func (p *Alpha) Bounds() Rectangle { return p.Rect }
func (p *Alpha) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return AlphaColor{}
}
return p.Pix[y*p.Stride+x]
}
func (p *Alpha) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
}
func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -383,21 +383,21 @@ func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
func (p *Alpha16) Bounds() Rectangle { return p.Rect }
func (p *Alpha16) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return Alpha16Color{}
}
return p.Pix[y*p.Stride+x]
}
func (p *Alpha16) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
}
func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -452,21 +452,21 @@ func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
func (p *Gray) Bounds() Rectangle { return p.Rect }
func (p *Gray) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return GrayColor{}
}
return p.Pix[y*p.Stride+x]
}
func (p *Gray) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
}
func (p *Gray) SetGray(x, y int, c GrayColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -507,21 +507,21 @@ func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
func (p *Gray16) Bounds() Rectangle { return p.Rect }
func (p *Gray16) At(x, y int) Color {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return Gray16Color{}
}
return p.Pix[y*p.Stride+x]
}
func (p *Gray16) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
}
func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = c
@@ -563,14 +563,19 @@ func (p PalettedColorModel) Convert(c Color) Color {
if len(p) == 0 {
return nil
}
+ return p[p.Index(c)]
+}
+
+// Index returns the index of the palette color closest to c in Euclidean
+// R,G,B space.
+func (p PalettedColorModel) Index(c Color) int {
cr, cg, cb, _ := c.RGBA()
// Shift by 1 bit to avoid potential uint32 overflow in sum-squared-difference.
cr >>= 1
cg >>= 1
cb >>= 1
- result := Color(nil)
- bestSSD := uint32(1<<32 - 1)
- for _, v := range p {
+ ret, bestSSD := 0, uint32(1<<32-1)
+ for i, v := range p {
vr, vg, vb, _ := v.RGBA()
vr >>= 1
vg >>= 1
@@ -578,11 +583,10 @@ func (p PalettedColorModel) Convert(c Color) Color {
dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
ssd := (dr * dr) + (dg * dg) + (db * db)
if ssd < bestSSD {
- bestSSD = ssd
- result = v
+ ret, bestSSD = i, ssd
}
}
- return result
+ return ret
}
// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
@@ -604,21 +608,28 @@ func (p *Paletted) At(x, y int) Color {
if len(p.Palette) == 0 {
return nil
}
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return p.Palette[0]
}
return p.Palette[p.Pix[y*p.Stride+x]]
}
+func (p *Paletted) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = uint8(p.Palette.Index(c))
+}
+
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return 0
}
return p.Pix[y*p.Stride+x]
}
func (p *Paletted) SetColorIndex(x, y int, index uint8) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
p.Pix[y*p.Stride+x] = index
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
new file mode 100644
index 000000000..17e314795
--- /dev/null
+++ b/src/pkg/image/image_test.go
@@ -0,0 +1,71 @@
+// 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 image
+
+import (
+ "testing"
+)
+
+func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
+ r0, g0, b0, a0 := cm.Convert(c0).RGBA()
+ r1, g1, b1, a1 := cm.Convert(c1).RGBA()
+ return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func TestImage(t *testing.T) {
+ type buffered interface {
+ Image
+ Set(int, int, Color)
+ SubImage(Rectangle) Image
+ }
+ testImage := []Image{
+ NewRGBA(10, 10),
+ NewRGBA64(10, 10),
+ NewNRGBA(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha(10, 10),
+ NewAlpha16(10, 10),
+ NewGray(10, 10),
+ NewGray16(10, 10),
+ NewPaletted(10, 10, PalettedColorModel{
+ Transparent,
+ Opaque,
+ }),
+ }
+ for _, m := range testImage {
+ b := m.(buffered)
+ if !Rect(0, 0, 10, 10).Eq(b.Bounds()) {
+ t.Errorf("%T: want bounds %v, got %v", b, Rect(0, 0, 10, 10), b.Bounds())
+ continue
+ }
+ if !cmp(t, b.ColorModel(), Transparent, b.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a zero color, got %v", b, b.At(6, 3))
+ continue
+ }
+ b.Set(6, 3, Opaque)
+ if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
+ continue
+ }
+ b = b.SubImage(Rect(3, 2, 9, 8)).(buffered)
+ if !Rect(3, 2, 9, 8).Eq(b.Bounds()) {
+ t.Errorf("%T: sub-image want bounds %v, got %v", b, Rect(3, 2, 9, 8), b.Bounds())
+ continue
+ }
+ if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
+ t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
+ continue
+ }
+ if !cmp(t, b.ColorModel(), Transparent, b.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", b, b.At(3, 3))
+ continue
+ }
+ b.Set(3, 3, Opaque)
+ if !cmp(t, b.ColorModel(), Opaque, b.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", b, b.At(3, 3))
+ continue
+ }
+ }
+}
diff --git a/src/pkg/image/tiff/reader.go b/src/pkg/image/tiff/reader.go
index 57a7be4a2..26e52144d 100644
--- a/src/pkg/image/tiff/reader.go
+++ b/src/pkg/image/tiff/reader.go
@@ -46,6 +46,11 @@ type decoder struct {
mode imageMode
features map[int][]uint
palette []image.Color
+
+ buf []byte
+ off int // Current offset in buf.
+ v uint32 // Buffer value for reading with arbitrary bit depths.
+ nbits uint // Remaining number of bits in v.
}
// firstVal returns the first uint of the features entry with the given tag,
@@ -151,78 +156,94 @@ func (d *decoder) parseIFD(p []byte) os.Error {
return nil
}
-// decode decodes the raw data of an image with 8 bits in each sample.
-// It reads from p and writes the strip with ymin <= y < ymax into dst.
-func (d *decoder) decode(dst image.Image, p []byte, ymin, ymax int) os.Error {
+// readBits reads n bits from the internal buffer starting at the current offset.
+func (d *decoder) readBits(n uint) uint32 {
+ for d.nbits < n {
+ d.v <<= 8
+ d.v |= uint32(d.buf[d.off])
+ d.off++
+ d.nbits += 8
+ }
+ d.nbits -= n
+ rv := d.v >> d.nbits
+ d.v &^= rv << d.nbits
+ return rv
+}
+
+// flushBits discards the unread bits in the buffer used by readBits.
+// It is used at the end of a line.
+func (d *decoder) flushBits() {
+ d.v = 0
+ d.nbits = 0
+}
+
+// decode decodes the raw data of an image.
+// It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
+func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
spp := len(d.features[tBitsPerSample]) // samples per pixel
- off := 0
+ d.off = 0
width := dst.Bounds().Dx()
- if len(p) < spp*(ymax-ymin)*width {
- return FormatError("short data strip")
- }
-
// Apply horizontal predictor if necessary.
// In this case, p contains the color difference to the preceding pixel.
// See page 64-65 of the spec.
- if d.firstVal(tPredictor) == prHorizontal {
+ if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
for y := ymin; y < ymax; y++ {
- off += spp
+ d.off += spp
for x := 0; x < (width-1)*spp; x++ {
- p[off] += p[off-spp]
- off++
+ d.buf[d.off] += d.buf[d.off-spp]
+ d.off++
}
}
- off = 0
+ d.off = 0
}
switch d.mode {
- case mGray:
- img := dst.(*image.Gray)
- for y := ymin; y < ymax; y++ {
- for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.GrayColor{p[off]})
- off += spp
- }
- }
- case mGrayInvert:
+ case mGray, mGrayInvert:
img := dst.(*image.Gray)
+ bpp := d.firstVal(tBitsPerSample)
+ max := uint32((1 << bpp) - 1)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.GrayColor{0xff - p[off]})
- off += spp
+ v := uint8(d.readBits(bpp) * 0xff / max)
+ if d.mode == mGrayInvert {
+ v = 0xff - v
+ }
+ img.SetGray(x, y, image.GrayColor{v})
}
+ d.flushBits()
}
case mPaletted:
img := dst.(*image.Paletted)
+ bpp := d.firstVal(tBitsPerSample)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.SetColorIndex(x, y, p[off])
- off += spp
+ img.SetColorIndex(x, y, uint8(d.readBits(bpp)))
}
+ d.flushBits()
}
case mRGB:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{p[off], p[off+1], p[off+2], 0xff})
- off += spp
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], 0xff})
+ d.off += spp
}
}
case mNRGBA:
img := dst.(*image.NRGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.NRGBAColor{p[off], p[off+1], p[off+2], p[off+3]})
- off += spp
+ img.SetNRGBA(x, y, image.NRGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
}
}
case mRGBA:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{p[off], p[off+1], p[off+2], p[off+3]})
- off += spp
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
}
}
}
@@ -272,9 +293,18 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
d.config.Width = int(d.firstVal(tImageWidth))
d.config.Height = int(d.firstVal(tImageLength))
+ if _, ok := d.features[tBitsPerSample]; !ok {
+ return nil, FormatError("BitsPerSample tag missing")
+ }
+
// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
case pRGB:
+ for _, b := range d.features[tBitsPerSample] {
+ if b != 8 {
+ return nil, UnsupportedError("non-8-bit RGB image")
+ }
+ }
d.config.ColorModel = image.RGBAColorModel
// RGB images normally have 3 samples per pixel.
// If there are more, ExtraSamples (p. 31-32 of the spec)
@@ -309,15 +339,6 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
return nil, UnsupportedError("color model")
}
- if _, ok := d.features[tBitsPerSample]; !ok {
- return nil, FormatError("BitsPerSample tag missing")
- }
- for _, b := range d.features[tBitsPerSample] {
- if b != 8 {
- return nil, UnsupportedError("not an 8-bit image")
- }
- }
-
return d, nil
}
@@ -357,7 +378,6 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
img = image.NewRGBA(d.config.Width, d.config.Height)
}
- var p []byte
for i := 0; i < numStrips; i++ {
ymin := i * rps
// The last strip may be shorter.
@@ -369,18 +389,18 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
switch d.firstVal(tCompression) {
case cNone:
// TODO(bsiegert): Avoid copy if r is a tiff.buffer.
- p = make([]byte, 0, n)
- _, err = d.r.ReadAt(p, offset)
+ d.buf = make([]byte, n)
+ _, err = d.r.ReadAt(d.buf, offset)
case cLZW:
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
- p, err = ioutil.ReadAll(r)
+ d.buf, err = ioutil.ReadAll(r)
r.Close()
case cDeflate, cDeflateOld:
r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
if err != nil {
return nil, err
}
- p, err = ioutil.ReadAll(r)
+ d.buf, err = ioutil.ReadAll(r)
r.Close()
default:
err = UnsupportedError("compression")
@@ -388,7 +408,7 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
if err != nil {
return
}
- err = d.decode(img, p, ymin, ymin+rps)
+ err = d.decode(img, ymin, ymin+rps)
}
return
}
diff --git a/src/pkg/image/ycbcr/ycbcr.go b/src/pkg/image/ycbcr/ycbcr.go
index c1c58b708..f2de3d6fb 100644
--- a/src/pkg/image/ycbcr/ycbcr.go
+++ b/src/pkg/image/ycbcr/ycbcr.go
@@ -142,7 +142,7 @@ func (p *YCbCr) Bounds() image.Rectangle {
}
func (p *YCbCr) At(x, y int) image.Color {
- if !p.Rect.Contains(image.Point{x, y}) {
+ if !(image.Point{x, y}.In(p.Rect)) {
return YCbCrColor{}
}
switch p.SubsampleRatio {
diff --git a/src/pkg/mail/message.go b/src/pkg/mail/message.go
index 9723863fe..754b779be 100644
--- a/src/pkg/mail/message.go
+++ b/src/pkg/mail/message.go
@@ -2,17 +2,42 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package mail implements parsing of mail messages according to RFC 5322.
+/*
+Package mail implements parsing of mail messages.
+
+For the most part, this package follows the syntax as specified by RFC 5322.
+Notable divergences:
+ * Obsolete address formats are not parsed, including addresses with
+ embedded route information.
+ * Group addresses are not parsed.
+ * The full range of spacing (the CFWS syntax element) is not supported,
+ such as breaking addresses across lines.
+*/
package mail
import (
"bufio"
+ "bytes"
+ "fmt"
"io"
+ "log"
"net/textproto"
"os"
+ "strconv"
+ "strings"
"time"
)
+var debug = debugT(false)
+
+type debugT bool
+
+func (d debugT) Printf(format string, args ...interface{}) {
+ if d {
+ log.Printf(format, args...)
+ }
+}
+
// A Message represents a parsed mail message.
type Message struct {
Header Header
@@ -72,8 +97,6 @@ func parseDate(date string) (*time.Time, os.Error) {
return nil, os.ErrorString("mail: header could not be parsed")
}
-// TODO(dsymonds): Parsers for more specific headers such as To, From, etc.
-
// A Header represents the key-value pairs in a mail message header.
type Header map[string][]string
@@ -93,3 +116,376 @@ func (h Header) Date() (*time.Time, os.Error) {
}
return parseDate(hdr)
}
+
+// AddressList parses the named header field as a list of addresses.
+func (h Header) AddressList(key string) ([]*Address, os.Error) {
+ hdr := h.Get(key)
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return newAddrParser(hdr).parseAddressList()
+}
+
+// Address represents a single mail address.
+// An address such as "Barry Gibbs <bg@example.com>" is represented
+// as Address{Name: "Barry Gibbs", Address: "bg@example.com"}.
+type Address struct {
+ Name string // Proper name; may be empty.
+ Address string // user@domain
+}
+
+// String formats the address as a valid RFC 5322 address.
+// If the address's name contains non-ASCII characters
+// the name will be rendered according to RFC 2047.
+func (a *Address) String() string {
+ s := "<" + a.Address + ">"
+ if a.Name == "" {
+ return s
+ }
+ // If every character is printable ASCII, quoting is simple.
+ allPrintable := true
+ for i := 0; i < len(a.Name); i++ {
+ if !isVchar(a.Name[i]) {
+ allPrintable = false
+ break
+ }
+ }
+ if allPrintable {
+ b := bytes.NewBufferString(`"`)
+ for i := 0; i < len(a.Name); i++ {
+ if !isQtext(a.Name[i]) {
+ b.WriteByte('\\')
+ }
+ b.WriteByte(a.Name[i])
+ }
+ b.WriteString(`" `)
+ b.WriteString(s)
+ return b.String()
+ }
+
+ // UTF-8 "Q" encoding
+ b := bytes.NewBufferString("=?utf-8?q?")
+ for i := 0; i < len(a.Name); i++ {
+ switch c := a.Name[i]; {
+ case c == ' ':
+ b.WriteByte('_')
+ case isVchar(c) && c != '=' && c != '?' && c != '_':
+ b.WriteByte(c)
+ default:
+ fmt.Fprintf(b, "=%02X", c)
+ }
+ }
+ b.WriteString("?= ")
+ b.WriteString(s)
+ return b.String()
+}
+
+type addrParser []byte
+
+func newAddrParser(s string) *addrParser {
+ p := addrParser([]byte(s))
+ return &p
+}
+
+func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
+ var list []*Address
+ for {
+ p.skipSpace()
+ addr, err := p.parseAddress()
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, addr)
+
+ p.skipSpace()
+ if p.empty() {
+ break
+ }
+ if !p.consume(',') {
+ return nil, os.ErrorString("mail: expected comma")
+ }
+ }
+ return list, nil
+}
+
+// parseAddress parses a single RFC 5322 address at the start of p.
+func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
+ debug.Printf("parseAddress: %q", *p)
+ p.skipSpace()
+ if p.empty() {
+ return nil, os.ErrorString("mail: no address")
+ }
+
+ // address = name-addr / addr-spec
+ // TODO(dsymonds): Support parsing group address.
+
+ // addr-spec has a more restricted grammar than name-addr,
+ // so try parsing it first, and fallback to name-addr.
+ // TODO(dsymonds): Is this really correct?
+ spec, err := p.consumeAddrSpec()
+ if err == nil {
+ return &Address{
+ Address: spec,
+ }, err
+ }
+ debug.Printf("parseAddress: not an addr-spec: %v", err)
+ debug.Printf("parseAddress: state is now %q", *p)
+
+ // display-name
+ var displayName string
+ if p.peek() != '<' {
+ displayName, err = p.consumePhrase()
+ if err != nil {
+ return nil, err
+ }
+ }
+ debug.Printf("parseAddress: displayName=%q", displayName)
+
+ // angle-addr = "<" addr-spec ">"
+ p.skipSpace()
+ if !p.consume('<') {
+ return nil, os.ErrorString("mail: no angle-addr")
+ }
+ spec, err = p.consumeAddrSpec()
+ if err != nil {
+ return nil, err
+ }
+ if !p.consume('>') {
+ return nil, os.ErrorString("mail: unclosed angle-addr")
+ }
+ debug.Printf("parseAddress: spec=%q", spec)
+
+ return &Address{
+ Name: displayName,
+ Address: spec,
+ }, nil
+}
+
+// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
+func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
+ debug.Printf("consumeAddrSpec: %q", *p)
+
+ orig := *p
+ defer func() {
+ if err != nil {
+ *p = orig
+ }
+ }()
+
+ // local-part = dot-atom / quoted-string
+ var localPart string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.ErrorString("mail: no addr-spec")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ debug.Printf("consumeAddrSpec: parsing quoted-string")
+ localPart, err = p.consumeQuotedString()
+ } else {
+ // dot-atom
+ debug.Printf("consumeAddrSpec: parsing dot-atom")
+ localPart, err = p.consumeAtom(true)
+ }
+ if err != nil {
+ debug.Printf("consumeAddrSpec: failed: %v", err)
+ return "", err
+ }
+
+ if !p.consume('@') {
+ return "", os.ErrorString("mail: missing @ in addr-spec")
+ }
+
+ // domain = dot-atom / domain-literal
+ var domain string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.ErrorString("mail: no domain in addr-spec")
+ }
+ // TODO(dsymonds): Handle domain-literal
+ domain, err = p.consumeAtom(true)
+ if err != nil {
+ return "", err
+ }
+
+ return localPart + "@" + domain, nil
+}
+
+// consumePhrase parses the RFC 5322 phrase at the start of p.
+func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
+ debug.Printf("consumePhrase: [%s]", *p)
+ // phrase = 1*word
+ var words []string
+ for {
+ // word = atom / quoted-string
+ var word string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.ErrorString("mail: missing phrase")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ word, err = p.consumeQuotedString()
+ } else {
+ // atom
+ word, err = p.consumeAtom(false)
+ }
+
+ // RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
+ if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
+ word, err = decodeRFC2047Word(word)
+ }
+
+ if err != nil {
+ break
+ }
+ debug.Printf("consumePhrase: consumed %q", word)
+ words = append(words, word)
+ }
+ // Ignore any error if we got at least one word.
+ if err != nil && len(words) == 0 {
+ debug.Printf("consumePhrase: hit err: %v", err)
+ return "", os.ErrorString("mail: missing word in phrase")
+ }
+ phrase = strings.Join(words, " ")
+ return phrase, nil
+}
+
+// consumeQuotedString parses the quoted string at the start of p.
+func (p *addrParser) consumeQuotedString() (qs string, err os.Error) {
+ // Assume first byte is '"'.
+ i := 1
+ qsb := make([]byte, 0, 10)
+Loop:
+ for {
+ if i >= p.len() {
+ return "", os.ErrorString("mail: unclosed quoted-string")
+ }
+ switch c := (*p)[i]; {
+ case c == '"':
+ break Loop
+ case c == '\\':
+ if i+1 == p.len() {
+ return "", os.ErrorString("mail: unclosed quoted-string")
+ }
+ qsb = append(qsb, (*p)[i+1])
+ i += 2
+ case isQtext(c), c == ' ' || c == '\t':
+ // qtext (printable US-ASCII excluding " and \), or
+ // FWS (almost; we're ignoring CRLF)
+ qsb = append(qsb, c)
+ i++
+ default:
+ return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
+ }
+ }
+ *p = (*p)[i+1:]
+ return string(qsb), nil
+}
+
+// consumeAtom parses an RFC 5322 atom at the start of p.
+// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
+func (p *addrParser) consumeAtom(dot bool) (atom string, err os.Error) {
+ if !isAtext(p.peek(), false) {
+ return "", os.ErrorString("mail: invalid string")
+ }
+ i := 1
+ for ; i < p.len() && isAtext((*p)[i], dot); i++ {
+ }
+ // TODO(dsymonds): Remove the []byte() conversion here when 6g doesn't need it.
+ atom, *p = string([]byte((*p)[:i])), (*p)[i:]
+ return atom, nil
+}
+
+func (p *addrParser) consume(c byte) bool {
+ if p.empty() || p.peek() != c {
+ return false
+ }
+ *p = (*p)[1:]
+ return true
+}
+
+// skipSpace skips the leading space and tab characters.
+func (p *addrParser) skipSpace() {
+ *p = bytes.TrimLeft(*p, " \t")
+}
+
+func (p *addrParser) peek() byte {
+ return (*p)[0]
+}
+
+func (p *addrParser) empty() bool {
+ return p.len() == 0
+}
+
+func (p *addrParser) len() int {
+ return len(*p)
+}
+
+func decodeRFC2047Word(s string) (string, os.Error) {
+ fields := strings.Split(s, "?", -1)
+ if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
+ return "", os.ErrorString("mail: address not RFC 2047 encoded")
+ }
+ charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
+ // TODO(dsymonds): Support "b" encoding too.
+ if enc != "q" {
+ return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ }
+ if charset != "iso-8859-1" && charset != "utf-8" {
+ return "", fmt.Errorf("mail: charset not supported: %q", charset)
+ }
+
+ in := fields[3]
+ b := new(bytes.Buffer)
+ for i := 0; i < len(in); i++ {
+ switch c := in[i]; {
+ case c == '=' && i+2 < len(in):
+ x, err := strconv.Btoi64(in[i+1:i+3], 16)
+ if err != nil {
+ return "", fmt.Errorf("mail: invalid RFC 2047 encoding: %q", in[i:i+3])
+ }
+ i += 2
+ switch charset {
+ case "iso-8859-1":
+ b.WriteRune(int(x))
+ case "utf-8":
+ b.WriteByte(byte(x))
+ }
+ case c == '_':
+ b.WriteByte(' ')
+ default:
+ b.WriteByte(c)
+ }
+ }
+ return b.String(), nil
+}
+
+var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "abcdefghijklmnopqrstuvwxyz" +
+ "0123456789" +
+ "!#$%&'*+-/=?^_`{|}~")
+
+// isAtext returns true if c is an RFC 5322 atext character.
+// If dot is true, period is included.
+func isAtext(c byte, dot bool) bool {
+ if dot && c == '.' {
+ return true
+ }
+ return bytes.IndexByte(atextChars, c) >= 0
+}
+
+// isQtext returns true if c is an RFC 5322 qtest character.
+func isQtext(c byte) bool {
+ // Printable US-ASCII, excluding backslash or quote.
+ if c == '\\' || c == '"' {
+ return false
+ }
+ return '!' <= c && c <= '~'
+}
+
+// isVchar returns true if c is an RFC 5322 VCHAR character.
+func isVchar(c byte) bool {
+ // Visible (printing) characters.
+ return '!' <= c && c <= '~'
+}
diff --git a/src/pkg/mail/message_test.go b/src/pkg/mail/message_test.go
index 1d1c6352e..1ff45d2c1 100644
--- a/src/pkg/mail/message_test.go
+++ b/src/pkg/mail/message_test.go
@@ -127,3 +127,132 @@ func TestDateParsing(t *testing.T) {
}
}
}
+
+func TestAddressParsing(t *testing.T) {
+ tests := []struct {
+ addrsStr string
+ exp []*Address
+ }{
+ // Bare address
+ {
+ `jdoe@machine.example`,
+ []*Address{&Address{
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.1
+ {
+ `John Doe <jdoe@machine.example>`,
+ []*Address{&Address{
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.2
+ {
+ `"Joe Q. Public" <john.q.public@example.com>`,
+ []*Address{&Address{
+ Name: "Joe Q. Public",
+ Address: "john.q.public@example.com",
+ }},
+ },
+ {
+ `Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>`,
+ []*Address{
+ &Address{
+ Name: "Mary Smith",
+ Address: "mary@x.test",
+ },
+ &Address{
+ Address: "jdoe@example.org",
+ },
+ &Address{
+ Name: "Who?",
+ Address: "one@y.test",
+ },
+ },
+ },
+ {
+ `<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>`,
+ []*Address{
+ &Address{
+ Address: "boss@nil.test",
+ },
+ &Address{
+ Name: `Giant; "Big" Box`,
+ Address: "sysservices@example.net",
+ },
+ },
+ },
+ // RFC 5322, Appendix A.1.3
+ // TODO(dsymonds): Group addresses.
+
+ // RFC 2047 "Q"-encoded ISO-8859-1 address.
+ {
+ `=?iso-8859-1?q?J=F6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047 "Q"-encoded UTF-8 address.
+ {
+ `=?utf-8?q?J=C3=B6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047, Section 8.
+ {
+ `=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
+ []*Address{
+ &Address{
+ Name: `André Pirard`,
+ Address: "PIRARD@vm1.ulg.ac.be",
+ },
+ },
+ },
+ }
+ for _, test := range tests {
+ addrs, err := newAddrParser(test.addrsStr).parseAddressList()
+ if err != nil {
+ t.Errorf("Failed parsing %q: %v", test.addrsStr, err)
+ continue
+ }
+ if !reflect.DeepEqual(addrs, test.exp) {
+ t.Errorf("Parse of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
+ }
+ }
+}
+
+func TestAddressFormatting(t *testing.T) {
+ tests := []struct {
+ addr *Address
+ exp string
+ }{
+ {
+ &Address{Address: "bob@example.com"},
+ "<bob@example.com>",
+ },
+ {
+ &Address{Name: "Bob", Address: "bob@example.com"},
+ `"Bob" <bob@example.com>`,
+ },
+ {
+ // note the ö (o with an umlaut)
+ &Address{Name: "Böb", Address: "bob@example.com"},
+ `=?utf-8?q?B=C3=B6b?= <bob@example.com>`,
+ },
+ }
+ for _, test := range tests {
+ s := test.addr.String()
+ if s != test.exp {
+ t.Errorf("Address%+v.String() = %v, want %v", *test.addr, s, test.exp)
+ }
+ }
+}
diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile
index 71347b7fa..8e8e74ae4 100644
--- a/src/pkg/math/Makefile
+++ b/src/pkg/math/Makefile
@@ -6,6 +6,9 @@ include ../../Make.inc
TARG=math
+OFILES_arm=\
+ sqrt_arm.$O\
+
OFILES_amd64=\
exp_amd64.$O\
fabs_amd64.$O\
diff --git a/src/pkg/math/sqrt_arm.s b/src/pkg/math/sqrt_arm.s
new file mode 100644
index 000000000..befbb8a89
--- /dev/null
+++ b/src/pkg/math/sqrt_arm.s
@@ -0,0 +1,10 @@
+// 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.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ MOVD x+0(FP),F0
+ SQRTD F0,F0
+ MOVD F0,r+8(FP)
+ RET
diff --git a/src/pkg/math/sqrt_port.go b/src/pkg/math/sqrt_port.go
index 83af255bf..148239bcf 100644
--- a/src/pkg/math/sqrt_port.go
+++ b/src/pkg/math/sqrt_port.go
@@ -141,3 +141,7 @@ func sqrtGo(x float64) float64 {
ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return Float64frombits(ix)
}
+
+func sqrtGoC(f float64, r *float64) {
+ *r = sqrtGo(f)
+}
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
index d4adbffc0..5472df392 100644
--- a/src/pkg/net/Makefile
+++ b/src/pkg/net/Makefile
@@ -10,6 +10,7 @@ GOFILES=\
dnsmsg.go\
fd_$(GOOS).go\
hosts.go\
+ interface.go\
ip.go\
ipsock.go\
iprawsock.go\
@@ -27,6 +28,7 @@ GOFILES_freebsd=\
dnsconfig.go\
fd.go\
file.go\
+ interface_bsd.go\
newpollserver.go\
port.go\
sendfile_stub.go\
@@ -41,6 +43,7 @@ GOFILES_darwin=\
dnsconfig.go\
fd.go\
file.go\
+ interface_bsd.go\
newpollserver.go\
port.go\
sendfile_stub.go\
@@ -55,12 +58,14 @@ GOFILES_linux=\
dnsconfig.go\
fd.go\
file.go\
+ interface_linux.go\
newpollserver.go\
port.go\
sendfile_linux.go\
sock_linux.go\
GOFILES_plan9=\
+ interface_stub.go\
sendfile_stub.go\
ifeq ($(GOARCH),arm)
@@ -75,6 +80,7 @@ endif
GOFILES_windows=\
cgo_stub.go\
file_windows.go\
+ interface_stub.go\
resolv_windows.go\
sendfile_stub.go\
sock_windows.go\
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
new file mode 100644
index 000000000..f622487ab
--- /dev/null
+++ b/src/pkg/net/interface.go
@@ -0,0 +1,89 @@
+// 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.
+
+// Network interface identification
+
+package net
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+)
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ var buf bytes.Buffer
+ for i, b := range a {
+ if i > 0 {
+ buf.WriteByte(':')
+ }
+ fmt.Fprintf(&buf, "%02x", b)
+ }
+ return buf.String()
+}
+
+// Interface represents a mapping between network interface name
+// and index. It also represents network interface facility
+// information.
+type Interface struct {
+ Index int // positive integer that starts at one, zero is never used
+ MTU int // maximum transmission unit
+ Name string // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
+ rawFlags int
+}
+
+// Addrs returns interface addresses for a specific interface.
+func (ifi *Interface) Addrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceAddrTable(ifi.Index)
+}
+
+// Interfaces returns a list of the systems's network interfaces.
+func Interfaces() ([]Interface, os.Error) {
+ return interfaceTable(0)
+}
+
+// InterfaceAddrs returns a list of the system's network interface
+// addresses.
+func InterfaceAddrs() ([]Addr, os.Error) {
+ return interfaceAddrTable(0)
+}
+
+// InterfaceByIndex returns the interface specified by index.
+func InterfaceByIndex(index int) (*Interface, os.Error) {
+ if index <= 0 {
+ return nil, os.NewError("net: invalid interface index")
+ }
+ ift, err := interfaceTable(index)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ return &ifi, nil
+ }
+ return nil, os.NewError("net: no such interface")
+}
+
+// InterfaceByName returns the interface specified by name.
+func InterfaceByName(name string) (*Interface, os.Error) {
+ if name == "" {
+ return nil, os.NewError("net: invalid interface name")
+ }
+ ift, err := interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ if name == ifi.Name {
+ return &ifi, nil
+ }
+ }
+ return nil, os.NewError("net: no such interface")
+}
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
new file mode 100644
index 000000000..141b95b38
--- /dev/null
+++ b/src/pkg/net/interface_bsd.go
@@ -0,0 +1,195 @@
+// 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.
+
+// Network interface identification for BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// IsUp returns true if ifi is up.
+func (ifi *Interface) IsUp() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_UP != 0
+}
+
+// IsLoopback returns true if ifi is a loopback interface.
+func (ifi *Interface) IsLoopback() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_LOOPBACK != 0
+}
+
+// CanBroadcast returns true if ifi supports a broadcast access
+// capability.
+func (ifi *Interface) CanBroadcast() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_BROADCAST != 0
+}
+
+// IsPointToPoint returns true if ifi belongs to a point-to-point
+// link.
+func (ifi *Interface) IsPointToPoint() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0
+}
+
+// CanMulticast returns true if ifi supports a multicast access
+// capability.
+func (ifi *Interface) CanMulticast() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_MULTICAST != 0
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ift []Interface
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifi, err := newLink(v)
+ if err != nil {
+ return nil, err
+ }
+ ift = append(ift, ifi...)
+ }
+ }
+ }
+
+ return ift, nil
+}
+
+func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
+ var ift []Interface
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrDatalink:
+ // NOTE: SockaddrDatalink.Data is minimum work area,
+ // can be larger.
+ m.Data = m.Data[unsafe.Offsetof(v.Data):]
+ ifi := Interface{Index: int(m.Header.Index), rawFlags: int(m.Header.Flags)}
+ var name [syscall.IFNAMSIZ]byte
+ for i := 0; i < int(v.Nlen); i++ {
+ name[i] = byte(m.Data[i])
+ }
+ ifi.Name = string(name[:v.Nlen])
+ ifi.MTU = int(m.Header.Data.Mtu)
+ addr := make([]byte, v.Alen)
+ for i := 0; i < int(v.Alen); i++ {
+ addr[i] = byte(m.Data[int(v.Nlen)+i])
+ }
+ ifi.HardwareAddr = addr[:v.Alen]
+ ift = append(ift, ifi)
+ }
+ }
+
+ return ift, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifa, err := newAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifat = append(ifat, ifa...)
+ }
+ }
+ }
+
+ return ifat, nil
+}
+
+func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ var ifa IPAddr
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ case *syscall.SockaddrInet6:
+ ifa.IP = make(IP, IPv6len)
+ copy(ifa.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifa.IP.IsLinkLocalUnicast() ||
+ ifa.IP.IsInterfaceLocalMulticast() ||
+ ifa.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifa.IP[2], ifa.IP[3] = 0, 0
+ }
+ }
+ ifat = append(ifat, ifa.toAddr())
+ }
+
+ return ifat, nil
+}
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
new file mode 100644
index 000000000..5c9657834
--- /dev/null
+++ b/src/pkg/net/interface_linux.go
@@ -0,0 +1,208 @@
+// 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.
+
+// Network interface identification for Linux
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// IsUp returns true if ifi is up.
+func (ifi *Interface) IsUp() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_UP != 0
+}
+
+// IsLoopback returns true if ifi is a loopback interface.
+func (ifi *Interface) IsLoopback() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_LOOPBACK != 0
+}
+
+// CanBroadcast returns true if ifi supports a broadcast access
+// capability.
+func (ifi *Interface) CanBroadcast() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_BROADCAST != 0
+}
+
+// IsPointToPoint returns true if ifi belongs to a point-to-point
+// link.
+func (ifi *Interface) IsPointToPoint() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0
+}
+
+// CanMulticast returns true if ifi supports a multicast access
+// capability.
+func (ifi *Interface) CanMulticast() bool {
+ if ifi == nil {
+ return false
+ }
+ return ifi.rawFlags&syscall.IFF_MULTICAST != 0
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ ift []Interface
+ tab []byte
+ msgs []syscall.NetlinkMessage
+ e int
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+
+ msgs, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWLINK:
+ ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifim.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifi := newLink(attrs, ifim)
+ ift = append(ift, ifi)
+ }
+ }
+ }
+
+done:
+ return ift, nil
+}
+
+func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+ ifi := Interface{Index: int(ifim.Index), rawFlags: int(ifim.Flags)}
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFLA_ADDRESS:
+ var nonzero bool
+ for _, b := range a.Value {
+ if b != 0 {
+ nonzero = true
+ }
+ }
+ if nonzero {
+ ifi.HardwareAddr = a.Value[:]
+ }
+ case syscall.IFLA_IFNAME:
+ ifi.Name = string(a.Value[:])
+ case syscall.IFLA_MTU:
+ ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
+ }
+ }
+ return ifi
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ ifat4 []Addr
+ ifat6 []Addr
+ tab []byte
+ msgs4 []syscall.NetlinkMessage
+ msgs6 []syscall.NetlinkMessage
+ e int
+ err os.Error
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs4, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat4, err = addrTable(msgs4, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs6, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat6, err = addrTable(msgs6, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(ifat4, ifat6...), nil
+}
+
+func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWADDR:
+ ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifam.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ }
+ }
+ }
+
+done:
+ return ifat, nil
+}
+
+func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
+ var ifat []Addr
+
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFA_ADDRESS:
+ ifa := IPAddr{}
+ switch family {
+ case syscall.AF_INET:
+ ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+ case syscall.AF_INET6:
+ ifa.IP = make(IP, IPv6len)
+ copy(ifa.IP, a.Value[:])
+ }
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+
+ return ifat
+}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
new file mode 100644
index 000000000..feb871bb5
--- /dev/null
+++ b/src/pkg/net/interface_stub.go
@@ -0,0 +1,51 @@
+// 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.
+
+// Network interface identification
+
+package net
+
+import "os"
+
+// IsUp returns true if ifi is up.
+func (ifi *Interface) IsUp() bool {
+ return false
+}
+
+// IsLoopback returns true if ifi is a loopback interface.
+func (ifi *Interface) IsLoopback() bool {
+ return false
+}
+
+// CanBroadcast returns true if ifi supports a broadcast access
+// capability.
+func (ifi *Interface) CanBroadcast() bool {
+ return false
+}
+
+// IsPointToPoint returns true if ifi belongs to a point-to-point
+// link.
+func (ifi *Interface) IsPointToPoint() bool {
+ return false
+}
+
+// CanMulticast returns true if ifi supports a multicast access
+// capability.
+func (ifi *Interface) CanMulticast() bool {
+ return false
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
new file mode 100644
index 000000000..938434623
--- /dev/null
+++ b/src/pkg/net/interface_test.go
@@ -0,0 +1,90 @@
+// 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 net
+
+import (
+ "bytes"
+ "testing"
+)
+
+func sameInterface(i, j *Interface) bool {
+ if i == nil || j == nil {
+ return false
+ }
+ if i.Index == j.Index && i.Name == j.Name && bytes.Equal(i.HardwareAddr, j.HardwareAddr) {
+ return true
+ }
+ return false
+}
+
+func interfaceFlagsString(ifi *Interface) string {
+ fs := "<"
+ if ifi.IsUp() {
+ fs += "UP,"
+ }
+ if ifi.CanBroadcast() {
+ fs += "BROADCAST,"
+ }
+ if ifi.IsLoopback() {
+ fs += "LOOPBACK,"
+ }
+ if ifi.IsPointToPoint() {
+ fs += "POINTOPOINT,"
+ }
+ if ifi.CanMulticast() {
+ fs += "MULTICAST,"
+ }
+ if len(fs) > 1 {
+ fs = fs[:len(fs)-1]
+ }
+ fs += ">"
+ return fs
+}
+
+func TestInterfaces(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
+
+ for _, ifi := range ift {
+ ifxi, err := InterfaceByIndex(ifi.Index)
+ if err != nil {
+ t.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+ }
+ if !sameInterface(ifxi, &ifi) {
+ t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+ }
+ ifxn, err := InterfaceByName(ifi.Name)
+ if err != nil {
+ t.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+ }
+ if !sameInterface(ifxn, &ifi) {
+ t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatalf("Interface.Addrs() failed: %v", err)
+ }
+ t.Logf("%s: flags %s, ifindex %v, mtu %v\n", ifi.Name, interfaceFlagsString(&ifi), ifi.Index, ifi.MTU)
+ for _, ifa := range ifat {
+ t.Logf("\tinterface address %s\n", ifa.String())
+ }
+ t.Logf("\thardware address %v", ifi.HardwareAddr.String())
+ }
+}
+
+func TestInterfaceAddrs(t *testing.T) {
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatalf("InterfaceAddrs() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+
+ for _, ifa := range ifat {
+ t.Logf("interface address %s\n", ifa.String())
+ }
+}
diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go
index 0a700ca2b..7d96228c4 100644
--- a/src/pkg/netchan/import.go
+++ b/src/pkg/netchan/import.go
@@ -11,6 +11,7 @@ import (
"os"
"reflect"
"sync"
+ "time"
)
// Import
@@ -31,6 +32,9 @@ type Importer struct {
chans map[int]*netChan
errors chan os.Error
maxId int
+ mu sync.Mutex // protects remaining fields
+ unacked int64 // number of unacknowledged sends.
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
}
// NewImporter creates a new Importer object to import a set of channels
@@ -42,6 +46,7 @@ func NewImporter(conn io.ReadWriter) *Importer {
imp.chans = make(map[int]*netChan)
imp.names = make(map[string]*netChan)
imp.errors = make(chan os.Error, 10)
+ imp.unacked = 0
go imp.run()
return imp
}
@@ -80,8 +85,10 @@ func (imp *Importer) run() {
for {
*hdr = header{}
if e := imp.decode(hdrValue); e != nil {
- impLog("header:", e)
- imp.shutdown()
+ if e != os.EOF {
+ impLog("header:", e)
+ imp.shutdown()
+ }
return
}
switch hdr.PayloadType {
@@ -114,6 +121,9 @@ func (imp *Importer) run() {
nch := imp.getChan(hdr.Id, true)
if nch != nil {
nch.acked()
+ imp.mu.Lock()
+ imp.unacked--
+ imp.mu.Unlock()
}
continue
default:
@@ -220,10 +230,17 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size,
}
return
}
+ // We hold the lock during transmission to guarantee messages are
+ // sent in order.
+ imp.mu.Lock()
+ imp.unacked++
+ imp.seqLock.Lock()
+ imp.mu.Unlock()
if err = imp.encode(hdr, payData, val.Interface()); err != nil {
impLog("error encoding client send:", err)
return
}
+ imp.seqLock.Unlock()
}
}()
}
@@ -244,3 +261,27 @@ func (imp *Importer) Hangup(name string) os.Error {
nc.close()
return nil
}
+
+func (imp *Importer) unackedCount() int64 {
+ imp.mu.Lock()
+ n := imp.unacked
+ imp.mu.Unlock()
+ return n
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any server and possibly including those sent while
+// Drain was executing, have been received by the exporter. In short, it
+// waits until all the importer's messages have been received.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (imp *Importer) Drain(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ for imp.unackedCount() > 0 {
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.ErrorString("timeout")
+ }
+ time.Sleep(100 * 1e6)
+ }
+ return nil
+}
diff --git a/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go
index fd4d8f780..8c0f9a6e4 100644
--- a/src/pkg/netchan/netchan_test.go
+++ b/src/pkg/netchan/netchan_test.go
@@ -178,6 +178,16 @@ func TestExportDrain(t *testing.T) {
<-done
}
+// Not a great test but it does at least invoke Drain.
+func TestImportDrain(t *testing.T) {
+ exp, imp := pair(t)
+ expDone := make(chan bool)
+ go exportReceive(exp, t, expDone)
+ <-expDone
+ importSend(imp, closeCount, t, nil)
+ imp.Drain(0)
+}
+
// Not a great test but it does at least invoke Sync.
func TestExportSync(t *testing.T) {
exp, imp := pair(t)
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index c781df7af..497e5a958 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -27,6 +27,7 @@ GOFILES_freebsd=\
sys_bsd.go\
exec_posix.go\
exec_unix.go\
+ signal_unix.go\
GOFILES_darwin=\
dir_unix.go\
@@ -38,6 +39,7 @@ GOFILES_darwin=\
sys_bsd.go\
exec_posix.go\
exec_unix.go\
+ signal_unix.go\
GOFILES_linux=\
dir_unix.go\
@@ -49,6 +51,7 @@ GOFILES_linux=\
sys_linux.go\
exec_posix.go\
exec_unix.go\
+ signal_unix.go\
GOFILES_windows=\
dir_windows.go\
@@ -60,6 +63,7 @@ GOFILES_windows=\
sys_windows.go\
exec_posix.go\
exec_windows.go\
+ signal_windows.go\
GOFILES_plan9=\
dir_plan9.go\
@@ -72,4 +76,12 @@ GOFILES_plan9=\
GOFILES+=$(GOFILES_$(GOOS))
+CLEANFILES+=signal_unix.go signal_windows.go
+
include ../../Make.pkg
+
+signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go
+ ./mkunixsignals.sh $< > $@ || rm -f $@
+
+signal_windows.go: ../syscall/ztypes_$(GOOS)_$(GOARCH).go
+ ./mkunixsignals.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/env_plan9.go b/src/pkg/os/env_plan9.go
index 14df55ed0..1fed89f92 100644
--- a/src/pkg/os/env_plan9.go
+++ b/src/pkg/os/env_plan9.go
@@ -23,13 +23,18 @@ func Getenverror(key string) (value string, err Error) {
}
defer f.Close()
- var buf [4096]byte
- n, e := f.Read(buf[:len(buf)-1])
+ l, _ := f.Seek(0, 2)
+ f.Seek(0, 0)
+ buf := make([]byte, l)
+ n, e := f.Read(buf)
if iserror(e) {
return "", ENOENV
}
- buf[n] = 0
- return string(buf[0:n]), nil
+
+ if n > 0 && buf[n-1] == 0 {
+ buf = buf[:n-1]
+ }
+ return string(buf), nil
}
// Getenv retrieves the value of the environment variable named by the key.
@@ -52,7 +57,7 @@ func Setenv(key, value string) Error {
}
defer f.Close()
- _, e = f.Write(syscall.StringByteSlice(value))
+ _, e = f.Write([]byte(value))
return nil
}
diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go
index 0ee34e4b0..d43f1786d 100644
--- a/src/pkg/os/error_posix.go
+++ b/src/pkg/os/error_posix.go
@@ -13,7 +13,7 @@ type Errno int64
func (e Errno) String() string { return syscall.Errstr(int(e)) }
func (e Errno) Temporary() bool {
- return e == Errno(syscall.EINTR) || e.Timeout()
+ return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout()
}
func (e Errno) Timeout() bool {
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index 9102dc0a4..bf992ef42 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -4,7 +4,25 @@
package os
-import "syscall"
+import (
+ "runtime"
+ "syscall"
+)
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+ String() string
+}
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+ s := runtime.Signame(int32(sig))
+ if len(s) > 0 {
+ return s
+ }
+ return "UnixSignal"
+}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
@@ -34,6 +52,11 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
return newProcess(pid, h), nil
}
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ return p.Signal(SIGKILL)
+}
+
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 8990d6a97..cf5ea9b61 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_unix.go
@@ -45,6 +45,14 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
return w, nil
}
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
+ return Errno(e)
+ }
+ return nil
+}
+
// Release releases any resources associated with the Process.
func (p *Process) Release() Error {
// NOOP for unix.
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index ae8ffeab2..bac33b908 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -20,13 +20,23 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
return nil, ErrorString("os: unexpected result from WaitForSingleObject")
}
var ec uint32
- e = syscall.GetExitCodeProcess(uint32(p.handle), &ec)
+ e = syscall.GetExitCodeProcess(int32(p.handle), &ec)
if e != 0 {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
}
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ switch sig.(UnixSignal) {
+ case SIGKILL:
+ e := syscall.TerminateProcess(int32(p.handle), 1)
+ return NewSyscallError("TerminateProcess", e)
+ }
+ return Errno(syscall.EWINDOWS)
+}
+
func (p *Process) Release() Error {
if p.handle == -1 {
return EINVAL
diff --git a/src/pkg/os/signal/mkunix.sh b/src/pkg/os/mkunixsignals.sh
index 653b01664..6ec764cbd 100755
--- a/src/pkg/os/signal/mkunix.sh
+++ b/src/pkg/os/mkunixsignals.sh
@@ -8,7 +8,7 @@ echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
cat <<EOH
-package signal
+package os
import (
"syscall"
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile
index 013b91a85..26f58760e 100644
--- a/src/pkg/os/signal/Makefile
+++ b/src/pkg/os/signal/Makefile
@@ -7,11 +7,5 @@ include ../../../Make.inc
TARG=os/signal
GOFILES=\
signal.go\
- unix.go\
-
-CLEANFILES+=unix.go
include ../../../Make.pkg
-
-unix.go: ../../syscall/zerrors_$(GOOS)_$(GOARCH).go
- ./mkunix.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
index 666c03e73..520f3f8a9 100644
--- a/src/pkg/os/signal/signal.go
+++ b/src/pkg/os/signal/signal.go
@@ -6,35 +6,20 @@
package signal
import (
+ "os"
"runtime"
- "strconv"
)
-// A Signal can represent any operating system signal.
-type Signal interface {
- String() string
-}
-
-type UnixSignal int32
-
-func (sig UnixSignal) String() string {
- s := runtime.Signame(int32(sig))
- if len(s) > 0 {
- return s
- }
- return "Signal " + strconv.Itoa(int(sig))
-}
-
// Incoming is the global signal channel.
// All signals received by the program will be delivered to this channel.
-var Incoming <-chan Signal
+var Incoming <-chan os.Signal
-func process(ch chan<- Signal) {
+func process(ch chan<- os.Signal) {
for {
var mask uint32 = runtime.Sigrecv()
for sig := uint(0); sig < 32; sig++ {
if mask&(1<<sig) != 0 {
- ch <- UnixSignal(sig)
+ ch <- os.UnixSignal(sig)
}
}
}
@@ -42,7 +27,7 @@ func process(ch chan<- Signal) {
func init() {
runtime.Siginit()
- ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal
+ ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal
Incoming = ch
go process(ch)
}
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index f2679f14d..00eb29578 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/os/signal/signal_test.go
@@ -5,6 +5,7 @@
package signal
import (
+ "os"
"syscall"
"testing"
)
@@ -13,7 +14,7 @@ func TestSignal(t *testing.T) {
// Send this process a SIGHUP.
syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
- if sig := (<-Incoming).(UnixSignal); sig != SIGHUP {
- t.Errorf("signal was %v, want %v", sig, SIGHUP)
+ if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
+ t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
}
}
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/386/memmove.s
index 38a0652b5..471553ba2 100644
--- a/src/pkg/runtime/386/memmove.s
+++ b/src/pkg/runtime/386/memmove.s
@@ -32,7 +32,6 @@ TEXT runtime·memmove(SB), 7, $0
/*
* check and set for backwards
- * should we look closer for overlap?
*/
CMPL SI, DI
JLS back
@@ -40,6 +39,7 @@ TEXT runtime·memmove(SB), 7, $0
/*
* forward copy loop
*/
+forward:
MOVL BX, CX
SHRL $2, CX
ANDL $3, BX
@@ -51,10 +51,18 @@ TEXT runtime·memmove(SB), 7, $0
MOVL to+0(FP),AX
RET
/*
+ * check overlap
+ */
+back:
+ MOVL SI, CX
+ ADDL BX, CX
+ CMPL CX, DI
+ JLS forward
+/*
* whole thing backwards has
* adjusted addresses
*/
-back:
+
ADDL BX, DI
ADDL BX, SI
STD
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/amd64/memmove.s
index 9966b0ba7..fc9573f72 100644
--- a/src/pkg/runtime/amd64/memmove.s
+++ b/src/pkg/runtime/amd64/memmove.s
@@ -33,7 +33,6 @@ TEXT runtime·memmove(SB), 7, $0
/*
* check and set for backwards
- * should we look closer for overlap?
*/
CMPQ SI, DI
JLS back
@@ -41,6 +40,7 @@ TEXT runtime·memmove(SB), 7, $0
/*
* forward copy loop
*/
+forward:
MOVQ BX, CX
SHRQ $3, CX
ANDQ $7, BX
@@ -51,11 +51,19 @@ TEXT runtime·memmove(SB), 7, $0
MOVQ to+0(FP),AX
RET
+back:
+/*
+ * check overlap
+ */
+ MOVQ SI, CX
+ ADDQ BX, CX
+ CMPQ CX, DI
+ JLS forward
+
/*
* whole thing backwards has
* adjusted addresses
*/
-back:
ADDQ BX, DI
ADDQ BX, SI
STD
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c
index f91a6fc09..0a071dada 100644
--- a/src/pkg/runtime/arm/softfloat.c
+++ b/src/pkg/runtime/arm/softfloat.c
@@ -15,6 +15,7 @@
#define FLAGS_V (1 << 28)
void runtime·abort(void);
+void math·sqrtGoC(uint64, uint64*);
static uint32 trace = 0;
@@ -357,6 +358,15 @@ stage3: // regd, regm are 4bit variables
regd, regm, m->freghi[regd], m->freglo[regd]);
break;
+ case 0xeeb10bc0: // D[regd] = sqrt D[regm]
+ math·sqrtGoC(getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
m->fflag = fstatus(nan, cmp);
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index 868a0d901..e8b423324 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -47,6 +47,14 @@ TEXT runtime·setitimer(SB),7,$0-24
INT $0x80
RET
+TEXT runtime·mincore(SB),7,$0-24
+ MOVL $218, AX // syscall - mincore
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
TEXT runtime·gettime(SB), 7, $32
MOVL $78, AX // syscall - gettimeofday
LEAL 8(SP), BX
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
index eadd30005..66fdab208 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -53,6 +53,14 @@ TEXT runtime·setitimer(SB),7,$0-24
SYSCALL
RET
+TEXT runtime·mincore(SB),7,$0-24
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $27, AX // syscall entry
+ SYSCALL
+ RET
+
TEXT runtime·gettime(SB), 7, $32
LEAQ 8(SP), DI
MOVQ $0, SI
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index 2b5365bd8..ab5349822 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -26,6 +26,7 @@
#define SYS_exit_group (SYS_BASE + 248)
#define SYS_munmap (SYS_BASE + 91)
#define SYS_setitimer (SYS_BASE + 104)
+#define SYS_mincore (SYS_BASE + 219)
#define SYS_gettid (SYS_BASE + 224)
#define SYS_tkill (SYS_BASE + 238)
@@ -91,6 +92,14 @@ TEXT runtime·setitimer(SB),7,$0
SWI $0
RET
+TEXT runtime·mincore(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_mincore, R7
+ SWI $0
+ RET
+
TEXT runtime·gettime(SB),7,$32
/* dummy version - return 0,0 */
MOVW $0, R1
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index 02f798732..38ca7e4a0 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -3,6 +3,30 @@
#include "os.h"
#include "malloc.h"
+enum
+{
+ ENOMEM = 12,
+};
+
+static int32
+addrspace_free(void *v, uintptr n)
+{
+ uintptr page_size = 4096;
+ uintptr off;
+ int8 one_byte;
+
+ for(off = 0; off < n; off += page_size) {
+ int32 errval = runtime·mincore((int8 *)v + off, page_size, (void *)&one_byte);
+ // errval is 0 if success, or -(error_code) if error.
+ if (errval == 0 || errval != -ENOMEM)
+ return 0;
+ }
+ USED(v);
+ USED(n);
+ return 1;
+}
+
+
void*
runtime·SysAlloc(uintptr n)
{
@@ -54,11 +78,6 @@ runtime·SysReserve(void *v, uintptr n)
return p;
}
-enum
-{
- ENOMEM = 12,
-};
-
void
runtime·SysMap(void *v, uintptr n)
{
@@ -69,6 +88,11 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p != v && addrspace_free(v, n)) {
+ // On some systems, mmap ignores v without
+ // MAP_FIXED, so retry if the address space is free.
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ }
if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 2b2b34a3c..f3ccff1bc 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -413,6 +413,7 @@ int32 runtime·gotraceback(void);
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
void runtime·tracebackothers(G*);
int32 runtime·write(int32, void*, int32);
+int32 runtime·mincore(void*, uintptr, byte*);
bool runtime·cas(uint32*, uint32, uint32);
bool runtime·casp(void**, void*, void*);
uint32 runtime·xadd(uint32 volatile*, int32);
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index 2ce8fae15..81ad68033 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -373,7 +373,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
return &c->asmbody;
}
}
- if(cbs.n >= 20)
+ if(cbs.n >= 2000)
runtime·throw("too many callback functions");
c = runtime·mal(sizeof *c + n);
c->gobody = fn.data;
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index bbc0b2658..98b19d3a2 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -14,56 +14,68 @@ import (
const lowerhex = "0123456789abcdef"
-func quoteWith(s string, quote byte) string {
+func quoteWith(s string, quote byte, ASCIIonly bool) string {
var buf bytes.Buffer
buf.WriteByte(quote)
- for ; len(s) > 0; s = s[1:] {
- switch c := s[0]; {
- case c == quote:
+ for width := 0; len(s) > 0; s = s[width:] {
+ rune := int(s[0])
+ width = 1
+ if rune >= utf8.RuneSelf {
+ rune, width = utf8.DecodeRuneInString(s)
+ }
+ if width == 1 && rune == utf8.RuneError {
+ goto printEscX
+ }
+ if rune == int(quote) || rune == '\\' { // always backslashed
buf.WriteByte('\\')
- buf.WriteByte(quote)
- case c == '\\':
- buf.WriteString(`\\`)
- case ' ' <= c && c <= '~':
- buf.WriteString(string(c))
- case c == '\a':
+ buf.WriteByte(byte(rune))
+ continue
+ }
+ if ASCIIonly {
+ if rune <= unicode.MaxASCII && unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ } else if unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ switch rune {
+ case '\a':
buf.WriteString(`\a`)
- case c == '\b':
+ case '\b':
buf.WriteString(`\b`)
- case c == '\f':
+ case '\f':
buf.WriteString(`\f`)
- case c == '\n':
+ case '\n':
buf.WriteString(`\n`)
- case c == '\r':
+ case '\r':
buf.WriteString(`\r`)
- case c == '\t':
+ case '\t':
buf.WriteString(`\t`)
- case c == '\v':
+ case '\v':
buf.WriteString(`\v`)
-
- case c >= utf8.RuneSelf && utf8.FullRuneInString(s):
- r, size := utf8.DecodeRuneInString(s)
- if r == utf8.RuneError && size == 1 {
- goto EscX
- }
- s = s[size-1:] // next iteration will slice off 1 more
- if r < 0x10000 {
+ default:
+ switch {
+ case rune < ' ':
+ printEscX:
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ case rune > unicode.MaxRune:
+ rune = 0xFFFD
+ fallthrough
+ case rune < 0x10000:
buf.WriteString(`\u`)
- for j := uint(0); j < 4; j++ {
- buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
+ for s := 12; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
}
- } else {
+ default:
buf.WriteString(`\U`)
- for j := uint(0); j < 8; j++ {
- buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
+ for s := 28; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
}
}
-
- default:
- EscX:
- buf.WriteString(`\x`)
- buf.WriteByte(lowerhex[c>>4])
- buf.WriteByte(lowerhex[c&0xF])
}
}
buf.WriteByte(quote)
@@ -71,21 +83,38 @@ func quoteWith(s string, quote byte) string {
}
-// Quote returns a double-quoted Go string literal
-// representing s. The returned string uses Go escape
-// sequences (\t, \n, \xFF, \u0100) for control characters
-// and non-ASCII characters.
+// Quote returns a double-quoted Go string literal representing s. The
+// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// control characters and non-printable characters as defined by
+// unicode.IsPrint.
func Quote(s string) string {
- return quoteWith(s, '"')
+ return quoteWith(s, '"', false)
+}
+
+// QuoteToASCII returns a double-quoted Go string literal representing s.
+// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// non-ASCII characters and non-printable characters as defined by
+// unicode.IsPrint.
+func QuoteToASCII(s string) string {
+ return quoteWith(s, '"', true)
}
-// QuoteRune returns a single-quoted Go character literal
-// representing the rune. The returned string uses Go escape
-// sequences (\t, \n, \xFF, \u0100) for control characters
-// and non-ASCII characters.
+// QuoteRune returns a single-quoted Go character literal representing the
+// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
+// for control characters and non-printable characters as defined by
+// unicode.IsPrint.
func QuoteRune(rune int) string {
// TODO: avoid the allocation here.
- return quoteWith(string(rune), '\'')
+ return quoteWith(string(rune), '\'', false)
+}
+
+// QuoteRuneToASCII returns a single-quoted Go character literal representing
+// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
+// \u0100) for non-ASCII characters and non-printable characters as defined
+// by unicode.IsPrint.
+func QuoteRuneToASCII(rune int) string {
+ // TODO: avoid the allocation here.
+ return quoteWith(string(rune), '\'', true)
}
// CanBackquote returns whether the string s would be
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 3232d611c..4d615db44 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -11,17 +11,18 @@ import (
)
type quoteTest struct {
- in string
- out string
+ in string
+ out string
+ ascii string
}
var quotetests = []quoteTest{
- {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
- {"\\", `"\\"`},
- {"abc\xffdef", `"abc\xffdef"`},
- {"\u263a", `"\u263a"`},
- {"\U0010ffff", `"\U0010ffff"`},
- {"\x04", `"\x04"`},
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`, `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`},
+ {"\u263a", `"☺"`, `"\u263a"`},
+ {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`},
+ {"\x04", `"\x04"`, `"\x04"`},
}
func TestQuote(t *testing.T) {
@@ -32,20 +33,30 @@ func TestQuote(t *testing.T) {
}
}
+func TestQuoteToASCII(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := QuoteToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
type quoteRuneTest struct {
- in int
- out string
+ in int
+ out string
+ ascii string
}
var quoterunetests = []quoteRuneTest{
- {'a', `'a'`},
- {'\a', `'\a'`},
- {'\\', `'\\'`},
- {0xFF, `'\u00ff'`},
- {0x263a, `'\u263a'`},
- {0x0010ffff, `'\U0010ffff'`},
- {0x0010ffff + 1, `'\ufffd'`},
- {0x04, `'\x04'`},
+ {'a', `'a'`, `'a'`},
+ {'\a', `'\a'`, `'\a'`},
+ {'\\', `'\\'`, `'\\'`},
+ {0xFF, `'ÿ'`, `'\u00ff'`},
+ {0x263a, `'☺'`, `'\u263a'`},
+ {0xfffd, `'�'`, `'\ufffd'`},
+ {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`},
+ {0x0010ffff + 1, `'�'`, `'\ufffd'`},
+ {0x04, `'\x04'`, `'\x04'`},
}
func TestQuoteRune(t *testing.T) {
@@ -56,6 +67,14 @@ func TestQuoteRune(t *testing.T) {
}
}
+func TestQuoteRuneToASCII(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
type canBackquoteTest struct {
in string
out bool
@@ -110,7 +129,12 @@ func TestCanBackquote(t *testing.T) {
}
}
-var unquotetests = []quoteTest{
+type unQuoteTest struct {
+ in string
+ out string
+}
+
+var unquotetests = []unQuoteTest{
{`""`, ""},
{`"a"`, "a"},
{`"abc"`, "abc"},
diff --git a/src/pkg/sync/atomic/asm_arm.s b/src/pkg/sync/atomic/asm_arm.s
index 448a98a01..95e2f5be4 100644
--- a/src/pkg/sync/atomic/asm_arm.s
+++ b/src/pkg/sync/atomic/asm_arm.s
@@ -90,11 +90,11 @@ add64loop:
TEXT check64<>(SB),7,$16
MOVW $10, R1
// 8-aligned stack address scratch space.
- MOVW $8(SP), R3
- AND $~7, R3
+ MOVW $8(R13), R5
+ AND $~7, R5
loop:
- LDREXD (R3), R2
- STREXD R2, (R3), R0
+ LDREXD (R5), R2
+ STREXD R2, (R5), R0
CMP $0, R0
BEQ ok
SUB $1, R1
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index 9fb89f8e8..0480a6601 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_test.go
@@ -45,6 +45,7 @@ func doTestParallelReaders(numReaders, gomaxprocs int) {
}
func TestParallelReaders(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
doTestParallelReaders(1, 4)
doTestParallelReaders(3, 4)
doTestParallelReaders(4, 2)
@@ -102,6 +103,7 @@ func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
}
func TestRWMutex(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
n := 1000
if testing.Short() {
n = 5
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index bb93533bd..d01664d12 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -141,8 +141,9 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
//sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
//sys CancelIo(s uint32) (errno int)
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW
-//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int)
-//sys GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int)
+//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int)
+//sys TerminateProcess(handle int32, exitcode uint32) (errno int)
+//sys GetExitCodeProcess(handle int32, exitcode *uint32) (errno int)
//sys GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW
//sys GetCurrentProcess() (pseudoHandle int32, errno int)
//sys DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
@@ -697,10 +698,6 @@ func BindToDevice(fd int, device string) (errno int) { return
// TODO(brainman): fix all needed for os
-const (
- SIGTRAP = 5
-)
-
func Getpid() (pid int) { return -1 }
func Getppid() (ppid int) { return -1 }
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index ce36ab6c0..447b09043 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -46,6 +46,7 @@ var (
procCancelIo = getSysProcAddr(modkernel32, "CancelIo")
procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW")
procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess")
+ procTerminateProcess = getSysProcAddr(modkernel32, "TerminateProcess")
procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess")
procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW")
procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess")
@@ -542,7 +543,7 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
return
}
-func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) {
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int) {
var _p0 uint32
if inheritHandle {
_p0 = 1
@@ -550,7 +551,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errn
_p0 = 0
}
r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid))
- handle = uint32(r0)
+ handle = int32(r0)
if handle == 0 {
if e1 != 0 {
errno = int(e1)
@@ -563,7 +564,21 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errn
return
}
-func GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int) {
+func TerminateProcess(handle int32, exitcode uint32) (errno int) {
+ r1, _, e1 := Syscall(procTerminateProcess, 2, uintptr(handle), uintptr(exitcode), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetExitCodeProcess(handle int32, exitcode *uint32) (errno int) {
r1, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
if int(r1) == 0 {
if e1 != 0 {
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
index 2dec01787..ba6e590c4 100644
--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -2,10 +2,6 @@
// MACHINE GENERATED - DO NOT EDIT.
-// Manual corrections: TODO: need to fix godefs (issue 1466)
-// change Msghdr field to Iov *Iovec (was uint32/64)
-// change BpfProgram field to Insns *BpfInsn (was uint32/64)
-
package syscall
// Constants
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
index 96500d732..59c832812 100644
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -2,10 +2,6 @@
// MACHINE GENERATED - DO NOT EDIT.
-// Manual corrections: TODO: need to fix godefs (issue 1466)
-// change Msghdr field to Iov *Iovec (was uint32/64)
-// change BpfProgram field to Insns *BpfInsn (was uint32/64)
-
package syscall
// Constants
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index 7b15ea404..b04fea576 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -49,6 +49,23 @@ const (
)
const (
+ // More invented values for signals
+ SIGHUP = 0x1
+ SIGINT = 0x2
+ SIGQUIT = 0x3
+ SIGILL = 0x4
+ SIGTRAP = 0x5
+ SIGABRT = 0x6
+ SIGBUS = 0x7
+ SIGFPE = 0x8
+ SIGKILL = 0x9
+ SIGSEGV = 0xb
+ SIGPIPE = 0xd
+ SIGALRM = 0xe
+ SIGTERM = 0xf
+)
+
+const (
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
diff --git a/src/pkg/template/Makefile b/src/pkg/template/Makefile
index 4915527b4..4f1e06527 100644
--- a/src/pkg/template/Makefile
+++ b/src/pkg/template/Makefile
@@ -6,7 +6,9 @@ include ../../Make.inc
TARG=template
GOFILES=\
+ doc.go\
+ execute.go\
format.go\
- template.go\
+ parse.go\
include ../../Make.pkg
diff --git a/src/pkg/template/doc.go b/src/pkg/template/doc.go
new file mode 100644
index 000000000..e778d801d
--- /dev/null
+++ b/src/pkg/template/doc.go
@@ -0,0 +1,91 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Package template implements data-driven templates for generating textual
+ output such as HTML.
+
+ Templates are executed by applying them to a data structure.
+ Annotations in the template refer to elements of the data
+ structure (typically a field of a struct or a key in a map)
+ to control execution and derive values to be displayed.
+ The template walks the structure as it executes and the
+ "cursor" @ represents the value at the current location
+ in the structure.
+
+ Data items may be values or pointers; the interface hides the
+ indirection.
+
+ In the following, 'Field' is one of several things, according to the data.
+
+ - The name of a field of a struct (result = data.Field),
+ - The value stored in a map under that key (result = data["Field"]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.Field())
+
+ If Field is a struct field or method name, it must be an exported
+ (capitalized) name.
+
+ Major constructs ({} are the default delimiters for template actions;
+ [] are the notation in this comment for optional elements):
+
+ {# comment }
+
+ A one-line comment.
+
+ {.section field} XXX [ {.or} YYY ] {.end}
+
+ Set @ to the value of the field. It may be an explicit @
+ to stay at the same point in the data. If the field is nil
+ or empty, execute YYY; otherwise execute XXX.
+
+ {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+ Like .section, but field must be an array or slice. XXX
+ is executed for each element. If the array is nil or empty,
+ YYY is executed instead. If the {.alternates with} marker
+ is present, ZZZ is executed between iterations of XXX.
+
+ {field}
+ {field1 field2 ...}
+ {field|formatter}
+ {field1 field2...|formatter}
+ {field|formatter1|formatter2}
+
+ Insert the value of the fields into the output. Each field is
+ first looked for in the cursor, as in .section and .repeated.
+ If it is not found, the search continues in outer sections
+ until the top level is reached.
+
+ If the field value is a pointer, leading asterisks indicate
+ that the value to be inserted should be evaluated through the
+ pointer. For example, if x.p is of type *int, {x.p} will
+ insert the value of the pointer but {*x.p} will insert the
+ value of the underlying integer. If the value is nil or not a
+ pointer, asterisks have no effect.
+
+ If a formatter is specified, it must be named in the formatter
+ map passed to the template set up routines or in the default
+ set ("html","str","") and is used to process the data for
+ output. The formatter function has signature
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
+
+ Multiple formatters separated by the pipeline character | are
+ executed sequentially, with each formatter receiving the bytes
+ emitted by the one to its left.
+
+ As well as field names, one may use literals with Go syntax.
+ Integer, floating-point, and string literals are supported.
+ Raw strings may not span newlines.
+
+ The delimiter strings get their default value, "{" and "}", from
+ JSON-template. They may be set to any non-empty, space-free
+ string using the SetDelims method. Their value can be printed
+ in the output using {.meta-left} and {.meta-right}.
+*/
+package template
diff --git a/src/pkg/template/execute.go b/src/pkg/template/execute.go
new file mode 100644
index 000000000..5bc7ff7e9
--- /dev/null
+++ b/src/pkg/template/execute.go
@@ -0,0 +1,346 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code to execute a parsed template.
+
+package template
+
+import (
+ "bytes"
+ "io"
+ "reflect"
+ "strings"
+)
+
+// Internal state for executing a Template. As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+ parent *state // parent in hierarchy
+ data reflect.Value // the driver data for this section etc.
+ wr io.Writer // where to send output
+ buf [2]bytes.Buffer // alternating buffers used when chaining formatters
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent: parent, data: data, wr: parent.wr}
+}
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
+ for v.IsValid() {
+ typ := v.Type()
+ if n := v.Type().NumMethod(); n > 0 {
+ for i := 0; i < n; i++ {
+ m := typ.Method(i)
+ mtyp := m.Type
+ if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return v.Method(i).Call(nil)[0]
+ }
+ }
+ }
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ case reflect.Struct:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return av.FieldByName(name)
+ case reflect.Map:
+ if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
+ return v
+ }
+ return reflect.Zero(typ.Elem())
+ default:
+ return reflect.Value{}
+ }
+ }
+ return v
+}
+
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error. If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+ for i := numLevels; v.IsValid() && i > 0; i++ {
+ if p := v; p.Kind() == reflect.Ptr {
+ if p.IsNil() {
+ return v
+ }
+ v = p.Elem()
+ } else {
+ break
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v.IsValid() {
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ default:
+ break loop
+ }
+ }
+ return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field. Leading stars indicate
+// levels of indirection to be applied to the value.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ data := st.data
+ flattenedName := strings.TrimLeft(s, "*")
+ numStars := len(s) - len(flattenedName)
+ s = flattenedName
+ if s == "@" {
+ return indirectPtr(data, numStars)
+ }
+ for _, elem := range strings.Split(s, ".", -1) {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if !data.IsValid() {
+ return reflect.Value{}
+ }
+ }
+ return indirectPtr(data, numStars)
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if !v.IsValid() {
+ return true
+ }
+ switch v.Kind() {
+ case reflect.Bool:
+ return v.Bool() == false
+ case reflect.String:
+ return v.String() == ""
+ case reflect.Struct:
+ return false
+ case reflect.Map:
+ return false
+ case reflect.Array:
+ return v.Len() == 0
+ case reflect.Slice:
+ return v.Len() == 0
+ }
+ return false
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+ field := t.findVar(st, name)
+ if !field.IsValid() {
+ if st.parent == nil {
+ t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+ }
+ return t.varValue(name, st.parent)
+ }
+ return field
+}
+
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+ fn := t.formatter(fmt)
+ if fn == nil {
+ t.execError(st, v.linenum, "missing formatter %s for variable", fmt)
+ }
+ fn(wr, fmt, val...)
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+ // Resolve field names
+ val := make([]interface{}, len(v.args))
+ for i, arg := range v.args {
+ if name, ok := arg.(fieldName); ok {
+ val[i] = t.varValue(string(name), st).Interface()
+ } else {
+ val[i] = arg
+ }
+ }
+ for i, fmt := range v.fmts[:len(v.fmts)-1] {
+ b := &st.buf[i&1]
+ b.Reset()
+ t.format(b, fmt, val, v, st)
+ val = val[0:1]
+ val[0] = b.Bytes()
+ }
+ t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems[i].(type) {
+ case *textElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *literalElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *variableElement:
+ t.writeVariable(elem, st)
+ return i + 1
+ case *sectionElement:
+ t.executeSection(elem, st)
+ return elem.end
+ case *repeatedElement:
+ t.executeRepeated(elem, st)
+ return elem.end
+ }
+ e := t.elems[i]
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
+ return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(s.field, st)
+ if !field.IsValid() {
+ t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+ }
+ st = st.clone(field)
+ start, end := s.start, s.or
+ if !empty(field) {
+ // Execute the normal block.
+ if end < 0 {
+ end = s.end
+ }
+ } else {
+ // Execute the .or block. If it's missing, do nothing.
+ start, end = s.or, s.end
+ if start < 0 {
+ return
+ }
+ }
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) reflect.Value {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type()
+ // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+ if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+ continue
+ }
+ ct := ft.Out(0)
+ if ct.Kind() != reflect.Chan ||
+ ct.ChanDir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0]
+ }
+ return reflect.Value{}
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(r.field, st)
+ if !field.IsValid() {
+ t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+ }
+ field = indirect(field)
+
+ start, end := r.start, r.or
+ if end < 0 {
+ end = r.end
+ }
+ if r.altstart >= 0 {
+ end = r.altstart
+ }
+ first := true
+
+ // Code common to all the loops.
+ loopBody := func(newst *state) {
+ // .alternates between elements
+ if !first && r.altstart >= 0 {
+ for i := r.altstart; i < r.altend; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ first = false
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+
+ if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Index(j)))
+ }
+ } else if m := field; m.Kind() == reflect.Map {
+ for _, key := range m.MapKeys() {
+ loopBody(st.clone(m.MapIndex(key)))
+ }
+ } else if ch := iter(field); ch.IsValid() {
+ for {
+ e, ok := ch.Recv()
+ if !ok {
+ break
+ }
+ loopBody(st.clone(e))
+ }
+ } else {
+ t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+ r.field, field.Type())
+ }
+
+ if first {
+ // Empty. Execute the .or block, once. If it's missing, do nothing.
+ start, end := r.or, r.end
+ if start >= 0 {
+ newst := st.clone(field)
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ return
+ }
+}
+
+// A valid delimiter must contain no space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if isSpace(c) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/template/template.go b/src/pkg/template/parse.go
index f481cbd1e..b4aa5fcd2 100644
--- a/src/pkg/template/template.go
+++ b/src/pkg/template/parse.go
@@ -2,97 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
- Package template implements data-driven templates for generating textual
- output such as HTML.
+// Code to parse a template.
- Templates are executed by applying them to a data structure.
- Annotations in the template refer to elements of the data
- structure (typically a field of a struct or a key in a map)
- to control execution and derive values to be displayed.
- The template walks the structure as it executes and the
- "cursor" @ represents the value at the current location
- in the structure.
-
- Data items may be values or pointers; the interface hides the
- indirection.
-
- In the following, 'Field' is one of several things, according to the data.
-
- - The name of a field of a struct (result = data.Field),
- - The value stored in a map under that key (result = data["Field"]), or
- - The result of invoking a niladic single-valued method with that name
- (result = data.Field())
-
- If Field is a struct field or method name, it must be an exported
- (capitalized) name.
-
- Major constructs ({} are the default delimiters for template actions;
- [] are the notation in this comment for optional elements):
-
- {# comment }
-
- A one-line comment.
-
- {.section field} XXX [ {.or} YYY ] {.end}
-
- Set @ to the value of the field. It may be an explicit @
- to stay at the same point in the data. If the field is nil
- or empty, execute YYY; otherwise execute XXX.
-
- {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
-
- Like .section, but field must be an array or slice. XXX
- is executed for each element. If the array is nil or empty,
- YYY is executed instead. If the {.alternates with} marker
- is present, ZZZ is executed between iterations of XXX.
-
- {field}
- {field1 field2 ...}
- {field|formatter}
- {field1 field2...|formatter}
- {field|formatter1|formatter2}
-
- Insert the value of the fields into the output. Each field is
- first looked for in the cursor, as in .section and .repeated.
- If it is not found, the search continues in outer sections
- until the top level is reached.
-
- If the field value is a pointer, leading asterisks indicate
- that the value to be inserted should be evaluated through the
- pointer. For example, if x.p is of type *int, {x.p} will
- insert the value of the pointer but {*x.p} will insert the
- value of the underlying integer. If the value is nil or not a
- pointer, asterisks have no effect.
-
- If a formatter is specified, it must be named in the formatter
- map passed to the template set up routines or in the default
- set ("html","str","") and is used to process the data for
- output. The formatter function has signature
- func(wr io.Writer, formatter string, data ...interface{})
- where wr is the destination for output, data holds the field
- values at the instantiation, and formatter is its name at
- the invocation site. The default formatter just concatenates
- the string representations of the fields.
-
- Multiple formatters separated by the pipeline character | are
- executed sequentially, with each formatter receiving the bytes
- emitted by the one to its left.
-
- As well as field names, one may use literals with Go syntax.
- Integer, floating-point, and string literals are supported.
- Raw strings may not span newlines.
-
- The delimiter strings get their default value, "{" and "}", from
- JSON-template. They may be set to any non-empty, space-free
- string using the SetDelims method. Their value can be printed
- in the output using {.meta-left} and {.meta-right}.
-*/
package template
import (
- "bytes"
- "container/vector"
"fmt"
"io"
"io/ioutil"
@@ -113,6 +27,19 @@ type Error struct {
func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+ if v := recover(); v != nil {
+ if e, ok := v.(*Error); ok {
+ *error = e
+ } else {
+ // runtime errors should crash
+ panic(v)
+ }
+ }
+}
+
// Most of the literals are aces.
var lbrace = []byte{'{'}
var rbrace = []byte{'}'}
@@ -192,21 +119,7 @@ type Template struct {
p int // position in buf
linenum int // position in input
// Parsed results:
- elems *vector.Vector
-}
-
-// Internal state for executing a Template. As we evaluate the struct,
-// the data item descends into the fields associated with sections, etc.
-// Parent is used to walk upwards to find variables higher in the tree.
-type state struct {
- parent *state // parent in hierarchy
- data reflect.Value // the driver data for this section etc.
- wr io.Writer // where to send output
- buf [2]bytes.Buffer // alternating buffers used when chaining formatters
-}
-
-func (parent *state) clone(data reflect.Value) *state {
- return &state{parent: parent, data: data, wr: parent.wr}
+ elems []interface{}
}
// New creates a new template with the specified formatter map (which
@@ -216,7 +129,7 @@ func New(fmap FormatterMap) *Template {
t.fmap = fmap
t.ldelim = lbrace
t.rdelim = rbrace
- t.elems = new(vector.Vector)
+ t.elems = make([]interface{}, 0, 16)
return t
}
@@ -583,24 +496,24 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
case tokComment:
return
case tokText:
- t.elems.Push(&textElement{item})
+ t.elems = append(t.elems, &textElement{item})
return
case tokLiteral:
switch w[0] {
case ".meta-left":
- t.elems.Push(&literalElement{t.ldelim})
+ t.elems = append(t.elems, &literalElement{t.ldelim})
case ".meta-right":
- t.elems.Push(&literalElement{t.rdelim})
+ t.elems = append(t.elems, &literalElement{t.rdelim})
case ".space":
- t.elems.Push(&literalElement{space})
+ t.elems = append(t.elems, &literalElement{space})
case ".tab":
- t.elems.Push(&literalElement{tab})
+ t.elems = append(t.elems, &literalElement{tab})
default:
t.parseError("internal error: unknown literal: %s", w[0])
}
return
case tokVariable:
- t.elems.Push(t.newVariable(w))
+ t.elems = append(t.elems, t.newVariable(w))
return
}
return false, tok, w
@@ -610,11 +523,11 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
func (t *Template) parseRepeated(words []string) *repeatedElement {
r := new(repeatedElement)
- t.elems.Push(r)
+ t.elems = append(t.elems, r)
r.linenum = t.linenum
r.field = words[2]
// Scan section, collecting true and false (.or) blocks.
- r.start = t.elems.Len()
+ r.start = len(t.elems)
r.or = -1
r.altstart = -1
r.altend = -1
@@ -637,8 +550,8 @@ Loop:
t.parseError("extra .or in .repeated section")
break Loop
}
- r.altend = t.elems.Len()
- r.or = t.elems.Len()
+ r.altend = len(t.elems)
+ r.or = len(t.elems)
case tokSection:
t.parseSection(w)
case tokRepeated:
@@ -652,26 +565,26 @@ Loop:
t.parseError(".alternates inside .or block in .repeated section")
break Loop
}
- r.altstart = t.elems.Len()
+ r.altstart = len(t.elems)
default:
t.parseError("internal error: unknown repeated section item: %s", item)
break Loop
}
}
if r.altend < 0 {
- r.altend = t.elems.Len()
+ r.altend = len(t.elems)
}
- r.end = t.elems.Len()
+ r.end = len(t.elems)
return r
}
func (t *Template) parseSection(words []string) *sectionElement {
s := new(sectionElement)
- t.elems.Push(s)
+ t.elems = append(t.elems, s)
s.linenum = t.linenum
s.field = words[1]
// Scan section, collecting true and false (.or) blocks.
- s.start = t.elems.Len()
+ s.start = len(t.elems)
s.or = -1
Loop:
for {
@@ -692,7 +605,7 @@ Loop:
t.parseError("extra .or in .section")
break Loop
}
- s.or = t.elems.Len()
+ s.or = len(t.elems)
case tokSection:
t.parseSection(w)
case tokRepeated:
@@ -703,7 +616,7 @@ Loop:
t.parseError("internal error: unknown section item: %s", item)
}
}
- s.end = t.elems.Len()
+ s.end = len(t.elems)
return s
}
@@ -732,337 +645,6 @@ func (t *Template) parse() {
// -- Execution
-// Evaluate interfaces and pointers looking for a value that can look up the name, via a
-// struct field, method, or map key, and return the result of the lookup.
-func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
- for v.IsValid() {
- typ := v.Type()
- if n := v.Type().NumMethod(); n > 0 {
- for i := 0; i < n; i++ {
- m := typ.Method(i)
- mtyp := m.Type
- if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return v.Method(i).Call(nil)[0]
- }
- }
- }
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- case reflect.Struct:
- if !isExported(name) {
- t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
- }
- return av.FieldByName(name)
- case reflect.Map:
- if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
- return v
- }
- return reflect.Zero(typ.Elem())
- default:
- return reflect.Value{}
- }
- }
- return v
-}
-
-// indirectPtr returns the item numLevels levels of indirection below the value.
-// It is forgiving: if the value is not a pointer, it returns it rather than giving
-// an error. If the pointer is nil, it is returned as is.
-func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
- for i := numLevels; v.IsValid() && i > 0; i++ {
- if p := v; p.Kind() == reflect.Ptr {
- if p.IsNil() {
- return v
- }
- v = p.Elem()
- } else {
- break
- }
- }
- return v
-}
-
-// Walk v through pointers and interfaces, extracting the elements within.
-func indirect(v reflect.Value) reflect.Value {
-loop:
- for v.IsValid() {
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- default:
- break loop
- }
- }
- return v
-}
-
-// If the data for this template is a struct, find the named variable.
-// Names of the form a.b.c are walked down the data tree.
-// The special name "@" (the "cursor") denotes the current data.
-// The value coming in (st.data) might need indirecting to reach
-// a struct while the return value is not indirected - that is,
-// it represents the actual named field. Leading stars indicate
-// levels of indirection to be applied to the value.
-func (t *Template) findVar(st *state, s string) reflect.Value {
- data := st.data
- flattenedName := strings.TrimLeft(s, "*")
- numStars := len(s) - len(flattenedName)
- s = flattenedName
- if s == "@" {
- return indirectPtr(data, numStars)
- }
- for _, elem := range strings.Split(s, ".", -1) {
- // Look up field; data must be a struct or map.
- data = t.lookup(st, data, elem)
- if !data.IsValid() {
- return reflect.Value{}
- }
- }
- return indirectPtr(data, numStars)
-}
-
-// Is there no data to look at?
-func empty(v reflect.Value) bool {
- v = indirect(v)
- if !v.IsValid() {
- return true
- }
- switch v.Kind() {
- case reflect.Bool:
- return v.Bool() == false
- case reflect.String:
- return v.String() == ""
- case reflect.Struct:
- return false
- case reflect.Map:
- return false
- case reflect.Array:
- return v.Len() == 0
- case reflect.Slice:
- return v.Len() == 0
- }
- return false
-}
-
-// Look up a variable or method, up through the parent if necessary.
-func (t *Template) varValue(name string, st *state) reflect.Value {
- field := t.findVar(st, name)
- if !field.IsValid() {
- if st.parent == nil {
- t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
- }
- return t.varValue(name, st.parent)
- }
- return field
-}
-
-func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
- fn := t.formatter(fmt)
- if fn == nil {
- t.execError(st, v.linenum, "missing formatter %s for variable", fmt)
- }
- fn(wr, fmt, val...)
-}
-
-// Evaluate a variable, looking up through the parent if necessary.
-// If it has a formatter attached ({var|formatter}) run that too.
-func (t *Template) writeVariable(v *variableElement, st *state) {
- // Resolve field names
- val := make([]interface{}, len(v.args))
- for i, arg := range v.args {
- if name, ok := arg.(fieldName); ok {
- val[i] = t.varValue(string(name), st).Interface()
- } else {
- val[i] = arg
- }
- }
- for i, fmt := range v.fmts[:len(v.fmts)-1] {
- b := &st.buf[i&1]
- b.Reset()
- t.format(b, fmt, val, v, st)
- val = val[0:1]
- val[0] = b.Bytes()
- }
- t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
-}
-
-// Execute element i. Return next index to execute.
-func (t *Template) executeElement(i int, st *state) int {
- switch elem := t.elems.At(i).(type) {
- case *textElement:
- st.wr.Write(elem.text)
- return i + 1
- case *literalElement:
- st.wr.Write(elem.text)
- return i + 1
- case *variableElement:
- t.writeVariable(elem, st)
- return i + 1
- case *sectionElement:
- t.executeSection(elem, st)
- return elem.end
- case *repeatedElement:
- t.executeRepeated(elem, st)
- return elem.end
- }
- e := t.elems.At(i)
- t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(e).Interface(), e)
- return 0
-}
-
-// Execute the template.
-func (t *Template) execute(start, end int, st *state) {
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Execute a .section
-func (t *Template) executeSection(s *sectionElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(s.field, st)
- if !field.IsValid() {
- t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
- }
- st = st.clone(field)
- start, end := s.start, s.or
- if !empty(field) {
- // Execute the normal block.
- if end < 0 {
- end = s.end
- }
- } else {
- // Execute the .or block. If it's missing, do nothing.
- start, end = s.or, s.end
- if start < 0 {
- return
- }
- }
- for i := start; i < end; {
- i = t.executeElement(i, st)
- }
-}
-
-// Return the result of calling the Iter method on v, or nil.
-func iter(v reflect.Value) reflect.Value {
- for j := 0; j < v.Type().NumMethod(); j++ {
- mth := v.Type().Method(j)
- fv := v.Method(j)
- ft := fv.Type()
- // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
- if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
- continue
- }
- ct := ft.Out(0)
- if ct.Kind() != reflect.Chan ||
- ct.ChanDir()&reflect.RecvDir == 0 {
- continue
- }
- return fv.Call(nil)[0]
- }
- return reflect.Value{}
-}
-
-// Execute a .repeated section
-func (t *Template) executeRepeated(r *repeatedElement, st *state) {
- // Find driver data for this section. It must be in the current struct.
- field := t.varValue(r.field, st)
- if !field.IsValid() {
- t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
- }
- field = indirect(field)
-
- start, end := r.start, r.or
- if end < 0 {
- end = r.end
- }
- if r.altstart >= 0 {
- end = r.altstart
- }
- first := true
-
- // Code common to all the loops.
- loopBody := func(newst *state) {
- // .alternates between elements
- if !first && r.altstart >= 0 {
- for i := r.altstart; i < r.altend; {
- i = t.executeElement(i, newst)
- }
- }
- first = false
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
-
- if array := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
- for j := 0; j < array.Len(); j++ {
- loopBody(st.clone(array.Index(j)))
- }
- } else if m := field; m.Kind() == reflect.Map {
- for _, key := range m.MapKeys() {
- loopBody(st.clone(m.MapIndex(key)))
- }
- } else if ch := iter(field); ch.IsValid() {
- for {
- e, ok := ch.Recv()
- if !ok {
- break
- }
- loopBody(st.clone(e))
- }
- } else {
- t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
- r.field, field.Type())
- }
-
- if first {
- // Empty. Execute the .or block, once. If it's missing, do nothing.
- start, end := r.or, r.end
- if start >= 0 {
- newst := st.clone(field)
- for i := start; i < end; {
- i = t.executeElement(i, newst)
- }
- }
- return
- }
-}
-
-// A valid delimiter must contain no space and be non-empty.
-func validDelim(d []byte) bool {
- if len(d) == 0 {
- return false
- }
- for _, c := range d {
- if isSpace(c) {
- return false
- }
- }
- return true
-}
-
-// checkError is a deferred function to turn a panic with type *Error into a plain error return.
-// Other panics are unexpected and so are re-enabled.
-func checkError(error *os.Error) {
- if v := recover(); v != nil {
- if e, ok := v.(*Error); ok {
- *error = e
- } else {
- // runtime errors should crash
- panic(v)
- }
- }
-}
-
// -- Public interface
// Parse initializes a Template by parsing its definition. The string
@@ -1100,7 +682,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
val := reflect.ValueOf(data)
defer checkError(&err)
t.p = 0
- t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
+ t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
return nil
}
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index db4c65941..f8b53e63a 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -143,7 +143,6 @@ func (b *B) run() BenchmarkResult {
b.runN(n)
}
return BenchmarkResult{b.N, b.ns, b.bytes}
-
}
// The results of a benchmark run.
@@ -183,6 +182,7 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
if len(*matchBenchmarks) == 0 {
return
}
+ procs := runtime.GOMAXPROCS(-1)
for _, Benchmark := range benchmarks {
matched, err := matchString(*matchBenchmarks, Benchmark.Name)
if err != nil {
@@ -194,7 +194,12 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
}
b := &B{benchmark: Benchmark}
r := b.run()
- fmt.Printf("%s\t%v\n", Benchmark.Name, r)
+ print(fmt.Sprintf("%s\t%v\n", Benchmark.Name, r))
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", Benchmark.Name, p))
+ procs = p
+ }
+
}
}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 8781b207d..3b2dd377a 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -171,6 +171,7 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
if len(tests) == 0 {
println("testing: warning: no tests to run")
}
+ procs := runtime.GOMAXPROCS(-1)
for i := 0; i < len(tests); i++ {
matched, err := matchString(*match, tests[i].Name)
if err != nil {
@@ -190,6 +191,11 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
<-t.ch
ns += time.Nanoseconds()
tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
+ if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
+ t.failed = true
+ t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", tests[i].Name, p)
+ procs = p
+ }
if t.failed {
println("--- FAIL:", tests[i].Name, tstr)
print(t.errors)
diff --git a/src/pkg/unicode/Makefile b/src/pkg/unicode/Makefile
index 26e6e501f..55ed5b2d9 100644
--- a/src/pkg/unicode/Makefile
+++ b/src/pkg/unicode/Makefile
@@ -8,6 +8,7 @@ TARG=unicode
GOFILES=\
casetables.go\
digit.go\
+ graphic.go\
letter.go\
tables.go\
diff --git a/src/pkg/unicode/digit.go b/src/pkg/unicode/digit.go
index 471c4dfdc..6793fd7e5 100644
--- a/src/pkg/unicode/digit.go
+++ b/src/pkg/unicode/digit.go
@@ -6,7 +6,7 @@ package unicode
// IsDigit reports whether the rune is a decimal digit.
func IsDigit(rune int) bool {
- if rune < 0x100 { // quick ASCII (Latin-1, really) check
+ if rune <= MaxLatin1 {
return '0' <= rune && rune <= '9'
}
return Is(Digit, rune)
diff --git a/src/pkg/unicode/digit_test.go b/src/pkg/unicode/digit_test.go
index 9bbccde92..ae3c0ece9 100644
--- a/src/pkg/unicode/digit_test.go
+++ b/src/pkg/unicode/digit_test.go
@@ -118,7 +118,7 @@ func TestDigit(t *testing.T) {
// Test that the special case in IsDigit agrees with the table
func TestDigitOptimization(t *testing.T) {
- for i := 0; i < 0x100; i++ {
+ for i := 0; i <= MaxLatin1; i++ {
if Is(Digit, i) != IsDigit(i) {
t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
}
diff --git a/src/pkg/unicode/graphic.go b/src/pkg/unicode/graphic.go
new file mode 100644
index 000000000..d482aace2
--- /dev/null
+++ b/src/pkg/unicode/graphic.go
@@ -0,0 +1,132 @@
+// 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 unicode
+
+// Bit masks for each code point under U+0100, for fast lookup.
+const (
+ pC = 1 << iota // a control character.
+ pP // a punctuation character.
+ pN // a numeral.
+ pS // a symbolic character.
+ pZ // a spacing character.
+ pLu // an upper-case letter.
+ pLl // a lower-case letter.
+ pp // a printable character according to Go's definition.
+ pg = pp | pZ // a graphical character according to the Unicode definition.
+)
+
+// GraphicRanges defines the set of graphic characters according to Unicode.
+var GraphicRanges = []*RangeTable{
+ L, M, N, P, S, Zs,
+}
+
+// PrintRanges defines the set of printable characters according to Go.
+// ASCII space, U+0020, is handled separately.
+var PrintRanges = []*RangeTable{
+ L, M, N, P, S,
+}
+
+// IsGraphic reports whether the rune is defined as a Graphic by Unicode.
+// Such characters include letters, marks, numbers, punctuation, symbols, and
+// spaces, from categories L, M, N, P, S, Zs.
+func IsGraphic(rune int) bool {
+ // We cast to uint32 to avoid the extra test for negative,
+ // and in the index we cast to uint8 to avoid the range check.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pg != 0
+ }
+ return IsOneOf(GraphicRanges, rune)
+}
+
+// IsPrint reports whether the rune is defined as printable by Go. Such
+// characters include letters, marks, numbers, punctuation, symbols, and the
+// ASCII space character, from categories L, M, N, P, S and the ASCII space
+// character. This categorization is the same as IsGraphic except that the
+// only spacing character is ASCII space, U+0020.
+func IsPrint(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pp != 0
+ }
+ return IsOneOf(PrintRanges, rune)
+}
+
+// IsOneOf reports whether the rune is a member of one of the ranges.
+// The rune is known to be above Latin-1.
+func IsOneOf(set []*RangeTable, rune int) bool {
+ for _, inside := range set {
+ if Is(inside, rune) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsControl reports whether the rune is a control character.
+// The C (Other) Unicode category includes more code points
+// such as surrogates; use Is(C, rune) to test for them.
+func IsControl(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pC != 0
+ }
+ // All control characters are < Latin1Max.
+ return false
+}
+
+// IsLetter reports whether the rune is a letter (category L).
+func IsLetter(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&(pLu|pLl) != 0
+ }
+ return Is(Letter, rune)
+}
+
+// IsMark reports whether the rune is a mark character (category M).
+func IsMark(rune int) bool {
+ // There are no mark characters in Latin-1.
+ return Is(Mark, rune)
+}
+
+// IsNumber reports whether the rune is a number (category N).
+func IsNumber(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pN != 0
+ }
+ return Is(Number, rune)
+}
+
+// IsPunct reports whether the rune is a Unicode punctuation character
+// (category P).
+func IsPunct(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pP != 0
+ }
+ return Is(Punct, rune)
+}
+
+// IsSpace reports whether the rune is a space character as defined
+// by Unicode's White Space property; in the Latin-1 space
+// this is
+// '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP).
+// Other definitions of spacing characters are set by category
+// Z and property Pattern_White_Space.
+func IsSpace(rune int) bool {
+ // This property isn't the same as Z; special-case it.
+ if uint32(rune) <= MaxLatin1 {
+ switch rune {
+ case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+ return true
+ }
+ return false
+ }
+ return Is(White_Space, rune)
+}
+
+// IsSymbol reports whether the rune is a symbolic character.
+func IsSymbol(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pS != 0
+ }
+ return Is(Symbol, rune)
+}
diff --git a/src/pkg/unicode/graphic_test.go b/src/pkg/unicode/graphic_test.go
new file mode 100644
index 000000000..77c679f7c
--- /dev/null
+++ b/src/pkg/unicode/graphic_test.go
@@ -0,0 +1,122 @@
+// 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 unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+// Independently check that the special "Is" functions work
+// in the Latin-1 range through the property table.
+
+func TestIsControlLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsControl(i)
+ want := false
+ switch {
+ case 0x00 <= i && i <= 0x1F:
+ want = true
+ case 0x7F <= i && i <= 0x9F:
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLetterLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLetter(i)
+ want := Is(Letter, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsUpperLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsUpper(i)
+ want := Is(Upper, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLowerLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLower(i)
+ want := Is(Lower, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestNumberLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsNumber(i)
+ want := Is(Number, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPrintLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPrint(i)
+ want := IsOneOf(PrintRanges, i)
+ if i == ' ' {
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsGraphicLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsGraphic(i)
+ want := IsOneOf(GraphicRanges, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPunctLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPunct(i)
+ want := Is(Punct, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSpaceLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSpace(i)
+ want := Is(White_Space, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSymbolLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSymbol(i)
+ want := Is(Symbol, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index 047bef19b..a0c55bbf7 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -9,6 +9,8 @@ package unicode
const (
MaxRune = 0x10FFFF // Maximum valid Unicode code point.
ReplacementChar = 0xFFFD // Represents invalid code points.
+ MaxASCII = 0x7F // maximum ASCII value.
+ MaxLatin1 = 0xFF // maximum Latin-1 value.
)
// RangeTable defines a set of Unicode code points by listing the ranges of
@@ -121,7 +123,7 @@ func is32(ranges []Range32, rune uint32) bool {
// Is tests whether rune is in the specified table of ranges.
func Is(rangeTab *RangeTable, rune int) bool {
// common case: rune is ASCII or Latin-1.
- if rune < 0x100 {
+ if uint32(rune) <= MaxLatin1 {
// Only need to check R16, since R32 is always >= 1<<16.
r16 := uint16(rune)
for _, r := range rangeTab.R16 {
@@ -148,49 +150,30 @@ func Is(rangeTab *RangeTable, rune int) bool {
// IsUpper reports whether the rune is an upper case letter.
func IsUpper(rune int) bool {
- if rune < 0x80 { // quick ASCII check
- return 'A' <= rune && rune <= 'Z'
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLu != 0
}
return Is(Upper, rune)
}
// IsLower reports whether the rune is a lower case letter.
func IsLower(rune int) bool {
- if rune < 0x80 { // quick ASCII check
- return 'a' <= rune && rune <= 'z'
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLl != 0
}
return Is(Lower, rune)
}
// IsTitle reports whether the rune is a title case letter.
func IsTitle(rune int) bool {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxLatin1 {
return false
}
return Is(Title, rune)
}
-// IsLetter reports whether the rune is a letter.
-func IsLetter(rune int) bool {
- if rune < 0x80 { // quick ASCII check
- rune &^= 'a' - 'A'
- return 'A' <= rune && rune <= 'Z'
- }
- return Is(Letter, rune)
-}
-
-// IsSpace reports whether the rune is a white space character.
-func IsSpace(rune int) bool {
- if rune <= 0xFF { // quick Latin-1 check
- switch rune {
- case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
- return true
- }
- return false
- }
- return Is(White_Space, rune)
-}
-
// to maps the rune using the specified case mapping.
func to(_case int, rune int, caseRange []CaseRange) int {
if _case < 0 || MaxCase <= _case {
@@ -235,7 +218,7 @@ func To(_case int, rune int) int {
// ToUpper maps the rune to upper case.
func ToUpper(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'a' <= rune && rune <= 'z' {
rune -= 'a' - 'A'
}
@@ -246,7 +229,7 @@ func ToUpper(rune int) int {
// ToLower maps the rune to lower case.
func ToLower(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'A' <= rune && rune <= 'Z' {
rune += 'a' - 'A'
}
@@ -257,7 +240,7 @@ func ToLower(rune int) int {
// ToTitle maps the rune to title case.
func ToTitle(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
rune -= 'a' - 'A'
}
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index 432ffb671..4c24ffc51 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -323,7 +323,7 @@ func TestIsSpace(t *testing.T) {
// Check that the optimizations for IsLetter etc. agree with the tables.
// We only need to check the Latin-1 range.
func TestLetterOptimizations(t *testing.T) {
- for i := 0; i < 0x100; i++ {
+ for i := 0; i <= MaxLatin1; i++ {
if Is(Letter, i) != IsLetter(i) {
t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
}
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index c3cf32b48..655fe46e4 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -28,6 +28,7 @@ func main() {
printScriptOrProperty(false)
printScriptOrProperty(true)
printCases()
+ printLatinProperties()
printSizes()
}
@@ -54,7 +55,17 @@ var test = flag.Bool("test",
var scriptRe = regexp.MustCompile(`^([0-9A-F]+)(\.\.[0-9A-F]+)? *; ([A-Za-z_]+)$`)
var logger = log.New(os.Stderr, "", log.Lshortfile)
-var category = map[string]bool{"letter": true} // Nd Lu etc. letter is a special case
+var category = map[string]bool{
+ // Nd Lu etc.
+ // We use one-character names to identify merged categories
+ "L": true, // Lu Ll Lt Lm Lo
+ "P": true, // Pc Pd Ps Pe Pu Pf Po
+ "M": true, // Mn Mc Me
+ "N": true, // Nd Nl No
+ "S": true, // Sm Sc Sk So
+ "Z": true, // Zs Zl Zp
+ "C": true, // Cc Cf Cs Co Cn
+}
// UnicodeData.txt has form:
// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
@@ -247,12 +258,9 @@ func version() string {
return "Unknown"
}
-func letterOp(code int) bool {
- switch chars[code].category {
- case "Lu", "Ll", "Lt", "Lm", "Lo":
- return true
- }
- return false
+func categoryOp(code int, class uint8) bool {
+ category := chars[code].category
+ return len(category) > 0 && category[0] == class
}
func loadChars() {
@@ -348,8 +356,27 @@ func printCategories() {
// Cases deserving special comments
varDecl := ""
switch name {
- case "letter":
- varDecl = "\tLetter = letter; // Letter is the set of Unicode letters.\n"
+ case "C":
+ varDecl = "\tOther = _C; // Other/C is the set of Unicode control and special characters, category C.\n"
+ varDecl += "\tC = _C\n"
+ case "L":
+ varDecl = "\tLetter = _L; // Letter/L is the set of Unicode letters, category L.\n"
+ varDecl += "\tL = _L\n"
+ case "M":
+ varDecl = "\tMark = _M; // Mark/M is the set of Unicode mark characters, category M.\n"
+ varDecl += "\tM = _M\n"
+ case "N":
+ varDecl = "\tNumber = _N; // Number/N is the set of Unicode number characters, category N.\n"
+ varDecl += "\tN = _N\n"
+ case "P":
+ varDecl = "\tPunct = _P; // Punct/P is the set of Unicode punctuation characters, category P.\n"
+ varDecl += "\tP = _P\n"
+ case "S":
+ varDecl = "\tSymbol = _S; // Symbol/S is the set of Unicode symbol characters, category S.\n"
+ varDecl += "\tS = _S\n"
+ case "Z":
+ varDecl = "\tSpace = _Z; // Space/Z is the set of Unicode space characters, category Z.\n"
+ varDecl += "\tZ = _Z\n"
case "Nd":
varDecl = "\tDigit = _Nd; // Digit is the set of Unicode characters with the \"decimal digit\" property.\n"
case "Lu":
@@ -359,17 +386,18 @@ func printCategories() {
case "Lt":
varDecl = "\tTitle = _Lt; // Title is the set of Unicode title case letters.\n"
}
- if name != "letter" {
+ if len(name) > 1 {
varDecl += fmt.Sprintf(
"\t%s = _%s; // %s is the set of Unicode characters in category %s.\n",
name, name, name, name)
}
decl[ndecl] = varDecl
ndecl++
- if name == "letter" { // special case
+ if len(name) == 1 { // unified categories
+ decl := fmt.Sprintf("var _%s = &RangeTable{\n", name)
dumpRange(
- "var letter = &RangeTable{\n",
- letterOp)
+ decl,
+ func(code int) bool { return categoryOp(code, name[0]) })
continue
}
dumpRange(
@@ -446,7 +474,7 @@ func printRange(lo, hi, stride uint32, size int, count *int) (int, *int) {
if size == 16 && hi >= 1<<16 {
if lo < 1<<16 {
if lo+stride != hi {
- log.Fatalf("unexpected straddle: %U %U %d", lo, hi, stride)
+ logger.Fatalf("unexpected straddle: %U %U %d", lo, hi, stride)
}
// No range contains U+FFFF as an instance, so split
// the range into two entries. That way we can maintain
@@ -472,11 +500,11 @@ func fullCategoryTest(list []string) {
logger.Fatal("unknown category", name)
}
r, ok := unicode.Categories[name]
- if !ok {
- logger.Fatal("unknown table", name)
+ if !ok && len(name) > 1 {
+ logger.Fatalf("unknown table %q", name)
}
- if name == "letter" {
- verifyRange(name, letterOp, r)
+ if len(name) == 1 {
+ verifyRange(name, func(code int) bool { return categoryOp(code, name[0]) }, r)
} else {
verifyRange(
name,
@@ -487,11 +515,16 @@ func fullCategoryTest(list []string) {
}
func verifyRange(name string, inCategory Op, table *unicode.RangeTable) {
+ count := 0
for i := range chars {
web := inCategory(i)
pkg := unicode.Is(table, i)
if web != pkg {
fmt.Fprintf(os.Stderr, "%s: %U: web=%t pkg=%t\n", name, i, web, pkg)
+ count++
+ if count > 10 {
+ break
+ }
}
}
}
@@ -882,6 +915,42 @@ func fullCaseTest() {
}
}
+func printLatinProperties() {
+ if *test {
+ return
+ }
+ fmt.Println("var properties = [MaxLatin1+1]uint8{")
+ for code := 0; code <= unicode.MaxLatin1; code++ {
+ var property string
+ switch chars[code].category {
+ case "Cc", "": // NUL has no category.
+ property = "pC"
+ case "Cf": // soft hyphen, unique category, not printable.
+ property = "0"
+ case "Ll":
+ property = "pLl | pp"
+ case "Lu":
+ property = "pLu | pp"
+ case "Nd", "No":
+ property = "pN | pp"
+ case "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps":
+ property = "pP | pp"
+ case "Sc", "Sk", "Sm", "So":
+ property = "pS | pp"
+ case "Zs":
+ property = "pZ"
+ default:
+ logger.Fatalf("%U has unknown category %q", code, chars[code].category)
+ }
+ // Special case
+ if code == ' ' {
+ property = "pZ | pp"
+ }
+ fmt.Printf("\t0x%.2X: %s, // %q\n", code, property, code)
+ }
+ fmt.Println("}")
+}
+
var range16Count = 0 // Number of entries in the 16-bit range tables.
var range32Count = 0 // Number of entries in the 32-bit range tables.
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index ff452b75c..b37ad1836 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -149,7 +149,14 @@ var inCategoryTest = []T{
{0x2028, "Zl"},
{0x2029, "Zp"},
{0x202f, "Zs"},
- {0x04aa, "letter"},
+ // Unifieds.
+ {0x04aa, "L"},
+ {0x0009, "C"},
+ {0x1712, "M"},
+ {0x0031, "N"},
+ {0x00bb, "P"},
+ {0x00a2, "S"},
+ {0x00a0, "Z"},
}
var inPropTest = []T{
@@ -197,13 +204,13 @@ func TestScripts(t *testing.T) {
t.Fatal(test.script, "not a known script")
}
if !Is(Scripts[test.script], test.rune) {
- t.Errorf("IsScript(%#x, %s) = false, want true", test.rune, test.script)
+ t.Errorf("IsScript(%U, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
for _, test := range outTest {
if Is(Scripts[test.script], test.rune) {
- t.Errorf("IsScript(%#x, %s) = true, want false", test.rune, test.script)
+ t.Errorf("IsScript(%U, %s) = true, want false", test.rune, test.script)
}
}
for k := range notTested {
@@ -221,7 +228,7 @@ func TestCategories(t *testing.T) {
t.Fatal(test.script, "not a known category")
}
if !Is(Categories[test.script], test.rune) {
- t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
@@ -240,7 +247,7 @@ func TestProperties(t *testing.T) {
t.Fatal(test.script, "not a known prop")
}
if !Is(Properties[test.script], test.rune) {
- t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index fc2bdd8d2..32681a8c0 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -9,36 +9,42 @@ const Version = "6.0.0"
// Categories is the set of Unicode data tables.
var Categories = map[string]*RangeTable{
- "Lm": Lm,
- "Ll": Ll,
- "Me": Me,
- "Mc": Mc,
- "Mn": Mn,
- "Zl": Zl,
- "letter": letter,
- "Zp": Zp,
- "Zs": Zs,
- "Cs": Cs,
- "Co": Co,
- "Cf": Cf,
- "Cc": Cc,
- "Po": Po,
- "Pi": Pi,
- "Pf": Pf,
- "Pe": Pe,
- "Pd": Pd,
- "Pc": Pc,
- "Ps": Ps,
- "Nd": Nd,
- "Nl": Nl,
- "No": No,
- "So": So,
- "Sm": Sm,
- "Sk": Sk,
- "Sc": Sc,
- "Lu": Lu,
- "Lt": Lt,
- "Lo": Lo,
+ "Lm": Lm,
+ "Ll": Ll,
+ "C": C,
+ "M": M,
+ "L": L,
+ "N": N,
+ "P": P,
+ "S": S,
+ "Z": Z,
+ "Me": Me,
+ "Mc": Mc,
+ "Mn": Mn,
+ "Zl": Zl,
+ "Zp": Zp,
+ "Zs": Zs,
+ "Cs": Cs,
+ "Co": Co,
+ "Cf": Cf,
+ "Cc": Cc,
+ "Po": Po,
+ "Pi": Pi,
+ "Pf": Pf,
+ "Pe": Pe,
+ "Pd": Pd,
+ "Pc": Pc,
+ "Ps": Ps,
+ "Nd": Nd,
+ "Nl": Nl,
+ "No": No,
+ "So": So,
+ "Sm": Sm,
+ "Sk": Sk,
+ "Sc": Sc,
+ "Lu": Lu,
+ "Lt": Lt,
+ "Lo": Lo,
}
var _Lm = &RangeTable{
@@ -226,127 +232,36 @@ var _Ll = &RangeTable{
},
}
-var _Me = &RangeTable{
+var _C = &RangeTable{
R16: []Range16{
- {0x0488, 0x0489, 1},
- {0x20dd, 0x20e0, 1},
- {0x20e2, 0x20e4, 1},
- {0xa670, 0xa672, 1},
- },
-}
-
-var _Mc = &RangeTable{
- R16: []Range16{
- {0x0903, 0x093b, 56},
- {0x093e, 0x0940, 1},
- {0x0949, 0x094c, 1},
- {0x094e, 0x094f, 1},
- {0x0982, 0x0983, 1},
- {0x09be, 0x09c0, 1},
- {0x09c7, 0x09c8, 1},
- {0x09cb, 0x09cc, 1},
- {0x09d7, 0x0a03, 44},
- {0x0a3e, 0x0a40, 1},
- {0x0a83, 0x0abe, 59},
- {0x0abf, 0x0ac0, 1},
- {0x0ac9, 0x0acb, 2},
- {0x0acc, 0x0b02, 54},
- {0x0b03, 0x0b3e, 59},
- {0x0b40, 0x0b47, 7},
- {0x0b48, 0x0b4b, 3},
- {0x0b4c, 0x0b57, 11},
- {0x0bbe, 0x0bbf, 1},
- {0x0bc1, 0x0bc2, 1},
- {0x0bc6, 0x0bc8, 1},
- {0x0bca, 0x0bcc, 1},
- {0x0bd7, 0x0c01, 42},
- {0x0c02, 0x0c03, 1},
- {0x0c41, 0x0c44, 1},
- {0x0c82, 0x0c83, 1},
- {0x0cbe, 0x0cc0, 2},
- {0x0cc1, 0x0cc4, 1},
- {0x0cc7, 0x0cc8, 1},
- {0x0cca, 0x0ccb, 1},
- {0x0cd5, 0x0cd6, 1},
- {0x0d02, 0x0d03, 1},
- {0x0d3e, 0x0d40, 1},
- {0x0d46, 0x0d48, 1},
- {0x0d4a, 0x0d4c, 1},
- {0x0d57, 0x0d82, 43},
- {0x0d83, 0x0dcf, 76},
- {0x0dd0, 0x0dd1, 1},
- {0x0dd8, 0x0ddf, 1},
- {0x0df2, 0x0df3, 1},
- {0x0f3e, 0x0f3f, 1},
- {0x0f7f, 0x102b, 172},
- {0x102c, 0x1031, 5},
- {0x1038, 0x103b, 3},
- {0x103c, 0x1056, 26},
- {0x1057, 0x1062, 11},
- {0x1063, 0x1064, 1},
- {0x1067, 0x106d, 1},
- {0x1083, 0x1084, 1},
- {0x1087, 0x108c, 1},
- {0x108f, 0x109a, 11},
- {0x109b, 0x109c, 1},
- {0x17b6, 0x17be, 8},
- {0x17bf, 0x17c5, 1},
- {0x17c7, 0x17c8, 1},
- {0x1923, 0x1926, 1},
- {0x1929, 0x192b, 1},
- {0x1930, 0x1931, 1},
- {0x1933, 0x1938, 1},
- {0x19b0, 0x19c0, 1},
- {0x19c8, 0x19c9, 1},
- {0x1a19, 0x1a1b, 1},
- {0x1a55, 0x1a57, 2},
- {0x1a61, 0x1a63, 2},
- {0x1a64, 0x1a6d, 9},
- {0x1a6e, 0x1a72, 1},
- {0x1b04, 0x1b35, 49},
- {0x1b3b, 0x1b3d, 2},
- {0x1b3e, 0x1b41, 1},
- {0x1b43, 0x1b44, 1},
- {0x1b82, 0x1ba1, 31},
- {0x1ba6, 0x1ba7, 1},
- {0x1baa, 0x1be7, 61},
- {0x1bea, 0x1bec, 1},
- {0x1bee, 0x1bf2, 4},
- {0x1bf3, 0x1c24, 49},
- {0x1c25, 0x1c2b, 1},
- {0x1c34, 0x1c35, 1},
- {0x1ce1, 0x1cf2, 17},
- {0xa823, 0xa824, 1},
- {0xa827, 0xa880, 89},
- {0xa881, 0xa8b4, 51},
- {0xa8b5, 0xa8c3, 1},
- {0xa952, 0xa953, 1},
- {0xa983, 0xa9b4, 49},
- {0xa9b5, 0xa9ba, 5},
- {0xa9bb, 0xa9bd, 2},
- {0xa9be, 0xa9c0, 1},
- {0xaa2f, 0xaa30, 1},
- {0xaa33, 0xaa34, 1},
- {0xaa4d, 0xaa7b, 46},
- {0xabe3, 0xabe4, 1},
- {0xabe6, 0xabe7, 1},
- {0xabe9, 0xabea, 1},
- {0xabec, 0xabec, 1},
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+ {0x00ad, 0x0600, 1363},
+ {0x0601, 0x0603, 1},
+ {0x06dd, 0x070f, 50},
+ {0x17b4, 0x17b5, 1},
+ {0x200b, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ {0x2060, 0x2064, 1},
+ {0x206a, 0x206f, 1},
+ {0xd800, 0xf8ff, 1},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
},
R32: []Range32{
- {0x11000, 0x11000, 1},
- {0x11002, 0x11082, 128},
- {0x110b0, 0x110b2, 1},
- {0x110b7, 0x110b8, 1},
- {0x1d165, 0x1d166, 1},
- {0x1d16d, 0x1d172, 1},
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
},
}
-var _Mn = &RangeTable{
+var _M = &RangeTable{
R16: []Range16{
{0x0300, 0x036f, 1},
- {0x0483, 0x0487, 1},
+ {0x0483, 0x0489, 1},
{0x0591, 0x05bd, 1},
{0x05bf, 0x05c1, 2},
{0x05c2, 0x05c4, 2},
@@ -367,49 +282,69 @@ var _Mn = &RangeTable{
{0x0825, 0x0827, 1},
{0x0829, 0x082d, 1},
{0x0859, 0x085b, 1},
- {0x0900, 0x0902, 1},
- {0x093a, 0x093c, 2},
- {0x0941, 0x0948, 1},
- {0x094d, 0x0951, 4},
- {0x0952, 0x0957, 1},
+ {0x0900, 0x0903, 1},
+ {0x093a, 0x093c, 1},
+ {0x093e, 0x094f, 1},
+ {0x0951, 0x0957, 1},
{0x0962, 0x0963, 1},
- {0x0981, 0x09bc, 59},
- {0x09c1, 0x09c4, 1},
- {0x09cd, 0x09e2, 21},
+ {0x0981, 0x0983, 1},
+ {0x09bc, 0x09be, 2},
+ {0x09bf, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cd, 1},
+ {0x09d7, 0x09e2, 11},
{0x09e3, 0x0a01, 30},
- {0x0a02, 0x0a3c, 58},
- {0x0a41, 0x0a42, 1},
+ {0x0a02, 0x0a03, 1},
+ {0x0a3c, 0x0a3e, 2},
+ {0x0a3f, 0x0a42, 1},
{0x0a47, 0x0a48, 1},
{0x0a4b, 0x0a4d, 1},
{0x0a51, 0x0a70, 31},
{0x0a71, 0x0a75, 4},
- {0x0a81, 0x0a82, 1},
- {0x0abc, 0x0ac1, 5},
- {0x0ac2, 0x0ac5, 1},
- {0x0ac7, 0x0ac8, 1},
- {0x0acd, 0x0ae2, 21},
- {0x0ae3, 0x0b01, 30},
- {0x0b3c, 0x0b3f, 3},
- {0x0b41, 0x0b44, 1},
- {0x0b4d, 0x0b56, 9},
+ {0x0a81, 0x0a83, 1},
+ {0x0abc, 0x0abe, 2},
+ {0x0abf, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acd, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3c, 0x0b3e, 2},
+ {0x0b3f, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4d, 1},
+ {0x0b56, 0x0b57, 1},
{0x0b62, 0x0b63, 1},
- {0x0b82, 0x0bc0, 62},
- {0x0bcd, 0x0c3e, 113},
- {0x0c3f, 0x0c40, 1},
+ {0x0b82, 0x0bbe, 60},
+ {0x0bbf, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
{0x0c46, 0x0c48, 1},
{0x0c4a, 0x0c4d, 1},
{0x0c55, 0x0c56, 1},
{0x0c62, 0x0c63, 1},
- {0x0cbc, 0x0cbf, 3},
- {0x0cc6, 0x0ccc, 6},
- {0x0ccd, 0x0ce2, 21},
- {0x0ce3, 0x0d41, 94},
- {0x0d42, 0x0d44, 1},
- {0x0d4d, 0x0d62, 21},
- {0x0d63, 0x0dca, 103},
- {0x0dd2, 0x0dd4, 1},
- {0x0dd6, 0x0e31, 91},
- {0x0e34, 0x0e3a, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbc, 0x0cbe, 2},
+ {0x0cbf, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccd, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4d, 1},
+ {0x0d57, 0x0d62, 11},
+ {0x0d63, 0x0d82, 31},
+ {0x0d83, 0x0dca, 71},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd8, 2},
+ {0x0dd9, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e34, 3},
+ {0x0e35, 0x0e3a, 1},
{0x0e47, 0x0e4e, 1},
{0x0eb1, 0x0eb4, 3},
{0x0eb5, 0x0eb9, 1},
@@ -417,94 +352,79 @@ var _Mn = &RangeTable{
{0x0ec8, 0x0ecd, 1},
{0x0f18, 0x0f19, 1},
{0x0f35, 0x0f39, 2},
- {0x0f71, 0x0f7e, 1},
- {0x0f80, 0x0f84, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f71, 0x0f84, 1},
{0x0f86, 0x0f87, 1},
{0x0f8d, 0x0f97, 1},
{0x0f99, 0x0fbc, 1},
- {0x0fc6, 0x102d, 103},
- {0x102e, 0x1030, 1},
- {0x1032, 0x1037, 1},
- {0x1039, 0x103a, 1},
- {0x103d, 0x103e, 1},
- {0x1058, 0x1059, 1},
+ {0x0fc6, 0x102b, 101},
+ {0x102c, 0x103e, 1},
+ {0x1056, 0x1059, 1},
{0x105e, 0x1060, 1},
+ {0x1062, 0x1064, 1},
+ {0x1067, 0x106d, 1},
{0x1071, 0x1074, 1},
- {0x1082, 0x1085, 3},
- {0x1086, 0x108d, 7},
- {0x109d, 0x135d, 704},
- {0x135e, 0x135f, 1},
+ {0x1082, 0x108d, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109d, 1},
+ {0x135d, 0x135f, 1},
{0x1712, 0x1714, 1},
{0x1732, 0x1734, 1},
{0x1752, 0x1753, 1},
{0x1772, 0x1773, 1},
- {0x17b7, 0x17bd, 1},
- {0x17c6, 0x17c9, 3},
- {0x17ca, 0x17d3, 1},
+ {0x17b6, 0x17d3, 1},
{0x17dd, 0x180b, 46},
{0x180c, 0x180d, 1},
{0x18a9, 0x1920, 119},
- {0x1921, 0x1922, 1},
- {0x1927, 0x1928, 1},
- {0x1932, 0x1939, 7},
- {0x193a, 0x193b, 1},
- {0x1a17, 0x1a18, 1},
- {0x1a56, 0x1a58, 2},
- {0x1a59, 0x1a5e, 1},
- {0x1a60, 0x1a62, 2},
- {0x1a65, 0x1a6c, 1},
- {0x1a73, 0x1a7c, 1},
+ {0x1921, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
{0x1a7f, 0x1b00, 129},
- {0x1b01, 0x1b03, 1},
- {0x1b34, 0x1b36, 2},
- {0x1b37, 0x1b3a, 1},
- {0x1b3c, 0x1b42, 6},
+ {0x1b01, 0x1b04, 1},
+ {0x1b34, 0x1b44, 1},
{0x1b6b, 0x1b73, 1},
- {0x1b80, 0x1b81, 1},
- {0x1ba2, 0x1ba5, 1},
- {0x1ba8, 0x1ba9, 1},
- {0x1be6, 0x1be8, 2},
- {0x1be9, 0x1bed, 4},
- {0x1bef, 0x1bf1, 1},
- {0x1c2c, 0x1c33, 1},
- {0x1c36, 0x1c37, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1baa, 1},
+ {0x1be6, 0x1bf3, 1},
+ {0x1c24, 0x1c37, 1},
{0x1cd0, 0x1cd2, 1},
- {0x1cd4, 0x1ce0, 1},
- {0x1ce2, 0x1ce8, 1},
- {0x1ced, 0x1dc0, 211},
- {0x1dc1, 0x1de6, 1},
+ {0x1cd4, 0x1ce8, 1},
+ {0x1ced, 0x1cf2, 5},
+ {0x1dc0, 0x1de6, 1},
{0x1dfc, 0x1dff, 1},
- {0x20d0, 0x20dc, 1},
- {0x20e1, 0x20e5, 4},
- {0x20e6, 0x20f0, 1},
+ {0x20d0, 0x20f0, 1},
{0x2cef, 0x2cf1, 1},
{0x2d7f, 0x2de0, 97},
{0x2de1, 0x2dff, 1},
{0x302a, 0x302f, 1},
{0x3099, 0x309a, 1},
- {0xa66f, 0xa67c, 13},
- {0xa67d, 0xa6f0, 115},
- {0xa6f1, 0xa802, 273},
- {0xa806, 0xa80b, 5},
- {0xa825, 0xa826, 1},
- {0xa8c4, 0xa8e0, 28},
- {0xa8e1, 0xa8f1, 1},
+ {0xa66f, 0xa672, 1},
+ {0xa67c, 0xa67d, 1},
+ {0xa6f0, 0xa6f1, 1},
+ {0xa802, 0xa806, 4},
+ {0xa80b, 0xa823, 24},
+ {0xa824, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c4, 1},
+ {0xa8e0, 0xa8f1, 1},
{0xa926, 0xa92d, 1},
- {0xa947, 0xa951, 1},
- {0xa980, 0xa982, 1},
- {0xa9b3, 0xa9b6, 3},
- {0xa9b7, 0xa9b9, 1},
- {0xa9bc, 0xaa29, 109},
- {0xaa2a, 0xaa2e, 1},
- {0xaa31, 0xaa32, 1},
- {0xaa35, 0xaa36, 1},
+ {0xa947, 0xa953, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b3, 0xa9c0, 1},
+ {0xaa29, 0xaa36, 1},
{0xaa43, 0xaa4c, 9},
+ {0xaa4d, 0xaa7b, 46},
{0xaab0, 0xaab2, 2},
{0xaab3, 0xaab4, 1},
{0xaab7, 0xaab8, 1},
{0xaabe, 0xaabf, 1},
- {0xaac1, 0xabe5, 292},
- {0xabe8, 0xabed, 5},
+ {0xaac1, 0xabe3, 290},
+ {0xabe4, 0xabea, 1},
+ {0xabec, 0xabed, 1},
{0xfb1e, 0xfe00, 738},
{0xfe01, 0xfe0f, 1},
{0xfe20, 0xfe26, 1},
@@ -515,12 +435,13 @@ var _Mn = &RangeTable{
{0x10a05, 0x10a06, 1},
{0x10a0c, 0x10a0f, 1},
{0x10a38, 0x10a3a, 1},
- {0x10a3f, 0x11001, 1474},
+ {0x10a3f, 0x11000, 1473},
+ {0x11001, 0x11002, 1},
{0x11038, 0x11046, 1},
- {0x11080, 0x11081, 1},
- {0x110b3, 0x110b6, 1},
- {0x110b9, 0x110ba, 1},
- {0x1d167, 0x1d169, 1},
+ {0x11080, 0x11082, 1},
+ {0x110b0, 0x110ba, 1},
+ {0x1d165, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
{0x1d17b, 0x1d182, 1},
{0x1d185, 0x1d18b, 1},
{0x1d1aa, 0x1d1ad, 1},
@@ -529,13 +450,7 @@ var _Mn = &RangeTable{
},
}
-var _Zl = &RangeTable{
- R16: []Range16{
- {0x2028, 0x2028, 1},
- },
-}
-
-var letter = &RangeTable{
+var _L = &RangeTable{
R16: []Range16{
{0x0041, 0x005a, 1},
{0x0061, 0x007a, 1},
@@ -956,6 +871,725 @@ var letter = &RangeTable{
},
}
+var _N = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x0660, 0x0669, 1},
+ {0x06f0, 0x06f9, 1},
+ {0x07c0, 0x07c9, 1},
+ {0x0966, 0x096f, 1},
+ {0x09e6, 0x09ef, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0a66, 0x0a6f, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0b66, 0x0b6f, 1},
+ {0x0b72, 0x0b77, 1},
+ {0x0be6, 0x0bf2, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0e50, 0x0e59, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0f20, 0x0f33, 1},
+ {0x1040, 0x1049, 1},
+ {0x1090, 0x1099, 1},
+ {0x1369, 0x137c, 1},
+ {0x16ee, 0x16f0, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x1810, 0x1819, 1},
+ {0x1946, 0x194f, 1},
+ {0x19d0, 0x19da, 1},
+ {0x1a80, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1b50, 0x1b59, 1},
+ {0x1bb0, 0x1bb9, 1},
+ {0x1c40, 0x1c49, 1},
+ {0x1c50, 0x1c59, 1},
+ {0x2070, 0x2074, 4},
+ {0x2075, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x2182, 1},
+ {0x2185, 0x2189, 1},
+ {0x2460, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3007, 778},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3192, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa620, 0xa629, 1},
+ {0xa6e6, 0xa6ef, 1},
+ {0xa830, 0xa835, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ },
+ R32: []Range32{
+ {0x10107, 0x10133, 1},
+ {0x10140, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x104a0, 0x104a9, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x11052, 0x1106f, 1},
+ {0x12400, 0x12462, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f100, 0x1f10a, 1},
+ },
+}
+
+var _P = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x002a, 1},
+ {0x002c, 0x002f, 1},
+ {0x003a, 0x003b, 1},
+ {0x003f, 0x0040, 1},
+ {0x005b, 0x005d, 1},
+ {0x005f, 0x007b, 28},
+ {0x007d, 0x00a1, 36},
+ {0x00ab, 0x00b7, 12},
+ {0x00bb, 0x00bf, 4},
+ {0x037e, 0x0387, 9},
+ {0x055a, 0x055f, 1},
+ {0x0589, 0x058a, 1},
+ {0x05be, 0x05c0, 2},
+ {0x05c3, 0x05c6, 3},
+ {0x05f3, 0x05f4, 1},
+ {0x0609, 0x060a, 1},
+ {0x060c, 0x060d, 1},
+ {0x061b, 0x061e, 3},
+ {0x061f, 0x066a, 75},
+ {0x066b, 0x066d, 1},
+ {0x06d4, 0x0700, 44},
+ {0x0701, 0x070d, 1},
+ {0x07f7, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x085e, 0x0964, 262},
+ {0x0965, 0x0970, 11},
+ {0x0df4, 0x0e4f, 91},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f3a, 0x0f3d, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x1400, 0x166d, 621},
+ {0x166e, 0x169b, 45},
+ {0x169c, 0x16eb, 79},
+ {0x16ec, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1bfc, 0x1bff, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2010, 829},
+ {0x2011, 0x2027, 1},
+ {0x2030, 0x2043, 1},
+ {0x2045, 0x2051, 1},
+ {0x2053, 0x205e, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x2329, 0x232a, 1},
+ {0x2768, 0x2775, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2d70, 0x2e00, 144},
+ {0x2e01, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x3008, 0x3011, 1},
+ {0x3014, 0x301f, 1},
+ {0x3030, 0x303d, 13},
+ {0x30a0, 0x30fb, 91},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa673, 0xa67e, 11},
+ {0xa6f2, 0xa6f7, 1},
+ {0xa874, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa8f8, 0xa8fa, 1},
+ {0xa92e, 0xa92f, 1},
+ {0xa95f, 0xa9c1, 98},
+ {0xa9c2, 0xa9cd, 1},
+ {0xa9de, 0xa9df, 1},
+ {0xaa5c, 0xaa5f, 1},
+ {0xaade, 0xaadf, 1},
+ {0xabeb, 0xfd3e, 20819},
+ {0xfd3f, 0xfe10, 209},
+ {0xfe11, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe61, 1},
+ {0xfe63, 0xfe68, 5},
+ {0xfe6a, 0xfe6b, 1},
+ {0xff01, 0xff03, 1},
+ {0xff05, 0xff0a, 1},
+ {0xff0c, 0xff0f, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff20, 1},
+ {0xff3b, 0xff3d, 1},
+ {0xff3f, 0xff5b, 28},
+ {0xff5d, 0xff5f, 2},
+ {0xff60, 0xff65, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10101, 1},
+ {0x1039f, 0x103d0, 49},
+ {0x10857, 0x1091f, 200},
+ {0x1093f, 0x10a50, 273},
+ {0x10a51, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _S = &RangeTable{
+ R16: []Range16{
+ {0x0024, 0x002b, 7},
+ {0x003c, 0x003e, 1},
+ {0x005e, 0x0060, 2},
+ {0x007c, 0x007e, 2},
+ {0x00a2, 0x00a9, 1},
+ {0x00ac, 0x00ae, 2},
+ {0x00af, 0x00b1, 1},
+ {0x00b4, 0x00b8, 2},
+ {0x00d7, 0x00f7, 32},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x03f6, 113},
+ {0x0482, 0x0606, 388},
+ {0x0607, 0x0608, 1},
+ {0x060b, 0x060e, 3},
+ {0x060f, 0x06de, 207},
+ {0x06e9, 0x06fd, 20},
+ {0x06fe, 0x07f6, 248},
+ {0x09f2, 0x09f3, 1},
+ {0x09fa, 0x09fb, 1},
+ {0x0af1, 0x0b70, 127},
+ {0x0bf3, 0x0bfa, 1},
+ {0x0c7f, 0x0d79, 250},
+ {0x0e3f, 0x0f01, 194},
+ {0x0f02, 0x0f03, 1},
+ {0x0f13, 0x0f17, 1},
+ {0x0f1a, 0x0f1f, 1},
+ {0x0f34, 0x0f38, 2},
+ {0x0fbe, 0x0fc5, 1},
+ {0x0fc7, 0x0fcc, 1},
+ {0x0fce, 0x0fcf, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x109e, 0x109f, 1},
+ {0x1360, 0x1390, 48},
+ {0x1391, 0x1399, 1},
+ {0x17db, 0x1940, 357},
+ {0x19de, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x1fbd, 0x1fbf, 2},
+ {0x1fc0, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x20a0, 0x20b9, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x2118, 1},
+ {0x211e, 0x2123, 1},
+ {0x2125, 0x2129, 2},
+ {0x212e, 0x213a, 12},
+ {0x213b, 0x2140, 5},
+ {0x2141, 0x2144, 1},
+ {0x214a, 0x214d, 1},
+ {0x214f, 0x2190, 65},
+ {0x2191, 0x2328, 1},
+ {0x232b, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x26ff, 1},
+ {0x2701, 0x2767, 1},
+ {0x2794, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27ce, 2},
+ {0x27cf, 0x27e5, 1},
+ {0x27f0, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2b4c, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2ce5, 0x2cea, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3004, 0x3012, 14},
+ {0x3013, 0x3020, 13},
+ {0x3036, 0x3037, 1},
+ {0x303e, 0x303f, 1},
+ {0x309b, 0x309c, 1},
+ {0x3190, 0x3191, 1},
+ {0x3196, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3200, 0x321e, 1},
+ {0x322a, 0x3250, 1},
+ {0x3260, 0x327f, 1},
+ {0x328a, 0x32b0, 1},
+ {0x32c0, 0x32fe, 1},
+ {0x3300, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa490, 0xa4c6, 1},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa839, 1},
+ {0xaa77, 0xaa79, 1},
+ {0xfb29, 0xfbb2, 137},
+ {0xfbb3, 0xfbc1, 1},
+ {0xfdfc, 0xfdfd, 1},
+ {0xfe62, 0xfe64, 2},
+ {0xfe65, 0xfe66, 1},
+ {0xfe69, 0xff04, 155},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff3e, 0xff40, 2},
+ {0xff5c, 0xff5e, 2},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfffc, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10102, 0x10137, 53},
+ {0x10138, 0x1013f, 1},
+ {0x10179, 0x10189, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d164, 1},
+ {0x1d16a, 0x1d16c, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d200, 0x1d241, 1},
+ {0x1d245, 0x1d300, 187},
+ {0x1d301, 0x1d356, 1},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f442, 2},
+ {0x1f443, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f61c, 2},
+ {0x1f61d, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f630, 3},
+ {0x1f631, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ },
+}
+
+var _Z = &RangeTable{
+ R16: []Range16{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var _Me = &RangeTable{
+ R16: []Range16{
+ {0x0488, 0x0489, 1},
+ {0x20dd, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
+ },
+}
+
+var _Mc = &RangeTable{
+ R16: []Range16{
+ {0x0903, 0x093b, 56},
+ {0x093e, 0x0940, 1},
+ {0x0949, 0x094c, 1},
+ {0x094e, 0x094f, 1},
+ {0x0982, 0x0983, 1},
+ {0x09be, 0x09c0, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x0a03, 44},
+ {0x0a3e, 0x0a40, 1},
+ {0x0a83, 0x0abe, 59},
+ {0x0abf, 0x0ac0, 1},
+ {0x0ac9, 0x0acb, 2},
+ {0x0acc, 0x0b02, 54},
+ {0x0b03, 0x0b3e, 59},
+ {0x0b40, 0x0b47, 7},
+ {0x0b48, 0x0b4b, 3},
+ {0x0b4c, 0x0b57, 11},
+ {0x0bbe, 0x0bbf, 1},
+ {0x0bc1, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c41, 0x0c44, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc0, 2},
+ {0x0cc1, 0x0cc4, 1},
+ {0x0cc7, 0x0cc8, 1},
+ {0x0cca, 0x0ccb, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d40, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d82, 43},
+ {0x0d83, 0x0dcf, 76},
+ {0x0dd0, 0x0dd1, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f7f, 0x102b, 172},
+ {0x102c, 0x1031, 5},
+ {0x1038, 0x103b, 3},
+ {0x103c, 0x1056, 26},
+ {0x1057, 0x1062, 11},
+ {0x1063, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1083, 0x1084, 1},
+ {0x1087, 0x108c, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109c, 1},
+ {0x17b6, 0x17be, 8},
+ {0x17bf, 0x17c5, 1},
+ {0x17c7, 0x17c8, 1},
+ {0x1923, 0x1926, 1},
+ {0x1929, 0x192b, 1},
+ {0x1930, 0x1931, 1},
+ {0x1933, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a19, 0x1a1b, 1},
+ {0x1a55, 0x1a57, 2},
+ {0x1a61, 0x1a63, 2},
+ {0x1a64, 0x1a6d, 9},
+ {0x1a6e, 0x1a72, 1},
+ {0x1b04, 0x1b35, 49},
+ {0x1b3b, 0x1b3d, 2},
+ {0x1b3e, 0x1b41, 1},
+ {0x1b43, 0x1b44, 1},
+ {0x1b82, 0x1ba1, 31},
+ {0x1ba6, 0x1ba7, 1},
+ {0x1baa, 0x1be7, 61},
+ {0x1bea, 0x1bec, 1},
+ {0x1bee, 0x1bf2, 4},
+ {0x1bf3, 0x1c24, 49},
+ {0x1c25, 0x1c2b, 1},
+ {0x1c34, 0x1c35, 1},
+ {0x1ce1, 0x1cf2, 17},
+ {0xa823, 0xa824, 1},
+ {0xa827, 0xa880, 89},
+ {0xa881, 0xa8b4, 51},
+ {0xa8b5, 0xa8c3, 1},
+ {0xa952, 0xa953, 1},
+ {0xa983, 0xa9b4, 49},
+ {0xa9b5, 0xa9ba, 5},
+ {0xa9bb, 0xa9bd, 2},
+ {0xa9be, 0xa9c0, 1},
+ {0xaa2f, 0xaa30, 1},
+ {0xaa33, 0xaa34, 1},
+ {0xaa4d, 0xaa7b, 46},
+ {0xabe3, 0xabe4, 1},
+ {0xabe6, 0xabe7, 1},
+ {0xabe9, 0xabea, 1},
+ {0xabec, 0xabec, 1},
+ },
+ R32: []Range32{
+ {0x11000, 0x11000, 1},
+ {0x11002, 0x11082, 128},
+ {0x110b0, 0x110b2, 1},
+ {0x110b7, 0x110b8, 1},
+ {0x1d165, 0x1d166, 1},
+ {0x1d16d, 0x1d172, 1},
+ },
+}
+
+var _Mn = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0487, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065f, 1},
+ {0x0670, 0x06d6, 102},
+ {0x06d7, 0x06dc, 1},
+ {0x06df, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ea, 0x06ed, 1},
+ {0x0711, 0x0730, 31},
+ {0x0731, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f3, 1},
+ {0x0816, 0x0819, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082d, 1},
+ {0x0859, 0x085b, 1},
+ {0x0900, 0x0902, 1},
+ {0x093a, 0x093c, 2},
+ {0x0941, 0x0948, 1},
+ {0x094d, 0x0951, 4},
+ {0x0952, 0x0957, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x09bc, 59},
+ {0x09c1, 0x09c4, 1},
+ {0x09cd, 0x09e2, 21},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a3c, 58},
+ {0x0a41, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a82, 1},
+ {0x0abc, 0x0ac1, 5},
+ {0x0ac2, 0x0ac5, 1},
+ {0x0ac7, 0x0ac8, 1},
+ {0x0acd, 0x0ae2, 21},
+ {0x0ae3, 0x0b01, 30},
+ {0x0b3c, 0x0b3f, 3},
+ {0x0b41, 0x0b44, 1},
+ {0x0b4d, 0x0b56, 9},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bc0, 62},
+ {0x0bcd, 0x0c3e, 113},
+ {0x0c3f, 0x0c40, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0cbc, 0x0cbf, 3},
+ {0x0cc6, 0x0ccc, 6},
+ {0x0ccd, 0x0ce2, 21},
+ {0x0ce3, 0x0d41, 94},
+ {0x0d42, 0x0d44, 1},
+ {0x0d4d, 0x0d62, 21},
+ {0x0d63, 0x0dca, 103},
+ {0x0dd2, 0x0dd4, 1},
+ {0x0dd6, 0x0e31, 91},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f71, 0x0f7e, 1},
+ {0x0f80, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f8d, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102d, 103},
+ {0x102e, 0x1030, 1},
+ {0x1032, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x103d, 0x103e, 1},
+ {0x1058, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1085, 3},
+ {0x1086, 0x108d, 7},
+ {0x109d, 0x135d, 704},
+ {0x135e, 0x135f, 1},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b7, 0x17bd, 1},
+ {0x17c6, 0x17c9, 3},
+ {0x17ca, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x1922, 1},
+ {0x1927, 0x1928, 1},
+ {0x1932, 0x1939, 7},
+ {0x193a, 0x193b, 1},
+ {0x1a17, 0x1a18, 1},
+ {0x1a56, 0x1a58, 2},
+ {0x1a59, 0x1a5e, 1},
+ {0x1a60, 0x1a62, 2},
+ {0x1a65, 0x1a6c, 1},
+ {0x1a73, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b03, 1},
+ {0x1b34, 0x1b36, 2},
+ {0x1b37, 0x1b3a, 1},
+ {0x1b3c, 0x1b42, 6},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b81, 1},
+ {0x1ba2, 0x1ba5, 1},
+ {0x1ba8, 0x1ba9, 1},
+ {0x1be6, 0x1be8, 2},
+ {0x1be9, 0x1bed, 4},
+ {0x1bef, 0x1bf1, 1},
+ {0x1c2c, 0x1c33, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1dc0, 211},
+ {0x1dc1, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e5, 4},
+ {0x20e6, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2d7f, 0x2de0, 97},
+ {0x2de1, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa67c, 13},
+ {0xa67d, 0xa6f0, 115},
+ {0xa6f1, 0xa802, 273},
+ {0xa806, 0xa80b, 5},
+ {0xa825, 0xa826, 1},
+ {0xa8c4, 0xa8e0, 28},
+ {0xa8e1, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa951, 1},
+ {0xa980, 0xa982, 1},
+ {0xa9b3, 0xa9b6, 3},
+ {0xa9b7, 0xa9b9, 1},
+ {0xa9bc, 0xaa29, 109},
+ {0xaa2a, 0xaa2e, 1},
+ {0xaa31, 0xaa32, 1},
+ {0xaa35, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe5, 292},
+ {0xabe8, 0xabed, 5},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11001, 1474},
+ {0x11038, 0x11046, 1},
+ {0x11080, 0x11081, 1},
+ {0x110b3, 0x110b6, 1},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Zl = &RangeTable{
+ R16: []Range16{
+ {0x2028, 0x2028, 1},
+ },
+}
+
var _Zp = &RangeTable{
R16: []Range16{
{0x2029, 0x2029, 1},
@@ -2068,40 +2702,53 @@ var _Lo = &RangeTable{
}
var (
- Cc = _Cc // Cc is the set of Unicode characters in category Cc.
- Cf = _Cf // Cf is the set of Unicode characters in category Cf.
- Co = _Co // Co is the set of Unicode characters in category Co.
- Cs = _Cs // Cs is the set of Unicode characters in category Cs.
- Digit = _Nd // Digit is the set of Unicode characters with the "decimal digit" property.
- Nd = _Nd // Nd is the set of Unicode characters in category Nd.
- Letter = letter // Letter is the set of Unicode letters.
- Lm = _Lm // Lm is the set of Unicode characters in category Lm.
- Lo = _Lo // Lo is the set of Unicode characters in category Lo.
- Lower = _Ll // Lower is the set of Unicode lower case letters.
- Ll = _Ll // Ll is the set of Unicode characters in category Ll.
- Mc = _Mc // Mc is the set of Unicode characters in category Mc.
- Me = _Me // Me is the set of Unicode characters in category Me.
- Mn = _Mn // Mn is the set of Unicode characters in category Mn.
- Nl = _Nl // Nl is the set of Unicode characters in category Nl.
- No = _No // No is the set of Unicode characters in category No.
- Pc = _Pc // Pc is the set of Unicode characters in category Pc.
- Pd = _Pd // Pd is the set of Unicode characters in category Pd.
- Pe = _Pe // Pe is the set of Unicode characters in category Pe.
- Pf = _Pf // Pf is the set of Unicode characters in category Pf.
- Pi = _Pi // Pi is the set of Unicode characters in category Pi.
- Po = _Po // Po is the set of Unicode characters in category Po.
- Ps = _Ps // Ps is the set of Unicode characters in category Ps.
- Sc = _Sc // Sc is the set of Unicode characters in category Sc.
- Sk = _Sk // Sk is the set of Unicode characters in category Sk.
- Sm = _Sm // Sm is the set of Unicode characters in category Sm.
- So = _So // So is the set of Unicode characters in category So.
- Title = _Lt // Title is the set of Unicode title case letters.
- Lt = _Lt // Lt is the set of Unicode characters in category Lt.
- Upper = _Lu // Upper is the set of Unicode upper case letters.
- Lu = _Lu // Lu is the set of Unicode characters in category Lu.
- Zl = _Zl // Zl is the set of Unicode characters in category Zl.
- Zp = _Zp // Zp is the set of Unicode characters in category Zp.
- Zs = _Zs // Zs is the set of Unicode characters in category Zs.
+ Cc = _Cc // Cc is the set of Unicode characters in category Cc.
+ Cf = _Cf // Cf is the set of Unicode characters in category Cf.
+ Co = _Co // Co is the set of Unicode characters in category Co.
+ Cs = _Cs // Cs is the set of Unicode characters in category Cs.
+ Digit = _Nd // Digit is the set of Unicode characters with the "decimal digit" property.
+ Nd = _Nd // Nd is the set of Unicode characters in category Nd.
+ Letter = _L // Letter/L is the set of Unicode letters, category L.
+ L = _L
+ Lm = _Lm // Lm is the set of Unicode characters in category Lm.
+ Lo = _Lo // Lo is the set of Unicode characters in category Lo.
+ Lower = _Ll // Lower is the set of Unicode lower case letters.
+ Ll = _Ll // Ll is the set of Unicode characters in category Ll.
+ Mark = _M // Mark/M is the set of Unicode mark characters, category M.
+ M = _M
+ Mc = _Mc // Mc is the set of Unicode characters in category Mc.
+ Me = _Me // Me is the set of Unicode characters in category Me.
+ Mn = _Mn // Mn is the set of Unicode characters in category Mn.
+ Nl = _Nl // Nl is the set of Unicode characters in category Nl.
+ No = _No // No is the set of Unicode characters in category No.
+ Number = _N // Number/N is the set of Unicode number characters, category N.
+ N = _N
+ Other = _C // Other/C is the set of Unicode control and special characters, category C.
+ C = _C
+ Pc = _Pc // Pc is the set of Unicode characters in category Pc.
+ Pd = _Pd // Pd is the set of Unicode characters in category Pd.
+ Pe = _Pe // Pe is the set of Unicode characters in category Pe.
+ Pf = _Pf // Pf is the set of Unicode characters in category Pf.
+ Pi = _Pi // Pi is the set of Unicode characters in category Pi.
+ Po = _Po // Po is the set of Unicode characters in category Po.
+ Ps = _Ps // Ps is the set of Unicode characters in category Ps.
+ Punct = _P // Punct/P is the set of Unicode punctuation characters, category P.
+ P = _P
+ Sc = _Sc // Sc is the set of Unicode characters in category Sc.
+ Sk = _Sk // Sk is the set of Unicode characters in category Sk.
+ Sm = _Sm // Sm is the set of Unicode characters in category Sm.
+ So = _So // So is the set of Unicode characters in category So.
+ Space = _Z // Space/Z is the set of Unicode space characters, category Z.
+ Z = _Z
+ Symbol = _S // Symbol/S is the set of Unicode symbol characters, category S.
+ S = _S
+ Title = _Lt // Title is the set of Unicode title case letters.
+ Lt = _Lt // Lt is the set of Unicode characters in category Lt.
+ Upper = _Lu // Upper is the set of Unicode upper case letters.
+ Lu = _Lu // Lu is the set of Unicode characters in category Lu.
+ Zl = _Zl // Zl is the set of Unicode characters in category Zl.
+ Zp = _Zp // Zp is the set of Unicode characters in category Zp.
+ Zs = _Zs // Zs is the set of Unicode characters in category Zs.
)
// Generated by running
@@ -4764,6 +5411,264 @@ var _CaseRanges = []CaseRange{
{0x10400, 0x10427, d{0, 40, 0}},
{0x10428, 0x1044F, d{-40, 0, -40}},
}
-
-// Range entries: 2715 16-bit, 545 32-bit, 3260 total.
-// Range bytes: 16290 16-bit, 6540 32-bit, 22830 total.
+var properties = [MaxLatin1 + 1]uint8{
+ 0x00: pC, // '\x00'
+ 0x01: pC, // '\x01'
+ 0x02: pC, // '\x02'
+ 0x03: pC, // '\x03'
+ 0x04: pC, // '\x04'
+ 0x05: pC, // '\x05'
+ 0x06: pC, // '\x06'
+ 0x07: pC, // '\a'
+ 0x08: pC, // '\b'
+ 0x09: pC, // '\t'
+ 0x0A: pC, // '\n'
+ 0x0B: pC, // '\v'
+ 0x0C: pC, // '\f'
+ 0x0D: pC, // '\r'
+ 0x0E: pC, // '\x0e'
+ 0x0F: pC, // '\x0f'
+ 0x10: pC, // '\x10'
+ 0x11: pC, // '\x11'
+ 0x12: pC, // '\x12'
+ 0x13: pC, // '\x13'
+ 0x14: pC, // '\x14'
+ 0x15: pC, // '\x15'
+ 0x16: pC, // '\x16'
+ 0x17: pC, // '\x17'
+ 0x18: pC, // '\x18'
+ 0x19: pC, // '\x19'
+ 0x1A: pC, // '\x1a'
+ 0x1B: pC, // '\x1b'
+ 0x1C: pC, // '\x1c'
+ 0x1D: pC, // '\x1d'
+ 0x1E: pC, // '\x1e'
+ 0x1F: pC, // '\x1f'
+ 0x20: pZ | pp, // ' '
+ 0x21: pP | pp, // '!'
+ 0x22: pP | pp, // '"'
+ 0x23: pP | pp, // '#'
+ 0x24: pS | pp, // '$'
+ 0x25: pP | pp, // '%'
+ 0x26: pP | pp, // '&'
+ 0x27: pP | pp, // '\''
+ 0x28: pP | pp, // '('
+ 0x29: pP | pp, // ')'
+ 0x2A: pP | pp, // '*'
+ 0x2B: pS | pp, // '+'
+ 0x2C: pP | pp, // ','
+ 0x2D: pP | pp, // '-'
+ 0x2E: pP | pp, // '.'
+ 0x2F: pP | pp, // '/'
+ 0x30: pN | pp, // '0'
+ 0x31: pN | pp, // '1'
+ 0x32: pN | pp, // '2'
+ 0x33: pN | pp, // '3'
+ 0x34: pN | pp, // '4'
+ 0x35: pN | pp, // '5'
+ 0x36: pN | pp, // '6'
+ 0x37: pN | pp, // '7'
+ 0x38: pN | pp, // '8'
+ 0x39: pN | pp, // '9'
+ 0x3A: pP | pp, // ':'
+ 0x3B: pP | pp, // ';'
+ 0x3C: pS | pp, // '<'
+ 0x3D: pS | pp, // '='
+ 0x3E: pS | pp, // '>'
+ 0x3F: pP | pp, // '?'
+ 0x40: pP | pp, // '@'
+ 0x41: pLu | pp, // 'A'
+ 0x42: pLu | pp, // 'B'
+ 0x43: pLu | pp, // 'C'
+ 0x44: pLu | pp, // 'D'
+ 0x45: pLu | pp, // 'E'
+ 0x46: pLu | pp, // 'F'
+ 0x47: pLu | pp, // 'G'
+ 0x48: pLu | pp, // 'H'
+ 0x49: pLu | pp, // 'I'
+ 0x4A: pLu | pp, // 'J'
+ 0x4B: pLu | pp, // 'K'
+ 0x4C: pLu | pp, // 'L'
+ 0x4D: pLu | pp, // 'M'
+ 0x4E: pLu | pp, // 'N'
+ 0x4F: pLu | pp, // 'O'
+ 0x50: pLu | pp, // 'P'
+ 0x51: pLu | pp, // 'Q'
+ 0x52: pLu | pp, // 'R'
+ 0x53: pLu | pp, // 'S'
+ 0x54: pLu | pp, // 'T'
+ 0x55: pLu | pp, // 'U'
+ 0x56: pLu | pp, // 'V'
+ 0x57: pLu | pp, // 'W'
+ 0x58: pLu | pp, // 'X'
+ 0x59: pLu | pp, // 'Y'
+ 0x5A: pLu | pp, // 'Z'
+ 0x5B: pP | pp, // '['
+ 0x5C: pP | pp, // '\\'
+ 0x5D: pP | pp, // ']'
+ 0x5E: pS | pp, // '^'
+ 0x5F: pP | pp, // '_'
+ 0x60: pS | pp, // '`'
+ 0x61: pLl | pp, // 'a'
+ 0x62: pLl | pp, // 'b'
+ 0x63: pLl | pp, // 'c'
+ 0x64: pLl | pp, // 'd'
+ 0x65: pLl | pp, // 'e'
+ 0x66: pLl | pp, // 'f'
+ 0x67: pLl | pp, // 'g'
+ 0x68: pLl | pp, // 'h'
+ 0x69: pLl | pp, // 'i'
+ 0x6A: pLl | pp, // 'j'
+ 0x6B: pLl | pp, // 'k'
+ 0x6C: pLl | pp, // 'l'
+ 0x6D: pLl | pp, // 'm'
+ 0x6E: pLl | pp, // 'n'
+ 0x6F: pLl | pp, // 'o'
+ 0x70: pLl | pp, // 'p'
+ 0x71: pLl | pp, // 'q'
+ 0x72: pLl | pp, // 'r'
+ 0x73: pLl | pp, // 's'
+ 0x74: pLl | pp, // 't'
+ 0x75: pLl | pp, // 'u'
+ 0x76: pLl | pp, // 'v'
+ 0x77: pLl | pp, // 'w'
+ 0x78: pLl | pp, // 'x'
+ 0x79: pLl | pp, // 'y'
+ 0x7A: pLl | pp, // 'z'
+ 0x7B: pP | pp, // '{'
+ 0x7C: pS | pp, // '|'
+ 0x7D: pP | pp, // '}'
+ 0x7E: pS | pp, // '~'
+ 0x7F: pC, // '\x7f'
+ 0x80: pC, // '\u0080'
+ 0x81: pC, // '\u0081'
+ 0x82: pC, // '\u0082'
+ 0x83: pC, // '\u0083'
+ 0x84: pC, // '\u0084'
+ 0x85: pC, // '\u0085'
+ 0x86: pC, // '\u0086'
+ 0x87: pC, // '\u0087'
+ 0x88: pC, // '\u0088'
+ 0x89: pC, // '\u0089'
+ 0x8A: pC, // '\u008a'
+ 0x8B: pC, // '\u008b'
+ 0x8C: pC, // '\u008c'
+ 0x8D: pC, // '\u008d'
+ 0x8E: pC, // '\u008e'
+ 0x8F: pC, // '\u008f'
+ 0x90: pC, // '\u0090'
+ 0x91: pC, // '\u0091'
+ 0x92: pC, // '\u0092'
+ 0x93: pC, // '\u0093'
+ 0x94: pC, // '\u0094'
+ 0x95: pC, // '\u0095'
+ 0x96: pC, // '\u0096'
+ 0x97: pC, // '\u0097'
+ 0x98: pC, // '\u0098'
+ 0x99: pC, // '\u0099'
+ 0x9A: pC, // '\u009a'
+ 0x9B: pC, // '\u009b'
+ 0x9C: pC, // '\u009c'
+ 0x9D: pC, // '\u009d'
+ 0x9E: pC, // '\u009e'
+ 0x9F: pC, // '\u009f'
+ 0xA0: pZ, // '\u00a0'
+ 0xA1: pP | pp, // '\u00a1'
+ 0xA2: pS | pp, // '\u00a2'
+ 0xA3: pS | pp, // '\u00a3'
+ 0xA4: pS | pp, // '\u00a4'
+ 0xA5: pS | pp, // '\u00a5'
+ 0xA6: pS | pp, // '\u00a6'
+ 0xA7: pS | pp, // '\u00a7'
+ 0xA8: pS | pp, // '\u00a8'
+ 0xA9: pS | pp, // '\u00a9'
+ 0xAA: pLl | pp, // '\u00aa'
+ 0xAB: pP | pp, // '\u00ab'
+ 0xAC: pS | pp, // '\u00ac'
+ 0xAD: 0, // '\u00ad'
+ 0xAE: pS | pp, // '\u00ae'
+ 0xAF: pS | pp, // '\u00af'
+ 0xB0: pS | pp, // '\u00b0'
+ 0xB1: pS | pp, // '\u00b1'
+ 0xB2: pN | pp, // '\u00b2'
+ 0xB3: pN | pp, // '\u00b3'
+ 0xB4: pS | pp, // '\u00b4'
+ 0xB5: pLl | pp, // '\u00b5'
+ 0xB6: pS | pp, // '\u00b6'
+ 0xB7: pP | pp, // '\u00b7'
+ 0xB8: pS | pp, // '\u00b8'
+ 0xB9: pN | pp, // '\u00b9'
+ 0xBA: pLl | pp, // '\u00ba'
+ 0xBB: pP | pp, // '\u00bb'
+ 0xBC: pN | pp, // '\u00bc'
+ 0xBD: pN | pp, // '\u00bd'
+ 0xBE: pN | pp, // '\u00be'
+ 0xBF: pP | pp, // '\u00bf'
+ 0xC0: pLu | pp, // '\u00c0'
+ 0xC1: pLu | pp, // '\u00c1'
+ 0xC2: pLu | pp, // '\u00c2'
+ 0xC3: pLu | pp, // '\u00c3'
+ 0xC4: pLu | pp, // '\u00c4'
+ 0xC5: pLu | pp, // '\u00c5'
+ 0xC6: pLu | pp, // '\u00c6'
+ 0xC7: pLu | pp, // '\u00c7'
+ 0xC8: pLu | pp, // '\u00c8'
+ 0xC9: pLu | pp, // '\u00c9'
+ 0xCA: pLu | pp, // '\u00ca'
+ 0xCB: pLu | pp, // '\u00cb'
+ 0xCC: pLu | pp, // '\u00cc'
+ 0xCD: pLu | pp, // '\u00cd'
+ 0xCE: pLu | pp, // '\u00ce'
+ 0xCF: pLu | pp, // '\u00cf'
+ 0xD0: pLu | pp, // '\u00d0'
+ 0xD1: pLu | pp, // '\u00d1'
+ 0xD2: pLu | pp, // '\u00d2'
+ 0xD3: pLu | pp, // '\u00d3'
+ 0xD4: pLu | pp, // '\u00d4'
+ 0xD5: pLu | pp, // '\u00d5'
+ 0xD6: pLu | pp, // '\u00d6'
+ 0xD7: pS | pp, // '\u00d7'
+ 0xD8: pLu | pp, // '\u00d8'
+ 0xD9: pLu | pp, // '\u00d9'
+ 0xDA: pLu | pp, // '\u00da'
+ 0xDB: pLu | pp, // '\u00db'
+ 0xDC: pLu | pp, // '\u00dc'
+ 0xDD: pLu | pp, // '\u00dd'
+ 0xDE: pLu | pp, // '\u00de'
+ 0xDF: pLl | pp, // '\u00df'
+ 0xE0: pLl | pp, // '\u00e0'
+ 0xE1: pLl | pp, // '\u00e1'
+ 0xE2: pLl | pp, // '\u00e2'
+ 0xE3: pLl | pp, // '\u00e3'
+ 0xE4: pLl | pp, // '\u00e4'
+ 0xE5: pLl | pp, // '\u00e5'
+ 0xE6: pLl | pp, // '\u00e6'
+ 0xE7: pLl | pp, // '\u00e7'
+ 0xE8: pLl | pp, // '\u00e8'
+ 0xE9: pLl | pp, // '\u00e9'
+ 0xEA: pLl | pp, // '\u00ea'
+ 0xEB: pLl | pp, // '\u00eb'
+ 0xEC: pLl | pp, // '\u00ec'
+ 0xED: pLl | pp, // '\u00ed'
+ 0xEE: pLl | pp, // '\u00ee'
+ 0xEF: pLl | pp, // '\u00ef'
+ 0xF0: pLl | pp, // '\u00f0'
+ 0xF1: pLl | pp, // '\u00f1'
+ 0xF2: pLl | pp, // '\u00f2'
+ 0xF3: pLl | pp, // '\u00f3'
+ 0xF4: pLl | pp, // '\u00f4'
+ 0xF5: pLl | pp, // '\u00f5'
+ 0xF6: pLl | pp, // '\u00f6'
+ 0xF7: pS | pp, // '\u00f7'
+ 0xF8: pLl | pp, // '\u00f8'
+ 0xF9: pLl | pp, // '\u00f9'
+ 0xFA: pLl | pp, // '\u00fa'
+ 0xFB: pLl | pp, // '\u00fb'
+ 0xFC: pLl | pp, // '\u00fc'
+ 0xFD: pLl | pp, // '\u00fd'
+ 0xFE: pLl | pp, // '\u00fe'
+ 0xFF: pLl | pp, // '\u00ff'
+}
+
+// Range entries: 3190 16-bit, 657 32-bit, 3847 total.
+// Range bytes: 19140 16-bit, 7884 32-bit, 27024 total.