Commits

Aram Hăvărneanu committed de60e4c Merge

merge upstream

Comments (0)

Files changed (47)

Add a comment to this file

src/cmd/dist/buildruntime.c

File contents unchanged.

 		dst->b[w] = src1->b[w] | src2->b[w];
 }
 
+/* intersection */
+void
+bvand(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+	int32 i, w;
+
+	if(dst->n != src1->n || dst->n != src2->n)
+		fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n);
+	for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
+		dst->b[w] = src1->b[w] & src2->b[w];
+}
+
 void
 bvprint(Bvec *bv)
 {
 int	bvisempty(Bvec *bv);
 void	bvnot(Bvec *bv);
 void	bvor(Bvec *dst, Bvec *src1, Bvec *src2);
+void	bvand(Bvec *dst, Bvec *src1, Bvec *src2);
 void	bvprint(Bvec *bv);
 void	bvreset(Bvec *bv, int32 i);
 void	bvresetall(Bvec *bv);

src/cmd/gc/pgen.c

 		return +1;
 	if(a->type->width > b->type->width)
 		return -1;
-	return 0;
+
+	return strcmp(a->sym->name, b->sym->name);
 }
 
 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.

src/cmd/gc/plive.c

 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Garbage collector liveness bitmap generation.
+
+// The command line flag -live causes this code to print debug information.
+// The levels are:
+//
+//	-live (aka -live=1): print liveness lists as code warnings at safe points
+//	-live=2: print an assembly listing with liveness annotations
+//	-live=3: print information during each computation phase (much chattier)
+//
+// Each level includes the earlier output as well.
+
 #include <u.h>
 #include <libc.h>
 #include "gg.h"
 	Array *vars;
 
 	// A list of basic blocks that are overlayed on the instruction list.
+	// The blocks are roughly in the same order as the instructions
+	// in the function (first block has TEXT instruction, and so on).
 	Array *cfg;
 
-	// Summary sets of block effects.  The upward exposed variables and
-	// variables killed sets are computed during the dataflow prologue.  The
-	// live in and live out are solved for and serialized in the epilogue.
+	// Summary sets of block effects.
+	// The Bvec** is indexed by bb->rpo to yield a single Bvec*.
+	// That bit vector is indexed by variable number (same as lv->vars).
+	//
+	// Computed during livenessprologue using only the content of
+	// individual blocks:
+	//
+	//	uevar: upward exposed variables (used before set in block)
+	//	varkill: killed variables (set in block)
+	//	avarinit: addrtaken variables set or used (proof of initialization)
+	//
+	// Computed during livenesssolve using control flow information:
+	//
+	//	livein: variables live at block entry
+	//	liveout: variables live at block exit
+	//	avarinitany: addrtaken variables possibly initialized at block exit
+	//		(initialized in block or at exit from any predecessor block)
+	//	avarinitall: addrtaken variables certainly initialized at block exit
+	//		(initialized in block or at exit from all predecessor blocks)
 	Bvec **uevar;
 	Bvec **varkill;
 	Bvec **livein;
 	Bvec **liveout;
+	Bvec **avarinit;
+	Bvec **avarinitany;
+	Bvec **avarinitall;
 
 	// An array with a bit vector for each safe point tracking live pointers
-	// in the arguments and locals area.
+	// in the arguments and locals area, indexed by bb->rpo.
 	Array *argslivepointers;
 	Array *livepointers;
 
 	// An array with a bit vector for each safe point tracking dead values
-	// pointers in the arguments and locals area.
+	// pointers in the arguments and locals area, indexed by bb->rpo.
 	Array *argsdeadvalues;
 	Array *deadvalues;
 };
 
-static int printnoise = 0;
-
 static void*
 xmalloc(uintptr size)
 {
 	return 0;
 }
 
-// Computes the upward exposure and kill effects of an instruction on a set of
+// Computes the effects of an instruction on a set of
 // variables.  The vars argument is an array of Node*s.
+//
+// The output vectors give bits for variables:
+//	uevar - used by this instruction
+//	varkill - set by this instruction
+//	avarinit - initialized or referred to by this instruction,
+//		only for variables with address taken but not escaping to heap
+//
+// The avarinit output serves as a signal that the data has been
+// initialized, because any use of a variable must come after its
+// initialization.
 static void
-progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill)
+progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
 {
 	ProgInfo info;
 	Adr *from;
 
 	bvresetall(uevar);
 	bvresetall(varkill);
+	bvresetall(avarinit);
+
 	proginfo(&info, prog);
 	if(prog->as == ARET) {
 		// Return instructions implicitly read all the arguments.  For
 			case PPARAMOUT:
 				bvset(uevar, i);
 				break;
-			case PAUTO:
-				// Because the lifetime of stack variables
-				// that have their address taken is undecidable,
-				// we conservatively assume their lifetime
-				// extends to the return as well.
-				if(isfat(node->type) || node->addrtaken)
-					bvset(uevar, i);
 			}
 		}
 		return;
 				pos = arrayindexof(vars, from->node);
 				if(pos == -1)
 					goto Next;
+				if(from->node->addrtaken)
+					bvset(avarinit, pos);
 				if(info.flags & (LeftRead | LeftAddr))
 					bvset(uevar, pos);
 				if(info.flags & LeftWrite)
 				pos = arrayindexof(vars, to->node);
 				if(pos == -1)
 					goto Next1;
+				if(to->node->addrtaken)
+					bvset(avarinit, pos);
 				if(info.flags & (RightRead | RightAddr))
 					bvset(uevar, pos);
 				if(info.flags & RightWrite)
 	result->varkill = xmalloc(sizeof(Bvec*) * nblocks);
 	result->livein = xmalloc(sizeof(Bvec*) * nblocks);
 	result->liveout = xmalloc(sizeof(Bvec*) * nblocks);
+	result->avarinit = xmalloc(sizeof(Bvec*) * nblocks);
+	result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks);
+	result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks);
 
 	nvars = arraylength(vars);
 	for(i = 0; i < nblocks; i++) {
 		result->varkill[i] = bvalloc(nvars);
 		result->livein[i] = bvalloc(nvars);
 		result->liveout[i] = bvalloc(nvars);
+		result->avarinit[i] = bvalloc(nvars);
+		result->avarinitany[i] = bvalloc(nvars);
+		result->avarinitall[i] = bvalloc(nvars);
 	}
 
 	result->livepointers = arraynew(0, sizeof(Bvec*));
 		free(lv->varkill[i]);
 		free(lv->livein[i]);
 		free(lv->liveout[i]);
+		free(lv->avarinit[i]);
+		free(lv->avarinitany[i]);
+		free(lv->avarinitall[i]);
 	}
 
 	free(lv->uevar);
 	free(lv->varkill);
 	free(lv->livein);
 	free(lv->liveout);
+	free(lv->avarinit);
+	free(lv->avarinitany);
+	free(lv->avarinitall);
 
 	free(lv);
 }
 
 static void
-printeffects(Prog *p, Bvec *uevar, Bvec *varkill)
+printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
 {
 	print("effects of %P", p);
 	print("\nuevar: ");
 	bvprint(uevar);
 	print("\nvarkill: ");
 	bvprint(varkill);
+	print("\navarinit: ");
+	bvprint(avarinit);
 	print("\n");
 }
 
 	printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars);
 	printvars("\tlivein", lv->livein[bb->rpo], lv->vars);
 	printvars("\tliveout", lv->liveout[bb->rpo], lv->vars);
+	printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars);
+	printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars);
+	printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars);
 
 	print("\tprog:\n");
 	for(prog = bb->first;; prog = prog->link) {
 			break;
 		}
 	}
