[dev.ssa] cmd/compile/internal/ssa: eval defer args before setting argsize and func

Evaluating args can overwrite arg area, so we can't write argsize and func
until args are evaluated.

Fixes test/recover.go, test/recover1.go, and test/fixedbugs/issue4066.go

Change-Id: I862e4934ccdb8661431bcc3e1e93817ea834ea3f
Reviewed-on: https://go-review.googlesource.com/14405
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 9791967..e3a71a9f 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -741,6 +741,10 @@
 			s.Unimplementedf("defer/go of %s", opnames[call.Op])
 		}
 
+		// Run all argument assignments.  The arg slots have already
+		// been offset by 2*widthptr.
+		s.stmtList(call.List)
+
 		// Write argsize and closure (args to Newproc/Deferproc)
 		argsize := s.constInt32(Types[TUINT32], int32(fn.Type.Argwid))
 		s.vars[&memvar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
@@ -748,10 +752,6 @@
 		addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
 		s.vars[&memvar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
 
-		// Run all argument assignments.  The arg slots have already
-		// been offset by 2*widthptr.
-		s.stmtList(call.List)
-
 		// Call deferproc or newproc
 		bNext := s.f.NewBlock(ssa.BlockPlain)
 		var op ssa.Op