syscall: another attempt to keep windows syscall pointers live

This approach was suggested in
https://golang.org/cl/138250043/#msg15.
Unlike current version of mksyscall_windows.go,
new code could be used in go.sys and other external
repos without help from asm.

LGTM=iant
R=golang-codereviews, iant, r
CC=golang-codereviews
https://golang.org/cl/143160046
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index 1cdd6b4..316e88d 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -138,8 +138,6 @@
 // TmpVarCode returns source code for temp variable.
 func (p *Param) TmpVarCode() string {
 	switch {
-	case p.Type == "string":
-		return p.StringTmpVarCode()
 	case p.Type == "bool":
 		return p.BoolTmpVarCode()
 	case strings.HasPrefix(p.Type, "[]"):
@@ -149,19 +147,26 @@
 	}
 }
 
+// TmpVarHelperCode returns source code for helper's temp variable.
+func (p *Param) TmpVarHelperCode() string {
+	if p.Type != "string" {
+		return ""
+	}
+	return p.StringTmpVarCode()
+}
+
 // SyscallArgList returns source code fragments representing p parameter
 // in syscall. Slices are translated into 2 syscall parameters: pointer to
 // the first element and length.
 func (p *Param) SyscallArgList() []string {
+	t := p.HelperType()
 	var s string
 	switch {
-	case p.Type[0] == '*':
+	case t[0] == '*':
 		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
-	case p.Type == "string":
-		s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar())
-	case p.Type == "bool":
+	case t == "bool":
 		s = p.tmpVar()
-	case strings.HasPrefix(p.Type, "[]"):
+	case strings.HasPrefix(t, "[]"):
 		return []string{
 			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
 			fmt.Sprintf("uintptr(len(%s))", p.Name),
@@ -177,6 +182,14 @@
 	return p.Name == "err" && p.Type == "error"
 }
 
+// HelperType returns type of parameter p used in helper function.
+func (p *Param) HelperType() string {
+	if p.Type == "string" {
+		return p.fn.StrconvType()
+	}
+	return p.Type
+}
+
 // join concatenates parameters ps into a string with sep separator.
 // Each parameter is converted into string by applying fn to it
 // before conversion.
@@ -454,6 +467,11 @@
 	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
 }
 
+// HelperParamList returns source code for helper function f parameters.
+func (f *Fn) HelperParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
+}
+
 // ParamPrintList returns source code of trace printing part correspondent
 // to syscall input parameters.
 func (f *Fn) ParamPrintList() string {
@@ -510,6 +528,19 @@
 	return strings.Join(a, ", ")
 }
 
+// HelperCallParamList returns source code of call into function f helper.
+func (f *Fn) HelperCallParamList() string {
+	a := make([]string, 0, len(f.Params))
+	for _, p := range f.Params {
+		s := p.Name
+		if p.Type == "string" {
+			s = p.tmpVar()
+		}
+		a = append(a, s)
+	}
+	return strings.Join(a, ", ")
+}
+
 // IsUTF16 is true, if f is W (utf16) function. It is false
 // for all A (ascii) functions.
 func (f *Fn) IsUTF16() bool {
@@ -533,6 +564,25 @@
 	return "*byte"
 }
 
+// HasStringParam is true, if f has at least one string parameter.
+// Otherwise it is false.
+func (f *Fn) HasStringParam() bool {
+	for _, p := range f.Params {
+		if p.Type == "string" {
+			return true
+		}
+	}
+	return false
+}
+
+// HelperName returns name of function f helper.
+func (f *Fn) HelperName() string {
+	if !f.HasStringParam() {
+		return f.Name
+	}
+	return "_" + f.Name
+}
+
 // Source files and functions.
 type Source struct {
 	Funcs []*Fn
@@ -666,7 +716,7 @@
 var (
 {{template "dlls" .}}
 {{template "funcnames" .}})
-{{range .Funcs}}{{template "funcbody" .}}{{end}}
+{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
 {{end}}
 
 {{/* help functions */}}
@@ -677,16 +727,27 @@
 {{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
 {{end}}{{end}}
 
+{{define "helperbody"}}
+func {{.Name}}({{.ParamList}}) {{template "results" .}}{
+{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
+}
+{{end}}
+
 {{define "funcbody"}}
-func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{
+func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
 {{template "tmpvars" .}}	{{template "syscall" .}}
 {{template "seterror" .}}{{template "printtrace" .}}	return
 }
 {{end}}
 
+{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
+{{end}}{{end}}{{end}}
+
 {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
 {{end}}{{end}}{{end}}
 
+{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
+
 {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
 
 {{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}