-	// In various and obscure circumstances, such as methods with an unused
-	// receiver, the this argument and in arguments are omitted from the
-	// node list.  We must explicitly preserve these values to ensure that
-	// the addresses printed in backtraces are valid.
+	
+	// The node list only contains declared names.
+	// If the receiver or arguments are unnamed, they will be omitted
+	// from the list above. Preserve those values - even though they are unused -
+	// in order to keep their addresses live for use in stack traces.
 	thisargtype = getthisx(lv->fn->type);
 	if(thisargtype != nil) {
 		xoffset = 0;
 static Prog*
 newpcdataprog(Prog *prog, int32 index)
 {
-	Node from;
-	Node to;
+	Node from, to;
 	Prog *pcdata;
 
 	nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
 livenessprologue(Liveness *lv)
 {
 	BasicBlock *bb;
-	Bvec *uevar;
-	Bvec *varkill;
+	Bvec *uevar, *varkill, *avarinit;
 	Prog *prog;
 	int32 i;
 	int32 nvars;
 	nvars = arraylength(lv->vars);
 	uevar = bvalloc(nvars);
 	varkill = bvalloc(nvars);
+	avarinit = bvalloc(nvars);
 	for(i = 0; i < arraylength(lv->cfg); i++) {
 		bb = *(BasicBlock**)arrayget(lv->cfg, i);
 		// Walk the block instructions backward and update the block
 		// effects with the each prog effects.
 		for(prog = bb->last; prog != nil; prog = prog->opt) {
-			progeffects(prog, lv->vars, uevar, varkill);
-			if(0) printeffects(prog, uevar, varkill);
+			progeffects(prog, lv->vars, uevar, varkill, avarinit);
+			if(debuglive >= 3)
+				printeffects(prog, uevar, varkill, avarinit);
 			bvor(lv->varkill[i], lv->varkill[i], varkill);
 			bvandnot(lv->uevar[i], lv->uevar[i], varkill);
-			bvor(lv->uevar[i], lv->uevar[i], uevar);
+			bvor(lv->uevar[i], lv->uevar[i], uevar);			
+			bvor(lv->avarinit[i], lv->avarinit[i], avarinit);
 		}
 	}
 	free(uevar);
 	free(varkill);
+	free(avarinit);
 }
 
 // Solve the liveness dataflow equations.
 static void
 livenesssolve(Liveness *lv)
 {
-	BasicBlock *bb;
-	BasicBlock *succ;
-	Bvec *newlivein;
-	Bvec *newliveout;
-	int32 rpo;
-	int32 i;
-	int32 j;
-	int change;
+	BasicBlock *bb, *succ, *pred;
+	Bvec *newlivein, *newliveout, *any, *all;
+	int32 rpo, i, j, change;
 
 	// These temporary bitvectors exist to avoid successive allocations and
 	// frees within the loop.
 	newlivein = bvalloc(arraylength(lv->vars));
 	newliveout = bvalloc(arraylength(lv->vars));
+	any = bvalloc(arraylength(lv->vars));
+	all = bvalloc(arraylength(lv->vars));
+
+	// Push avarinitall, avarinitany forward.
+	// avarinitall says the addressed var is initialized along all paths reaching the block exit.
+	// avarinitany says the addressed var is initialized along some path reaching the block exit.
+	for(i = 0; i < arraylength(lv->cfg); i++) {
+		bb = *(BasicBlock**)arrayget(lv->cfg, i);
+		rpo = bb->rpo;
+		if(i == 0)
+			bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]);
+		else {
+			bvresetall(lv->avarinitall[rpo]);
+			bvnot(lv->avarinitall[rpo]);
+		}
+		bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]);
+	}
+
+	change = 1;
+	while(change != 0) {
+		change = 0;
+		for(i = 0; i < arraylength(lv->cfg); i++) {
+			bb = *(BasicBlock**)arrayget(lv->cfg, i);
+			rpo = bb->rpo;
+			bvresetall(any);
+			bvresetall(all);
+			for(j = 0; j < arraylength(bb->pred); j++) {
+				pred = *(BasicBlock**)arrayget(bb->pred, j);
+				if(j == 0) {
+					bvcopy(any, lv->avarinitany[pred->rpo]);
+					bvcopy(all, lv->avarinitall[pred->rpo]);
+				} else {
+					bvor(any, any, lv->avarinitany[pred->rpo]);
+					bvand(all, all, lv->avarinitall[pred->rpo]);
+				}
+			}
+			bvor(any, any, lv->avarinit[rpo]);
+			bvor(all, all, lv->avarinit[rpo]);
+			if(bvcmp(any, lv->avarinitany[rpo])) {
+				change = 1;
+				bvcopy(lv->avarinitany[rpo], any);
+			}
+			if(bvcmp(all, lv->avarinitall[rpo])) {
+				change = 1;
+				bvcopy(lv->avarinitall[rpo], all);
+			}
+		}
+	}
 
 	// Iterate through the blocks in reverse round-robin fashion.  A work
 	// queue might be slightly faster.  As is, the number of iterations is
 		// Walk blocks in the general direction of propagation.  This
 		// improves convergence.
 		for(i = arraylength(lv->cfg) - 1; i >= 0; i--) {
+			// A variable is live on output from this block
+			// if it is live on input to some successor.
+			//
 			// out[b] = \bigcup_{s \in succ[b]} in[s]
 			bb = *(BasicBlock**)arrayget(lv->cfg, i);
 			rpo = bb->rpo;
 				change = 1;
 				bvcopy(lv->liveout[rpo], newliveout);
 			}
+
+			// A variable is live on input to this block
+			// if it is live on output from this block and
+			// not set by the code in this block.
+			//
 			// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
 			bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]);
 			bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]);
 
 	free(newlivein);
 	free(newliveout);
