github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/gl/gendebug.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 // The gendebug program takes gl.go and generates a version of it 8 // where each function includes tracing code that writes its arguments 9 // to the standard log. 10 package main 11 12 import ( 13 "bytes" 14 "flag" 15 "fmt" 16 "go/ast" 17 "go/format" 18 "go/parser" 19 "go/printer" 20 "go/token" 21 "io/ioutil" 22 "log" 23 "os" 24 "strconv" 25 ) 26 27 var outfile = flag.String("o", "", "result will be written to the file instead of stdout.") 28 29 var fset = new(token.FileSet) 30 31 func typeString(t ast.Expr) string { 32 buf := new(bytes.Buffer) 33 printer.Fprint(buf, fset, t) 34 return buf.String() 35 } 36 37 func typePrinter(t string) string { 38 switch t { 39 case "[]float32", "[]byte": 40 return "len(%d)" 41 } 42 return "%v" 43 } 44 45 func typePrinterArg(t, name string) string { 46 switch t { 47 case "[]float32", "[]byte": 48 return "len(" + name + ")" 49 } 50 return name 51 } 52 53 func die(err error) { 54 fmt.Fprintf(os.Stderr, err.Error()) 55 os.Exit(1) 56 } 57 58 func main() { 59 flag.Parse() 60 61 f, err := parser.ParseFile(fset, "consts.go", nil, parser.ParseComments) 62 if err != nil { 63 die(err) 64 } 65 entries := enum(f) 66 67 f, err = parser.ParseFile(fset, "gl.go", nil, parser.ParseComments) 68 if err != nil { 69 die(err) 70 } 71 72 buf := new(bytes.Buffer) 73 74 fmt.Fprint(buf, preamble) 75 76 fmt.Fprintf(buf, "func (v Enum) String() string {\n") 77 fmt.Fprintf(buf, "\tswitch v {\n") 78 for _, e := range dedup(entries) { 79 fmt.Fprintf(buf, "\tcase 0x%x: return %q\n", e.value, e.name) 80 } 81 fmt.Fprintf(buf, "\t%s\n", `default: return fmt.Sprintf("gl.Enum(0x%x)", uint32(v))`) 82 fmt.Fprintf(buf, "\t}\n") 83 fmt.Fprintf(buf, "}\n\n") 84 85 for _, d := range f.Decls { 86 // Before: 87 // func (ctx *context) StencilMask(mask uint32) { 88 // C.glStencilMask(C.GLuint(mask)) 89 // } 90 // 91 // After: 92 // func (ctx *context) StencilMask(mask uint32) { 93 // defer func() { 94 // errstr := ctx.errDrain() 95 // log.Printf("gl.StencilMask(%v) %v", mask, errstr) 96 // }() 97 // C.glStencilMask(C.GLuint(mask)) 98 // } 99 fn, ok := d.(*ast.FuncDecl) 100 if !ok { 101 continue 102 } 103 if fn.Recv == nil || fn.Recv.List[0].Names[0].Name != "ctx" { 104 continue 105 } 106 107 var ( 108 params []string 109 paramTypes []string 110 results []string 111 resultTypes []string 112 ) 113 114 // Print function signature. 115 fmt.Fprintf(buf, "func (ctx *context) %s(", fn.Name.Name) 116 for i, p := range fn.Type.Params.List { 117 if i > 0 { 118 fmt.Fprint(buf, ", ") 119 } 120 ty := typeString(p.Type) 121 for i, n := range p.Names { 122 if i > 0 { 123 fmt.Fprint(buf, ", ") 124 } 125 fmt.Fprintf(buf, "%s ", n.Name) 126 params = append(params, n.Name) 127 paramTypes = append(paramTypes, ty) 128 } 129 fmt.Fprint(buf, ty) 130 } 131 fmt.Fprintf(buf, ") (") 132 if fn.Type.Results != nil { 133 for i, r := range fn.Type.Results.List { 134 if i > 0 { 135 fmt.Fprint(buf, ", ") 136 } 137 ty := typeString(r.Type) 138 if len(r.Names) == 0 { 139 name := fmt.Sprintf("r%d", i) 140 fmt.Fprintf(buf, "%s ", name) 141 results = append(results, name) 142 resultTypes = append(resultTypes, ty) 143 } 144 for i, n := range r.Names { 145 if i > 0 { 146 fmt.Fprint(buf, ", ") 147 } 148 fmt.Fprintf(buf, "%s ", n.Name) 149 results = append(results, n.Name) 150 resultTypes = append(resultTypes, ty) 151 } 152 fmt.Fprint(buf, ty) 153 } 154 } 155 fmt.Fprintf(buf, ") {\n") 156 157 // gl.GetError is used by errDrain, which will be made part of 158 // all functions. So do not apply it to gl.GetError to avoid 159 // infinite recursion. 160 skip := fn.Name.Name == "GetError" 161 162 if !skip { 163 // Insert a defer block for tracing. 164 fmt.Fprintf(buf, "defer func() {\n") 165 fmt.Fprintf(buf, "\terrstr := ctx.errDrain()\n") 166 switch fn.Name.Name { 167 case "GetUniformLocation", "GetAttribLocation": 168 fmt.Fprintf(buf, "\tr0.name = name\n") 169 } 170 fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name) 171 for i, p := range paramTypes { 172 if i > 0 { 173 fmt.Fprint(buf, ", ") 174 } 175 fmt.Fprint(buf, typePrinter(p)) 176 } 177 fmt.Fprintf(buf, ") ") 178 if len(resultTypes) > 1 { 179 fmt.Fprint(buf, "(") 180 } 181 for i, r := range resultTypes { 182 if i > 0 { 183 fmt.Fprint(buf, ", ") 184 } 185 fmt.Fprint(buf, typePrinter(r)) 186 } 187 if len(resultTypes) > 1 { 188 fmt.Fprint(buf, ") ") 189 } 190 fmt.Fprintf(buf, "%%v\"") 191 for i, p := range paramTypes { 192 fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i])) 193 } 194 for i, r := range resultTypes { 195 fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i])) 196 } 197 fmt.Fprintf(buf, ", errstr)\n") 198 fmt.Fprintf(buf, "}()\n") 199 } 200 201 // Print original body of function. 202 for _, s := range fn.Body.List { 203 if c := enqueueCall(s); c != nil { 204 c.Fun.(*ast.SelectorExpr).Sel.Name = "enqueueDebug" 205 setEnqueueBlocking(c) 206 } 207 printer.Fprint(buf, fset, s) 208 fmt.Fprintf(buf, "\n") 209 } 210 fmt.Fprintf(buf, "}\n\n") 211 } 212 213 b, err := format.Source(buf.Bytes()) 214 if err != nil { 215 os.Stdout.Write(buf.Bytes()) 216 die(err) 217 } 218 219 if *outfile == "" { 220 os.Stdout.Write(b) 221 return 222 } 223 if err := ioutil.WriteFile(*outfile, b, 0666); err != nil { 224 die(err) 225 } 226 } 227 228 func enqueueCall(stmt ast.Stmt) *ast.CallExpr { 229 exprStmt, ok := stmt.(*ast.ExprStmt) 230 if !ok { 231 return nil 232 } 233 call, ok := exprStmt.X.(*ast.CallExpr) 234 if !ok { 235 return nil 236 } 237 fun, ok := call.Fun.(*ast.SelectorExpr) 238 if !ok { 239 return nil 240 } 241 if fun.Sel.Name != "enqueue" { 242 return nil 243 } 244 return call 245 } 246 247 func setEnqueueBlocking(c *ast.CallExpr) { 248 lit := c.Args[0].(*ast.CompositeLit) 249 for _, elt := range lit.Elts { 250 kv := elt.(*ast.KeyValueExpr) 251 if kv.Key.(*ast.Ident).Name == "blocking" { 252 kv.Value = &ast.Ident{Name: "true"} 253 return 254 } 255 } 256 lit.Elts = append(lit.Elts, &ast.KeyValueExpr{ 257 Key: &ast.Ident{ 258 NamePos: lit.Rbrace, 259 Name: "blocking", 260 }, 261 Value: &ast.Ident{Name: "true"}, 262 }) 263 } 264 265 const preamble = `// Copyright 2014 The Go Authors. All rights reserved. 266 // Use of this source code is governed by a BSD-style 267 // license that can be found in the LICENSE file. 268 269 // Generated from gl.go using go generate. DO NOT EDIT. 270 // See doc.go for details. 271 272 // +build linux darwin windows 273 // +build gldebug 274 275 package gl 276 277 import ( 278 "fmt" 279 "log" 280 "math" 281 "sync/atomic" 282 "unsafe" 283 ) 284 285 func (ctx *context) errDrain() string { 286 var errs []Enum 287 for { 288 e := ctx.GetError() 289 if e == 0 { 290 break 291 } 292 errs = append(errs, e) 293 } 294 if len(errs) > 0 { 295 return fmt.Sprintf(" error: %v", errs) 296 } 297 return "" 298 } 299 300 func (ctx *context) enqueueDebug(c call) uintptr { 301 numCalls := atomic.AddInt32(&ctx.debug, 1) 302 if numCalls > 1 { 303 panic("concurrent calls made to the same GL context") 304 } 305 defer func() { 306 if atomic.AddInt32(&ctx.debug, -1) > 0 { 307 select {} // block so you see us in the panic 308 } 309 }() 310 311 return ctx.enqueue(c) 312 } 313 314 ` 315 316 type entry struct { 317 name string 318 value int 319 } 320 321 // enum builds a list of all GL constants that make up the gl.Enum type. 322 func enum(f *ast.File) []entry { 323 var entries []entry 324 for _, d := range f.Decls { 325 gendecl, ok := d.(*ast.GenDecl) 326 if !ok { 327 continue 328 } 329 if gendecl.Tok != token.CONST { 330 continue 331 } 332 for _, s := range gendecl.Specs { 333 v, ok := s.(*ast.ValueSpec) 334 if !ok { 335 continue 336 } 337 if len(v.Names) != 1 || len(v.Values) != 1 { 338 continue 339 } 340 val, err := strconv.ParseInt(v.Values[0].(*ast.BasicLit).Value, 0, 32) 341 if err != nil { 342 log.Fatalf("enum %s: %v", v.Names[0].Name, err) 343 } 344 entries = append(entries, entry{v.Names[0].Name, int(val)}) 345 } 346 } 347 return entries 348 } 349 350 func dedup(entries []entry) []entry { 351 // Find all duplicates. Use "%d" as the name of any value with duplicates. 352 seen := make(map[int]int) 353 for _, e := range entries { 354 seen[e.value]++ 355 } 356 var dedup []entry 357 for _, e := range entries { 358 switch seen[e.value] { 359 case 0: // skip, already here 360 case 1: 361 dedup = append(dedup, e) 362 default: 363 // value is duplicated 364 dedup = append(dedup, entry{fmt.Sprintf("%d", e.value), e.value}) 365 seen[e.value] = 0 366 } 367 } 368 return dedup 369 }