+	free(any);
+	free(all);
+}
+
+// This function is slow but it is only used for generating debug prints.
+// Check whether n is marked live in args/locals.
+static int
+islive(Node *n, Bvec *args, Bvec *locals)
+{
+	int i;
+
+	switch(n->class) {
+	case PPARAM:
+	case PPARAMOUT:
+		for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+			if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i))
+				return 1;
+		break;
+	case PAUTO:
+		for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
+			if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i))
+				return 1;
+		break;
+	}
+	return 0;
 }
 
 // Visits all instructions in a basic block and computes a bit vector of live
 static void
 livenessepilogue(Liveness *lv)
 {
-	BasicBlock *bb;
-	Bvec *livein, *liveout, *uevar, *varkill, *args, *locals;
+	BasicBlock *bb, *pred;
+	Bvec *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all;
+	Node *n;
 	Prog *p, *next;
-	int32 i, j, nmsg, nvars, pos;
+	int32 i, j, numlive, startmsg, nmsg, nvars, pos;
 	char **msg;
 	Fmt fmt;
 
 	liveout = bvalloc(nvars);
 	uevar = bvalloc(nvars);
 	varkill = bvalloc(nvars);
+	avarinit = bvalloc(nvars);
+	any = bvalloc(nvars);
+	all = bvalloc(nvars);
 	msg = nil;
 	nmsg = 0;
+	startmsg = 0;
 
 	for(i = 0; i < arraylength(lv->cfg); i++) {
 		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		bvcopy(livein, lv->liveout[bb->rpo]);
-		// Walk forward through the basic block instructions and
-		// allocate and empty map for those instructions that need them
-		for(p = bb->last; p != nil; p = p->opt) {
-			if(!issafepoint(p))
-				continue;
-
-			// Allocate a bit vector for each class and facet of
-			// value we are tracking.
-
-			// Live stuff first.
-			args = bvalloc(argswords() * BitsPerPointer);
-			arrayadd(lv->argslivepointers, &args);
-			locals = bvalloc(localswords() * BitsPerPointer);
-			arrayadd(lv->livepointers, &locals);
-
-			// Dead stuff second.
-			if(lv->deadvalues != nil) {
-				args = bvalloc(argswords() * BitsPerPointer);
-				arrayadd(lv->argsdeadvalues, &args);
-				locals = bvalloc(localswords() * BitsPerPointer);
-				arrayadd(lv->deadvalues, &locals);
+		
+		// Compute avarinitany and avarinitall for entry to block.
+		// This duplicates information known during livenesssolve
+		// but avoids storing two more vectors for each block.
+		bvresetall(any);
+		bvresetall(all);
+		for(j = 0; j < arraylength(bb->pred); j++) {
+			pred = *(BasicBlock**)arrayget(bb->pred, j);
+			if(j == 0) {
+				bvcopy(any, lv->avarinitany[pred->rpo]);
+				bvcopy(all, lv->avarinitall[pred->rpo]);
+			} else {
+				bvor(any, any, lv->avarinitany[pred->rpo]);
+				bvand(all, all, lv->avarinitall[pred->rpo]);
 			}
 		}
+
+		// Walk forward through the basic block instructions and
+		// allocate liveness maps for those instructions that need them.
+		// Seed the maps with information about the addrtaken variables.
+		for(p = bb->first;; p = p->link) {
+			progeffects(p, lv->vars, uevar, varkill, avarinit);
+			bvor(any, any, avarinit);
+			bvor(all, all, avarinit);
+
+			if(issafepoint(p)) {
+				if(debuglive >= 3) {
+					// Diagnose ambiguously live variables (any &^ all).
+					// livein and liveout are dead here and used as temporaries.
+					bvresetall(livein);
+					bvandnot(liveout, any, all);
+					if(bvcmp(livein, liveout) != 0) {
+						for(pos = 0; pos < liveout->n; pos++) {
+							if(bvget(liveout, pos)) {
+								n = *(Node**)arrayget(lv->vars, pos);
+								if(!n->diag && strncmp(n->sym->name, "autotmp_", 8) != 0) {
+									n->diag = 1;
+									warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
+								}
+							}
+							bvset(all, pos); // silence future warnings in this block
+						}
+					}
+				}
+
+				// Allocate a bit vector for each class and facet of
+				// value we are tracking.
+	
+				// Live stuff first.
+				args = bvalloc(argswords() * BitsPerPointer);
+				arrayadd(lv->argslivepointers, &args);
+				locals = bvalloc(localswords() * BitsPerPointer);
+				arrayadd(lv->livepointers, &locals);
+
+				if(debuglive >= 3) {
+					print("%P\n", p);
+					printvars("avarinitany", any, lv->vars);
+				}
+
+				// Record any values with an "address taken" reaching
+				// this code position as live. Must do now instead of below
+				// because the any/all calculation requires walking forward
+				// over the block (as this loop does), while the liveout
+				// requires walking backward (as the next loop does).
+				twobitlivepointermap(lv, any, lv->vars, args, locals);
+	
+				// Dead stuff second.
+				if(lv->deadvalues != nil) {
+					args = bvalloc(argswords() * BitsPerPointer);
+					arrayadd(lv->argsdeadvalues, &args);
+					locals = bvalloc(localswords() * BitsPerPointer);
+					arrayadd(lv->deadvalues, &locals);
+				}
+			}
+			
+			if(p == bb->last)
+				break;
+		}
 		
-		if(debuglive) {
+		if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0) {
 			nmsg = arraylength(lv->livepointers);
+			startmsg = nmsg;
 			msg = xmalloc(nmsg*sizeof msg[0]);
 			for(j=0; j<nmsg; j++)
 				msg[j] = nil;
 			fatal("livenessepilogue");
 		}
 
+		bvcopy(livein, lv->liveout[bb->rpo]);
 		for(p = bb->last; p != nil; p = next) {
 			next = p->opt; // splicebefore modifies p->opt
 			// Propagate liveness information
-			progeffects(p, lv->vars, uevar, varkill);
+			progeffects(p, lv->vars, uevar, varkill, avarinit);
 			bvcopy(liveout, livein);
 			bvandnot(livein, liveout, varkill);
 			bvor(livein, livein, uevar);
-			if(printnoise){
+			if(debuglive >= 3 && issafepoint(p)){
 				print("%P\n", p);
 				printvars("uevar", uevar, lv->vars);
 				printvars("varkill", varkill, lv->vars);
 				// Found an interesting instruction, record the
 				// corresponding liveness information.  
 
-				if(debuglive) {
-					fmtstrinit(&fmt);
-					fmtprint(&fmt, "%L: live at ", p->lineno);
-					if(p->as == ACALL)
-						fmtprint(&fmt, "CALL %lS:", p->to.sym);
-					else
-						fmtprint(&fmt, "TEXT %lS:", p->from.sym);
-					for(j = 0; j < arraylength(lv->vars); j++)
-						if(bvget(liveout, j))
-							fmtprint(&fmt, " %N", *(Node**)arrayget(lv->vars, j));
-					fmtprint(&fmt, "\n");
-					msg[pos] = fmtstrflush(&fmt);
-				}
-
 				// Record live pointers.
 				args = *(Bvec**)arrayget(lv->argslivepointers, pos);
 				locals = *(Bvec**)arrayget(lv->livepointers, pos);
 				twobitlivepointermap(lv, liveout, lv->vars, args, locals);
 
+				// Show live pointer bitmaps.
+				// We're interpreting the args and locals bitmap instead of liveout so that we
+				// include the bits added by the avarinit logic in the
+				// previous loop.
+				if(debuglive >= 1) {
+					fmtstrinit(&fmt);
+					fmtprint(&fmt, "%L: live at ", p->lineno);
+					if(p->as == ACALL)
+						fmtprint(&fmt, "call to %s:", p->to.node->sym->name);
+					else
+						fmtprint(&fmt, "entry to %s:", p->from.node->sym->name);
+					numlive = 0;
+					for(j = 0; j < arraylength(lv->vars); j++) {
+						n = *(Node**)arrayget(lv->vars, j);
+						if(islive(n, args, locals)) {
+							fmtprint(&fmt, " %N", n);
+							numlive++;
+						}
+					}
+					fmtprint(&fmt, "\n");
+					if(numlive == 0) // squelch message
+						free(fmtstrflush(&fmt));
+					else
+						msg[--startmsg] = fmtstrflush(&fmt);
+				}
+
 				// Record dead values.
 				if(lv->deadvalues != nil) {
 					args = *(Bvec**)arrayget(lv->argsdeadvalues, pos);
 				// The TEXT instruction annotation is implicit.
 				if(p->as == ACALL) {
 					if(isdeferreturn(p)) {
-						// Because this runtime call
-						// modifies its return address
-						// to return back to itself,
-						// emitting a PCDATA before the
-						// call instruction will result
-						// in an off by one error during
-						// a stack walk.  Fortunately,
-						// the compiler inserts a no-op
-						// instruction before this call
-						// so we can reliably anchor the
-						// PCDATA to that instruction.
+						// runtime.deferreturn modifies its return address to return
+						// back to the CALL, not to the subsequent instruction.
+						// Because the return comes back one instruction early,
+						// the PCDATA must begin one instruction early too.
+						// The instruction before a call to deferreturn is always a
+						// no-op, to keep PC-specific data unambiguous.
 						splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt);
 					} else {
 						splicebefore(lv, bb, newpcdataprog(p, pos), p);
 				pos--;
 			}
 		}
-		if(debuglive) {
-			for(j=0; j<nmsg; j++) 
+		if(debuglive >= 1) {
+			for(j=startmsg; j<nmsg; j++) 
 				if(msg[j] != nil)
 					print("%s", msg[j]);
 			free(msg);
 			msg = nil;
 			nmsg = 0;
+			startmsg = 0;
 		}
 	}
 
 	free(liveout);
 	free(uevar);
 	free(varkill);
+	free(avarinit);
+	free(any);
+	free(all);
+}
+
+static int
+printbitset(int printed, char *name, Array *vars, Bvec *bits)
+{
+	int i, started;
+	Node *n;
+
+	started = 0;	
+	for(i=0; i<arraylength(vars); i++) {
+		if(!bvget(bits, i))
+			continue;
+		if(!started) {
+			if(!printed) {
+				printed = 1;
+				print("\t");
+			} else
+				print(" ");
+			started = 1;
+			printed = 1;
+			print("%s=", name);
+		} else {
+			print(",");
+		}
+		n = *(Node**)arrayget(vars, i);
+		print("%s", n->sym->name);
+	}
+	return printed;
+}
+
+// Prints the computed liveness information and inputs, for debugging.
+// This format synthesizes the information used during the multiple passes
+// into a single presentation.
+static void
+livenessprintdebug(Liveness *lv)
+{
+	int i, j, printed, nsafe;
+	BasicBlock *bb;
+	Prog *p;
+	Bvec *uevar, *varkill, *avarinit, *args, *locals;
+	Node *n;
+
+	print("liveness: %s\n", curfn->nname->sym->name);
+
+	uevar = bvalloc(arraylength(lv->vars));
+	varkill = bvalloc(arraylength(lv->vars));
+	avarinit = bvalloc(arraylength(lv->vars));
+
+	nsafe = 0;
+	for(i = 0; i < arraylength(lv->cfg); i++) {
+		if(i > 0)
+			print("\n");
+		bb = *(BasicBlock**)arrayget(lv->cfg, i);
+
+		// bb#0 pred=1,2 succ=3,4
+		print("bb#%d pred=", i);
+		for(j = 0; j < arraylength(bb->pred); j++) {
+			if(j > 0)
+				print(",");
+			print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo);
+		}
+		print(" succ=");
+		for(j = 0; j < arraylength(bb->succ); j++) {
+			if(j > 0)
+				print(",");
+			print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo);
+		}
+		print("\n");
+		
+		// initial settings
+		printed = 0;
+		printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]);
+		printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]);
+		if(printed)
+			print("\n");
+		
+		// program listing, with individual effects listed
+		for(p = bb->first;; p = p->link) {
+			print("%P\n", p);
+			progeffects(p, lv->vars, uevar, varkill, avarinit);
+			printed = 0;
+			printed = printbitset(printed, "uevar", lv->vars, uevar);
+			printed = printbitset(printed, "varkill", lv->vars, varkill);
+			printed = printbitset(printed, "avarinit", lv->vars, avarinit);
+			if(printed)
+				print("\n");
+			if(issafepoint(p)) {
+				args = *(Bvec**)arrayget(lv->argslivepointers, nsafe);
+				locals = *(Bvec**)arrayget(lv->livepointers, nsafe);
+				nsafe++;
+				print("\tlive=");
+				printed = 0;
+				for(j = 0; j < arraylength(lv->vars); j++) {
+					n = *(Node**)arrayget(lv->vars, j);
+					if(islive(n, args, locals)) {
+						if(printed++)
+							print(",");
+						print("%N", n);
+					}
+				}
+				print("\n");
+			}
+			if(p == bb->last)
+				break;
+		}
+		
+		// bb bitsets
+		print("end\n");
+		printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]);
+		printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]);
+		printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]);
+		printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]);
+		printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]);
+		if(printed)
+			print("\n");
+	}
+	print("\n");
+
+	free(uevar);
+	free(varkill);
+	free(avarinit);
 }
 
 // Dumps an array of bitmaps to a symbol as a sequence of uint32 values.  The
 twobitwritesymbol(Array *arr, Sym *sym, Bvec *check)
 {
 	Bvec *bv;
-	int off;
-	uint32 bit;
-	uint32 word;
-	uint32 checkword;
-	int32 i;
-	int32 j;
-	int32 len;
-	int32 pos;
+	int off, i, j, len, pos;
+	uint32 bit, word, checkword;
 
 	len = arraylength(arr);
 	// Dump the length of the bitmap array.
 				word = bv->b[j/32];
 				checkword = check->b[j/32];
 				if(word != checkword) {
-					// Found a mismatched word, find
-					// the mismatched bit.
+					// Found a mismatched word; find the mismatched bit.
 					for(pos = 0; pos < 32; pos++) {
 						bit = 1 << pos;
 						if((word & bit) && !(checkword & bit)) {
 void
 liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym, Sym *deadsym)
 {
-	Array *cfg;
-	Array *vars;
+	Array *cfg, *vars;
 	Liveness *lv;
+	int debugdelta;
 
-	if(0) print("curfn->nname->sym->name is %s\n", curfn->nname->sym->name);
-	if(0) printprog(firstp);
+	// Change name to dump debugging information only for a specific function.
+	debugdelta = 0;
+	if(strcmp(curfn->nname->sym->name, "!") == 0)
+		debugdelta = 2;
+	
+	debuglive += debugdelta;
+	if(debuglive >= 3) {
+		print("liveness: %s\n", curfn->nname->sym->name);
+		printprog(firstp);
+	}
 	checkptxt(fn, firstp);
 
 	// Construct the global liveness state.
 	cfg = newcfg(firstp);
-	if(0) printcfg(cfg);
+	if(debuglive >= 3)
+		printcfg(cfg);
 	vars = getvariables(fn, deadsym != nil);
 	lv = newliveness(fn, firstp, cfg, vars, deadsym != nil);
 
 	// Run the dataflow framework.
 	livenessprologue(lv);
-	if(0) livenessprintcfg(lv);
+	if(debuglive >= 3)
+		livenessprintcfg(lv);
 	livenesssolve(lv);
-	if(0) livenessprintcfg(lv);
+	if(debuglive >= 3)
+		livenessprintcfg(lv);
 	livenessepilogue(lv);
+	
+	if(debuglive >= 2)
+		livenessprintdebug(lv);
 
 	// Emit the live pointer map data structures
 	twobitwritesymbol(lv->livepointers, livesym, nil);
 	freeliveness(lv);
 	arrayfree(vars);
 	freecfg(cfg);
+	
+	debuglive -= debugdelta;
 }

src/cmd/gc/sinit.c

 					// copying someone else's computation.
 					rr = nod(OXXX, N, N);
 					*rr = *orig;
+					rr->orig = rr; // completely separate copy
 					rr->type = ll->type;
 					rr->xoffset += e->xoffset;
 					*out = list(*out, nod(OAS, ll, rr));

src/pkg/fmt/fmt_test.go

 	{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
 
 	// Used to crash because nByte didn't allow for a sign.
-	{"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
+	{"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
 
 	// Used to panic.
-	{"%0100d", 1, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
-	{"%0100d", -1, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
-	{"%0.100f", 1.0, "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
-	{"%0.100f", -1.0, "-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
+	{"%0100d", 1, zeroFill("", 100, "1")},
+	{"%0100d", -1, zeroFill("-", 99, "1")},
+	{"%0.100f", 1.0, zeroFill("1.", 100, "")},
+	{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
 
 	// Zero padding floats used to put the minus sign in the middle.
 	{"%020f", -1.0, "-000000000001.000000"},
 	{"%20f", -1.0, "           -1.000000"},
-	{"%0100f", -1.0, "-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"},
+	{"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
 
 	// Complex fmt used to leave the plus flag set for future entries in the array
 	// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
 
 	// Incomplete format specification caused crash.
 	{"%.", 3, "%!.(int=3)"},
+
+	// Used to panic with out-of-bounds for very large numeric representations.
+	// nByte is set to handle one bit per uint64 in %b format, with a negative number.
+	// See issue 6777.
+	{"%#064x", 1, zeroFill("0x", 64, "1")},
+	{"%#064x", -1, zeroFill("-0x", 63, "1")},
+	{"%#064b", 1, zeroFill("", 64, "1")},
+	{"%#064b", -1, zeroFill("-", 63, "1")},
+	{"%#064o", 1, zeroFill("", 64, "1")},
+	{"%#064o", -1, zeroFill("-", 63, "1")},
+	{"%#064d", 1, zeroFill("", 64, "1")},
+	{"%#064d", -1, zeroFill("-", 63, "1")},
+	// Test that we handle the crossover above the size of uint64
+	{"%#072x", 1, zeroFill("0x", 72, "1")},
+	{"%#072x", -1, zeroFill("-0x", 71, "1")},
+	{"%#072b", 1, zeroFill("", 72, "1")},
+	{"%#072b", -1, zeroFill("-", 71, "1")},
+	{"%#072o", 1, zeroFill("", 72, "1")},
+	{"%#072o", -1, zeroFill("-", 71, "1")},
+	{"%#072d", 1, zeroFill("", 72, "1")},
+	{"%#072d", -1, zeroFill("-", 71, "1")},
+}
+
+// zeroFill generates zero-filled strings of the specified width. The length
+// of the suffix (but not the prefix) is compensated for in the width calculation.
+func zeroFill(prefix string, width int, suffix string) string {
+	return prefix + strings.Repeat("0", width-len(suffix)) + suffix
 }
 
 func TestSprintf(t *testing.T) {

src/pkg/fmt/format.go

 )
 
 const (
-	nByte = 65 // %b of an int64, plus a sign.
+	// %b of an int64, plus a sign.
+	// Hex can add 0x and we handle it specially.
+	nByte = 65
 
 	ldigits = "0123456789abcdef"
 	udigits = "0123456789ABCDEF"
 	}
 
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent && f.wid > nByte {
-		// We're going to need a bigger boat.
-		buf = make([]byte, f.wid)
+	if f.widPresent {
+		width := f.wid
+		if base == 16 && f.sharp {
+			// Also adds "0x".
+			width += 2
+		}
+		if width > nByte {
+			// We're going to need a bigger boat.
+			buf = make([]byte, width)
+		}
 	}
 
 	negative := signedness == signed && a < 0

src/pkg/net/http/export_test.go

 	return &timeoutHandler{handler, f, ""}
 }
 
+func ResetCachedEnvironment() {
+	httpProxyEnv.reset()
+	noProxyEnv.reset()
+}
+
 var DefaultUserAgent = defaultUserAgent

src/pkg/net/http/serve_test.go

 	}
 }
 
-// Issue 6157
-func TestNoContentTypeOnNotModified(t *testing.T) {
-	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
-		if r.URL.Path == "/header" {
-			w.Header().Set("Content-Length", "123")
-		}
-		w.WriteHeader(StatusNotModified)
-		if r.URL.Path == "/more" {
-			w.Write([]byte("stuff"))
-		}
-	}))
-	for _, req := range []string{
-		"GET / HTTP/1.0",
-		"GET /header HTTP/1.0",
-		"GET /more HTTP/1.0",
-		"GET / HTTP/1.1",
-		"GET /header HTTP/1.1",
-		"GET /more HTTP/1.1",
-	} {
-		got := ht.rawResponse(req)
-		if !strings.Contains(got, "304 Not Modified") {
-			t.Errorf("Non-304 Not Modified for %q: %s", req, got)
-		} else if strings.Contains(got, "Content-Length") {
-			t.Errorf("Got a Content-Length from %q: %s", req, got)
+// Issue 6157, Issue 6685
+func TestCodesPreventingContentTypeAndBody(t *testing.T) {
+	for _, code := range []int{StatusNotModified, StatusNoContent, StatusContinue} {
+		ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+			if r.URL.Path == "/header" {
+				w.Header().Set("Content-Length", "123")
+			}
+			w.WriteHeader(code)
+			if r.URL.Path == "/more" {
+				w.Write([]byte("stuff"))
+			}
+		}))
+		for _, req := range []string{
+			"GET / HTTP/1.0",
+			"GET /header HTTP/1.0",
+			"GET /more HTTP/1.0",
+			"GET / HTTP/1.1",
+			"GET /header HTTP/1.1",
+			"GET /more HTTP/1.1",
+		} {
+			got := ht.rawResponse(req)
+			wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
+			if !strings.Contains(got, wantStatus) {
+				t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got)
+			} else if strings.Contains(got, "Content-Length") {
+				t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
+			} else if strings.Contains(got, "stuff") {
+				t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got)
+			}
 		}
 	}
 }

src/pkg/net/http/server.go

 	// response header and this is our first (and last) write, set
 	// it, even to zero. This helps HTTP/1.0 clients keep their
 	// "keep-alive" connections alive.
-	// Exceptions: 304 responses never get Content-Length, and if
+	// Exceptions: 304/204/1xx responses never get Content-Length, and if
 	// it was a HEAD request, we don't know the difference between
 	// 0 actual bytes and 0 bytes because the handler noticed it
 	// was a HEAD request and chose not to write anything.  So for
 	// write non-zero bytes.  If it's actually 0 bytes and the
 	// handler never looked at the Request.Method, we just don't
 	// send a Content-Length header.
-	if w.handlerDone && w.status != StatusNotModified && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+	if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
 		w.contentLength = int64(len(p))
 		setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
 	}
 	}
 
 	code := w.status
-	if code == StatusNotModified {
+	if !bodyAllowedForStatus(code) {
 		// Must not have body.
 		// RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
 		for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
 		hasCL = false
 	}
 
-	if w.req.Method == "HEAD" || code == StatusNotModified {
+	if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) {
 		// do nothing
 	} else if code == StatusNoContent {
 		delHeader("Transfer-Encoding")
 	if !w.wroteHeader {
 		panic("")
 	}
-	return w.status != StatusNotModified
+	return bodyAllowedForStatus(w.status)
 }
 
 // The Life Of A Write is like this:

src/pkg/net/http/transport.go

 // A nil URL and nil error are returned if no proxy is defined in the
 // environment, or a proxy should not be used for the given request.
 func ProxyFromEnvironment(req *Request) (*url.URL, error) {
-	proxy := getenvEitherCase("HTTP_PROXY")
+	proxy := httpProxyEnv.Get()
 	if proxy == "" {
 		return nil, nil
 	}
 // Private implementation past this point.
 //
 
-func getenvEitherCase(k string) string {
-	if v := os.Getenv(strings.ToUpper(k)); v != "" {
-		return v
+var (
+	httpProxyEnv = &envOnce{
+		names: []string{"HTTP_PROXY", "http_proxy"},
 	}
-	return os.Getenv(strings.ToLower(k))
+	noProxyEnv = &envOnce{
+		names: []string{"NO_PROXY", "no_proxy"},
+	}
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+type envOnce struct {
+	names []string
+	once  sync.Once
+	val   string
+}
+
+func (e *envOnce) Get() string {
+	e.once.Do(e.init)
+	return e.val
+}
+
+func (e *envOnce) init() {
+	for _, n := range e.names {
+		e.val = os.Getenv(n)
+		if e.val != "" {
+			return
+		}
+	}
+}
+
+// reset is used by tests
+func (e *envOnce) reset() {
+	e.once = sync.Once{}
+	e.val = ""
 }
 
 func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
 		}
 	}
 
-	no_proxy := getenvEitherCase("NO_PROXY")
+	no_proxy := noProxyEnv.Get()
 	if no_proxy == "*" {
 		return false
 	}

src/pkg/net/http/transport_test.go

 	for _, tt := range proxyFromEnvTests {
 		os.Setenv("HTTP_PROXY", tt.env)
 		os.Setenv("NO_PROXY", tt.noenv)
+		ResetCachedEnvironment()
 		reqURL := tt.req
 		if reqURL == "" {
 			reqURL = "http://example.com"

src/pkg/net/rpc/server.go

 // Register publishes in the server the set of methods of the
 // receiver value that satisfy the following conditions:
 //	- exported method
-//	- two arguments, both pointers to exported structs
+//	- two arguments, both of exported type
+//	- the second argument is a pointer
 //	- one return value, of type error
 // It returns an error if the receiver is not an exported type or has
-// no methods or unsuitable methods. It also logs the error using package log.
+// no suitable methods. It also logs the error using package log.
 // The client accesses each method using a string of the form "Type.Method",
 // where Type is the receiver's concrete type.
 func (server *Server) Register(rcvr interface{}) error {

src/pkg/net/smtp/example_test.go

+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp_test
+
+import (
+	"fmt"
+	"log"
+	"net/smtp"
+)
+
+func Example() {
+	// Connect to the remote SMTP server.
+	c, err := smtp.Dial("mail.example.com:25")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Set the sender and recipient first
+	if err := c.Mail("sender@example.org"); err != nil {
+		log.Fatal(err)
+	}
+	if err := c.Rcpt("recipient@example.net"); err != nil {
+		log.Fatal(err)
+	}
+
+	// Send the email body.
+	wc, err := c.Data()
+	if err != nil {
+		log.Fatal(err)
+	}
+	_, err = fmt.Fprintf(wc, "This is the email body")
+	if err != nil {
+		log.Fatal(err)
+	}
+	err = wc.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Send the QUIT command and close the connection.
+	err = c.Quit()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExamplePlainAuth() {
+	// Set up authentication information.
+	auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
+
+	// Connect to the server, authenticate, set the sender and recipient,
+	// and send the email all in one step.
+	to := []string{"recipient@example.net"}
+	msg := []byte("This is the email body.")
+	err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
+	if err != nil {
+		log.Fatal(err)
+	}
+}

src/pkg/net/unicast_posix_test.go

 }
 
 // TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
 // listening address and same port.
 func TestDualStackTCPListener(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in -short mode, see issue 5001")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
+		if tt.wildcard && !*testExternal {
 			continue
 		}
 		switch runtime.GOOS {

src/pkg/reflect/value.go

 // bigger than a pointer, its word is a pointer to v's data.
 // Otherwise, its word holds the data stored
 // in its leading bytes (so is not a pointer).
-// Because the value sometimes holds a pointer, we use
-// unsafe.Pointer to represent it, so that if iword appears
-// in a struct, the garbage collector knows that might be
-// a pointer.
-// TODO: get rid of all occurrences of iword (except in the interface decls below?)
-// We want to get rid of the "feature" that an unsafe.Pointer is sometimes a pointer
-// and sometimes a uintptr.
+// This type is very dangerous for the garbage collector because
+// it must be treated conservatively.  We try to never expose it
+// to the GC here so that GC remains precise.
 type iword unsafe.Pointer
 
-// Get an iword that represents this value.
-// TODO: this function goes away at some point
-func (v Value) iword() iword {
-	t := v.typ
-	if t == nil {
-		return iword(nil)
-	}
-	if v.flag&flagIndir != 0 {
-		if v.typ.size > ptrSize {
-			return iword(v.ptr)
-		}
-		// Have indirect but want direct word.
-		if t.pointers() {
-			return iword(*(*unsafe.Pointer)(v.ptr))
-		}
-		return iword(loadScalar(v.ptr, v.typ.size))
-	}
-	if t.pointers() {
-		return iword(v.ptr)
-	}
-	return iword(v.scalar)
-}
-
-// Build a Value from a type/iword pair, plus any extra flags.
-// TODO: this function goes away at some point
-func fromIword(t *rtype, w iword, fl flag) Value {
-	fl |= flag(t.Kind()) << flagKindShift
-	if t.size > ptrSize {
-		return Value{t, unsafe.Pointer(w), 0, fl | flagIndir}
-	} else if t.pointers() {
-		return Value{t, unsafe.Pointer(w), 0, fl}
-	} else {
-		return Value{t, nil, uintptr(w), fl}
-	}
-}
-
 // loadScalar loads n bytes at p from memory into a uintptr
 // that forms the second word of an interface.  The data
 // must be non-pointer in nature.
 	if ChanDir(tt.dir)&RecvDir == 0 {
 		panic("reflect: recv on send-only channel")
 	}
-	word, selected, ok := chanrecv(v.typ, v.pointer(), nb)
-	if selected {
-		val = fromIword(tt.elem, word, 0)
+	t := tt.elem
+	val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
+	var p unsafe.Pointer
+	if t.size > ptrSize {
+		p = unsafe_New(t)
+		val.ptr = p
+		val.flag |= flagIndir
+	} else if t.pointers() {
+		p = unsafe.Pointer(&val.ptr)
+	} else {
+		p = unsafe.Pointer(&val.scalar)
+	}
+	selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+	if !selected {
+		val = Value{}
 	}
 	return
 }
 	}
 	x.mustBeExported()
 	x = x.assignTo("reflect.Value.Send", tt.elem, nil)
-	return chansend(v.typ, v.pointer(), x.iword(), nb)
+	var p unsafe.Pointer
+	if x.flag&flagIndir != 0 {
+		p = x.ptr
+	} else if x.typ.pointers() {
+		p = unsafe.Pointer(&x.ptr)
+	} else {
+		p = unsafe.Pointer(&x.scalar)
+	}
+	return chansend(v.typ, v.pointer(), p, nb)
 }
 
 // Set assigns x to the value v.
 // A runtimeSelect is a single case passed to rselect.
 // This must match ../runtime/chan.c:/runtimeSelect
 type runtimeSelect struct {
-	dir uintptr // 0, SendDir, or RecvDir
-	typ *rtype  // channel type
-	ch  iword   // interface word for channel
-	val iword   // interface word for value (for SendDir)
+	dir uintptr        // 0, SendDir, or RecvDir
+	typ *rtype         // channel type
+	ch  unsafe.Pointer // channel
+	val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
 }
 
-// rselect runs a select. It returns the index of the chosen case,
-// and if the case was a receive, the interface word of the received
-// value and the conventional OK bool to indicate whether the receive
-// corresponds to a sent value.
-func rselect([]runtimeSelect) (chosen int, recv iword, recvOK bool)
+// rselect runs a select.  It returns the index of the chosen case.
+// If the case was a receive, val is filled in with the received value.
+// The conventional OK bool indicates whether the receive corresponds
+// to a sent value.
+//go:noescape
+func rselect([]runtimeSelect) (chosen int, recvOK bool)
 
 // A SelectDir describes the communication direction of a select case.
 type SelectDir int
 			if ChanDir(tt.dir)&SendDir == 0 {
 				panic("reflect.Select: SendDir case using recv-only channel")
 			}
-			rc.ch = ch.iword()
+			rc.ch = ch.pointer()
 			rc.typ = &tt.rtype
 			v := c.Send
 			if !v.IsValid() {
 			}
 			v.mustBeExported()
 			v = v.assignTo("reflect.Select", tt.elem, nil)
-			rc.val = v.iword()
+			if v.flag&flagIndir != 0 {
+				rc.val = v.ptr
+			} else if v.typ.pointers() {
+				rc.val = unsafe.Pointer(&v.ptr)
+			} else {
+				rc.val = unsafe.Pointer(&v.scalar)
+			}
 
 		case SelectRecv:
 			if c.Send.IsValid() {
 			ch.mustBe(Chan)
 			ch.mustBeExported()
 			tt := (*chanType)(unsafe.Pointer(ch.typ))
-			rc.typ = &tt.rtype
 			if ChanDir(tt.dir)&RecvDir == 0 {
 				panic("reflect.Select: RecvDir case using send-only channel")
 			}
-			rc.ch = ch.iword()
+			rc.ch = ch.pointer()
+			rc.typ = &tt.rtype
+			rc.val = unsafe_New(tt.elem)
 		}
 	}
 
-	chosen, word, recvOK := rselect(runcases)
+	chosen, recvOK = rselect(runcases)
 	if runcases[chosen].dir == uintptr(SelectRecv) {
 		tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
-		recv = fromIword(tt.elem, word, 0)
+		t := tt.elem
+		p := runcases[chosen].val
+		fl := flag(t.Kind()) << flagKindShift
+		if t.size > ptrSize {
+			recv = Value{t, p, 0, fl | flagIndir}
+		} else if t.pointers() {
+			recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
+		} else {
+			recv = Value{t, nil, loadScalar(p, t.size), fl}
+		}
 	}
 	return chosen, recv, recvOK
 }
 func chancap(ch unsafe.Pointer) int
 func chanclose(ch unsafe.Pointer)
 func chanlen(ch unsafe.Pointer) int
-func chanrecv(t *rtype, ch unsafe.Pointer, nb bool) (val iword, selected, received bool)
-func chansend(t *rtype, ch unsafe.Pointer, val iword, nb bool) bool
+
+//go:noescape
+func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+
+//go:noescape
+func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
 
 func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
 func makemap(t *rtype) (m unsafe.Pointer)
Add a comment to this file

src/pkg/runtime/arch_amd64.h

File contents unchanged.

Add a comment to this file

src/pkg/runtime/asm_amd64.s

File contents unchanged.

src/pkg/runtime/cgocall.c

 		return;
 	}
 
-	if(!runtime·iscgo && !Windows && !Solaris)
+	if(!runtime·iscgo && !Solaris && !Windows)
 		runtime·throw("cgocall unavailable");
 
 	if(fn == 0)

src/pkg/runtime/chan.c

 }
 
 // For reflect:
-//	func chansend(c chan, val iword, nb bool) (selected bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+//	func chansend(c chan, val *any, nb bool) (selected bool)
+// where val points to the data to be sent.
 //
 // The "uintptr selected" is really "bool selected" but saying
 // uintptr gets us the right alignment for the output parameter block.
 #pragma textflag NOSPLIT
 void
-reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
+reflect·chansend(ChanType *t, Hchan *c, byte *val, bool nb, uintptr selected)
 {
 	bool *sp;
-	byte *vp;
 
 	if(nb) {
 		selected = false;
 		FLUSH(&selected);
 		sp = nil;
 	}
-	if(t->elem->size <= sizeof(val))
-		vp = (byte*)&val;
-	else
-		vp = (byte*)val;
-	runtime·chansend(t, c, vp, sp, runtime·getcallerpc(&t));
+	runtime·chansend(t, c, val, sp, runtime·getcallerpc(&t));
 }
 
 // For reflect:
-//	func chanrecv(c chan, nb bool) (val iword, selected, received bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+//	func chanrecv(c chan, nb bool, val *any) (selected, received bool)
+// where val points to a data area that will be filled in with the
+// received value.  val must have the size and type of the channel element type.
 void
-reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
+reflect·chanrecv(ChanType *t, Hchan *c, bool nb, byte *val, bool selected, bool received)
 {
-	byte *vp;
 	bool *sp;
 
 	if(nb) {
 	}
 	received = false;
 	FLUSH(&received);
-	if(t->elem->size <= sizeof(val)) {
-		val = 0;
-		vp = (byte*)&val;
-	} else {
-		vp = runtime·mal(t->elem->size);
-		val = (uintptr)vp;
-		FLUSH(&val);
-	}
-	runtime·chanrecv(t, c, vp, sp, &received);
+	runtime·chanrecv(t, c, val, sp, &received);
 }
 
 static void newselect(int32, Select**);
 	uintptr dir;
 	ChanType *typ;
 	Hchan *ch;
-	uintptr val;
+	byte *val;
 };
 
 // This enum must match ../reflect/value.go:/SelectDir.
 	SelectDefault,
 };
 
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
+// func rselect(cases []runtimeSelect) (chosen int, recvOK bool)
 void
-reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
+reflect·rselect(Slice cases, intgo chosen, bool recvOK)
 {
 	int32 i;
 	Select *sel;
 	runtimeSelect* rcase, *rc;
-	void *elem;
-	void *recvptr;
-	uintptr maxsize;
 
 	chosen = -1;
-	word = 0;
 	recvOK = false;
 
-	maxsize = 0;
 	rcase = (runtimeSelect*)cases.array;
-	for(i=0; i<cases.len; i++) {
-		rc = &rcase[i];
-		if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->elem->size)
-			maxsize = rc->typ->elem->size;
-	}
-
-	recvptr = nil;
-	if(maxsize > sizeof(void*))
-		recvptr = runtime·mal(maxsize);
 
 	newselect(cases.len, &sel);
 	for(i=0; i<cases.len; i++) {
 		case SelectSend:
 			if(rc->ch == nil)
 				break;
-			if(rc->typ->elem->size > sizeof(void*))
-				elem = (void*)rc->val;
-			else
-				elem = (void*)&rc->val;
-			selectsend(sel, rc->ch, (void*)i, elem, 0);
+			selectsend(sel, rc->ch, (void*)i, rc->val, 0);
 			break;
 		case SelectRecv:
 			if(rc->ch == nil)
 				break;
-			if(rc->typ->elem->size > sizeof(void*))
-				elem = recvptr;
-			else
-				elem = &word;
-			selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0);
+			selectrecv(sel, rc->ch, (void*)i, rc->val, &recvOK, 0);
 			break;
 		}
 	}
 
 	chosen = (intgo)(uintptr)selectgo(&sel);
-	if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > sizeof(void*))
-		word = (uintptr)recvptr;
 
 	FLUSH(&chosen);
-	FLUSH(&word);
 	FLUSH(&recvOK);
 }
 
Add a comment to this file

src/pkg/runtime/defs_solaris_amd64.go

File contents unchanged.

Add a comment to this file

src/pkg/runtime/defs_solaris_amd64.h

File contents unchanged.

Add a comment to this file

src/pkg/runtime/env_posix.c

File contents unchanged.

Add a comment to this file

src/pkg/runtime/lfstack.c

File contents unchanged.

src/pkg/runtime/lock_sema.c

 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin netbsd openbsd plan9 windows solaris
+// +build darwin netbsd openbsd plan9 solaris windows
 
 #include "runtime.h"
 #include "stack.h"

src/pkg/runtime/netpoll.goc

 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
Add a comment to this file

src/pkg/runtime/os_solaris.h

File contents unchanged.

src/pkg/runtime/proc.c

 
 	// In case of cgo or Solaris, pthread_create will make us a stack.
 	// Windows will layout sched stack on OS stack.
-	if(runtime·iscgo || Windows || Solaris)
+	if(runtime·iscgo || Solaris || Windows)
 		mp->g0 = runtime·malg(-1);
 	else
 		mp->g0 = runtime·malg(8192);
Add a comment to this file

src/pkg/runtime/rt0_solaris_amd64.s

File contents unchanged.

Add a comment to this file

src/pkg/runtime/runtime.c

File contents unchanged.

Add a comment to this file

src/pkg/runtime/runtime.h

File contents unchanged.

Add a comment to this file

src/pkg/runtime/signal_amd64.c

File contents unchanged.

Add a comment to this file

src/pkg/runtime/signal_solaris_amd64.h

File contents unchanged.

src/pkg/runtime/signal_unix.c

 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux openbsd netbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
Add a comment to this file

src/pkg/runtime/signals_solaris.h

File contents unchanged.

Add a comment to this file

src/pkg/runtime/sys_solaris_amd64.s

File contents unchanged.

Add a comment to this file

src/pkg/runtime/syscall_solaris.goc

File contents unchanged.

Add a comment to this file

src/pkg/runtime/syscall_windows.goc

File contents unchanged.

src/pkg/syscall/consistency_unix_test.go

 		_ int = syscall.TCOFLUSH
 	)
 }
+
+func _() {
+	_ = syscall.Flock_t{
+		Type:   int16(0),
+		Whence: int16(0),
+		Start:  0,
+		Len:    0,
+		Pid:    int32(0),
+	}
+}

src/pkg/syscall/types_linux.go

 
 type Fsid C.fsid_t
 
+type Flock_t C.struct_flock
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in

src/pkg/syscall/ztypes_linux_386.go

 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type   int16
+	Whence int16
+	Start  int64
+	Len    int64
+	Pid    int32
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16

src/pkg/syscall/ztypes_linux_amd64.go

 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type      int16
+	Whence    int16
+	Pad_cgo_0 [4]byte
+	Start     int64
+	Len       int64
+	Pid       int32
+	Pad_cgo_1 [4]byte
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16

src/pkg/syscall/ztypes_linux_arm.go

 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type   int16
+	Whence int16
+	Start  int64
+	Len    int64
+	Pid    int32
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16

src/pkg/time/format_test.go

+// 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 time_test
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"testing"
+	"testing/quick"
+	. "time"
+)
+
+type TimeFormatTest struct {
+	time           Time
+	formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+	{Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+	{Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+	{Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+	for _, f := range rfc3339Formats {
+		if f.time.Format(RFC3339) != f.formattedValue {
+			t.Error("RFC3339:")
+			t.Errorf("  want=%+v", f.formattedValue)
+			t.Errorf("  have=%+v", f.time.Format(RFC3339))
+		}
+	}
+}
+
+type FormatTest struct {
+	name   string
+	format string
+	result string
+}
+
+var formatTests = []FormatTest{
+	{"ANSIC", ANSIC, "Wed Feb  4 21:00:57 2009"},
+	{"UnixDate", UnixDate, "Wed Feb  4 21:00:57 PST 2009"},
+	{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+	{"RFC822", RFC822, "04 Feb 09 21:00 PST"},
+	{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+	{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+	{"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
+	{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+	{"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
+	{"Kitchen", Kitchen, "9:00PM"},
+	{"am/pm", "3pm", "9pm"},
+	{"AM/PM", "3PM", "9PM"},
+	{"two-digit year", "06 01 02", "09 02 04"},
+	// Three-letter months and days must not be followed by lower-case letter.
+	{"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
+	// Time stamps, Fractional seconds.
+	{"Stamp", Stamp, "Feb  4 21:00:57"},
+	{"StampMilli", StampMilli, "Feb  4 21:00:57.012"},
+	{"StampMicro", StampMicro, "Feb  4 21:00:57.012345"},
+	{"StampNano", StampNano, "Feb  4 21:00:57.012345600"},
+}
+
+func TestFormat(t *testing.T) {
+	// The numeric time represents Thu Feb  4 21:00:57.012345600 PST 2010
+	time := Unix(0, 1233810057012345600)
+	for _, test := range formatTests {
+		result := time.Format(test.format)
+		if result != test.result {
+			t.Errorf("%s expected %q got %q", test.name, test.result, result)
+		}
+	}
+}
+
+func TestFormatShortYear(t *testing.T) {
+	years := []int{
+		-100001, -100000, -99999,
+		-10001, -10000, -9999,
+		-1001, -1000, -999,
+		-101, -100, -99,
+		-11, -10, -9,
+		-1, 0, 1,
+		9, 10, 11,
+		99, 100, 101,
+		999, 1000, 1001,
+		9999, 10000, 10001,
+		99999, 100000, 100001,
+	}
+
+	for _, y := range years {
+		time := Date(y, January, 1, 0, 0, 0, 0, UTC)
+		result := time.Format("2006.01.02")
+		var want string
+		if y < 0 {
+			// The 4 in %04d counts the - sign, so print -y instead
+			// and introduce our own - sign.
+			want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
+		} else {
+			want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
+		}
+		if result != want {
+			t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
+		}
+	}
+}
+
+type ParseTest struct {
+	name       string
+	format     string
+	value      string
+	hasTZ      bool // contains a time zone
+	hasWD      bool // contains a weekday
+	yearSign   int  // sign of year, -1 indicates the year is not present in the format
+	fracDigits int  // number of digits of fractional second
+}
+
+var parseTests = []ParseTest{
+	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010", false, true, 1, 0},
+	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010", true, true, 1, 0},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
+	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
+	{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+	{"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
+	// Optional fractional seconds.
+	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57.0 2010", false, true, 1, 1},
+	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57.01 PST 2010", true, true, 1, 2},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
+	{"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
+	{"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
+	// Amount of white space should not matter.
+	{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+	{"ANSIC", ANSIC, "Thu      Feb     4     21:00:57     2010", false, true, 1, 0},
+	// Case should not matter
+	{"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
+	{"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
+	// Fractional seconds.
+	{"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 21:00:57.012 2010", false, true, 1, 3},
+	{"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb  4 21:00:57.012345 2010", false, true, 1, 6},
+	{"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb  4 21:00:57.012345678 2010", false, true, 1, 9},
+	// Leading zeros in other places should not be taken as fractional seconds.
+	{"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+	{"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+	// Month and day names only match when not followed by a lower-case letter.
+	{"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb  4 21:00:57 2010", false, true, 1, 0},
+
+	// GMT with offset.
+	{"GMT-8", UnixDate, "Fri Feb  5 05:00:57 GMT-8 2010", true, true, 1, 0},
+
+	// Accept any number of fractional second digits (including none) for .999...
+	// In Go 1, .999... was completely ignored in the format, meaning the first two
+	// cases would succeed, but the next four would not. Go 1.1 accepts all six.
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+
+	// issue 4502.
+	{"", StampNano, "Feb  4 21:00:57.012345678", false, false, -1, 9},
+	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012300000", false, false, -1, 4},
+	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
+	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.0123", false, false, -1, 4},
+	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
+}
+
+func TestParse(t *testing.T) {
+	for _, test := range parseTests {
+		time, err := Parse(test.format, test.value)
+		if err != nil {
+			t.Errorf("%s error: %v", test.name, err)
+		} else {
+			checkTime(time, &test, t)
+		}
+	}
+}
+
+func TestParseInSydney(t *testing.T) {
+	loc, err := LoadLocation("Australia/Sydney")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Check that Parse (and ParseInLocation) understand
+	// that Feb EST and Aug EST are different time zones in Sydney
+	// even though both are called EST.
+	t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
+	if t1 != t2 {
+		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+	}
+	_, offset := t1.Zone()
+	if offset != 11*60*60 {
+		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
+	}
+
+	t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
+	if t1 != t2 {
+		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+	}
+	_, offset = t1.Zone()
+	if offset != 10*60*60 {
+		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
+	}
+}
+
+func TestLoadLocationZipFile(t *testing.T) {
+	ForceZipFileForTesting(true)
+	defer ForceZipFileForTesting(false)
+
+	_, err := LoadLocation("Australia/Sydney")
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+var rubyTests = []ParseTest{
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+	// Ignore the time zone in the test. If it parses, it'll be OK.
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},