github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/bind/genclasses.go (about) 1 // Copyright 2016 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 package bind 6 7 import ( 8 "fmt" 9 "path" 10 "reflect" 11 "strings" 12 "unicode" 13 "unicode/utf8" 14 15 "golang.org/x/mobile/internal/importers" 16 "golang.org/x/mobile/internal/importers/java" 17 ) 18 19 type ( 20 // ClassGen generates Go and C stubs for Java classes so import statements 21 // on the form 22 // 23 // 24 // import "Java/classpath/to/Class" 25 // 26 // will work. 27 ClassGen struct { 28 *Printer 29 // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go 30 // package name to create the full Java package name. 31 JavaPkg string 32 imported map[string]struct{} 33 // The list of imported Java classes 34 classes []*java.Class 35 // The list of Go package paths with Java interfaces inside 36 jpkgs []string 37 // For each Go package path, the list of Java classes. 38 typePkgs map[string][]*java.Class 39 // For each Go package path, the Java class with static functions 40 // or constants. 41 clsPkgs map[string]*java.Class 42 // goClsMap is the map of Java class names to Go type names, qualified with package name. Go types 43 // that implement Java classes need Super methods and Unwrap methods. 44 goClsMap map[string]string 45 // goClsImports is the list of imports of user packages that contains the Go types implementing Java 46 // classes. 47 goClsImports []string 48 } 49 ) 50 51 func (g *ClassGen) isSupported(t *java.Type) bool { 52 switch t.Kind { 53 case java.Array: 54 // TODO: Support all array types 55 return t.Elem.Kind == java.Byte 56 default: 57 return true 58 } 59 } 60 61 func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool { 62 for _, f := range fs.Funcs { 63 if g.isFuncSupported(f) { 64 return true 65 } 66 } 67 return false 68 } 69 70 func (g *ClassGen) isFuncSupported(f *java.Func) bool { 71 for _, a := range f.Params { 72 if !g.isSupported(a) { 73 return false 74 } 75 } 76 if f.Ret != nil { 77 return g.isSupported(f.Ret) 78 } 79 return true 80 } 81 82 func (g *ClassGen) goType(t *java.Type, local bool) string { 83 if t == nil { 84 // interface{} is used for parameters types for overloaded methods 85 // where no common ancestor type exists. 86 return "interface{}" 87 } 88 switch t.Kind { 89 case java.Int: 90 return "int32" 91 case java.Boolean: 92 return "bool" 93 case java.Short: 94 return "int16" 95 case java.Char: 96 return "uint16" 97 case java.Byte: 98 return "byte" 99 case java.Long: 100 return "int64" 101 case java.Float: 102 return "float32" 103 case java.Double: 104 return "float64" 105 case java.String: 106 return "string" 107 case java.Array: 108 return "[]" + g.goType(t.Elem, local) 109 case java.Object: 110 name := goClsName(t.Class) 111 if !local { 112 name = "Java." + name 113 } 114 return name 115 default: 116 panic("invalid kind") 117 } 118 } 119 120 // Init initializes the class wrapper generator. Classes is the 121 // list of classes to wrap, goClasses is the list of Java classes 122 // implemented in Go. 123 func (g *ClassGen) Init(classes []*java.Class, goClasses []importers.Struct) { 124 g.goClsMap = make(map[string]string) 125 impMap := make(map[string]struct{}) 126 for _, s := range goClasses { 127 n := s.Pkg + "." + s.Name 128 jn := n 129 if g.JavaPkg != "" { 130 jn = g.JavaPkg + "." + jn 131 } 132 g.goClsMap[jn] = n 133 if _, exists := impMap[s.PkgPath]; !exists { 134 impMap[s.PkgPath] = struct{}{} 135 g.goClsImports = append(g.goClsImports, s.PkgPath) 136 } 137 } 138 g.classes = classes 139 g.imported = make(map[string]struct{}) 140 g.typePkgs = make(map[string][]*java.Class) 141 g.clsPkgs = make(map[string]*java.Class) 142 pkgSet := make(map[string]struct{}) 143 for _, cls := range classes { 144 g.imported[cls.Name] = struct{}{} 145 clsPkg := strings.Replace(cls.Name, ".", "/", -1) 146 g.clsPkgs[clsPkg] = cls 147 typePkg := path.Dir(clsPkg) 148 g.typePkgs[typePkg] = append(g.typePkgs[typePkg], cls) 149 if _, exists := pkgSet[clsPkg]; !exists { 150 pkgSet[clsPkg] = struct{}{} 151 g.jpkgs = append(g.jpkgs, clsPkg) 152 } 153 if _, exists := pkgSet[typePkg]; !exists { 154 pkgSet[typePkg] = struct{}{} 155 g.jpkgs = append(g.jpkgs, typePkg) 156 } 157 } 158 } 159 160 // Packages return the list of Go packages to be generated. 161 func (g *ClassGen) Packages() []string { 162 return g.jpkgs 163 } 164 165 func (g *ClassGen) GenPackage(idx int) { 166 jpkg := g.jpkgs[idx] 167 g.Printf("// File is generated by gobind. Do not edit.\n\n") 168 g.Printf("package %s\n\n", path.Base(jpkg)) 169 g.Printf("import \"Java\"\n\n") 170 g.Printf("const _ = Java.Dummy\n\n") 171 for _, cls := range g.typePkgs[jpkg] { 172 g.Printf("type %s Java.%s\n", cls.PkgName, goClsName(cls.Name)) 173 } 174 if cls, ok := g.clsPkgs[jpkg]; ok { 175 g.Printf("const (\n") 176 g.Indent() 177 // Constants 178 for _, v := range cls.Vars { 179 if g.isSupported(v.Type) && v.Constant() { 180 g.Printf("%s = %s\n", initialUpper(v.Name), v.Val) 181 } 182 } 183 g.Outdent() 184 g.Printf(")\n\n") 185 186 g.Printf("var (\n") 187 g.Indent() 188 // Functions 189 loop: 190 for _, fs := range cls.Funcs { 191 for _, f := range fs.Funcs { 192 if f.Public && g.isFuncSupported(f) { 193 g.Printf("%s func", fs.GoName) 194 g.genFuncDecl(false, fs) 195 g.Printf("\n") 196 continue loop 197 } 198 } 199 } 200 g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name) 201 g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n") 202 g.Printf("// not extend or implement %s.\n", cls.Name) 203 g.Printf("Cast func(v interface{}) Java.%s\n", goClsName(cls.Name)) 204 g.Outdent() 205 g.Printf(")\n\n") 206 } 207 } 208 209 func (g *ClassGen) GenGo() { 210 g.Printf(classesGoHeader) 211 for _, cls := range g.classes { 212 pkgName := strings.Replace(cls.Name, ".", "/", -1) 213 g.Printf("import %q\n", "Java/"+pkgName) 214 } 215 for _, imp := range g.goClsImports { 216 g.Printf("import %q\n", imp) 217 } 218 if len(g.classes) > 0 { 219 g.Printf("import \"unsafe\"\n\n") 220 g.Printf("import \"reflect\"\n\n") 221 g.Printf("import \"fmt\"\n\n") 222 } 223 g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n") 224 g.Printf("// Suppress unused package error\n\n") 225 g.Printf("var _ = _seq.FromRefNum\n") 226 g.Printf("const _ = Java.Dummy\n\n") 227 g.Printf("//export initClasses\n") 228 g.Printf("func initClasses() {\n") 229 g.Indent() 230 g.Printf("C.init_proxies()\n") 231 for _, cls := range g.classes { 232 g.Printf("init_%s()\n", cls.JNIName) 233 } 234 g.Outdent() 235 g.Printf("}\n\n") 236 for _, cls := range g.classes { 237 g.genGo(cls) 238 } 239 } 240 241 func (g *ClassGen) GenH() { 242 g.Printf(classesHHeader) 243 for _, tn := range []string{"jint", "jboolean", "jshort", "jchar", "jbyte", "jlong", "jfloat", "jdouble", "nstring", "nbyteslice"} { 244 g.Printf("typedef struct ret_%s {\n", tn) 245 g.Printf(" %s res;\n", tn) 246 g.Printf(" jint exc;\n") 247 g.Printf("} ret_%s;\n", tn) 248 } 249 g.Printf("\n") 250 for _, cls := range g.classes { 251 for _, fs := range cls.AllMethods { 252 for _, f := range fs.Funcs { 253 if !g.isFuncSupported(f) { 254 continue 255 } 256 g.Printf("extern ") 257 g.genCMethodDecl("cproxy", cls.JNIName, f) 258 g.Printf(";\n") 259 if _, ok := g.goClsMap[cls.Name]; ok { 260 g.Printf("extern ") 261 g.genCMethodDecl("csuper", cls.JNIName, f) 262 g.Printf(";\n") 263 } 264 } 265 } 266 } 267 for _, cls := range g.classes { 268 g.genH(cls) 269 } 270 } 271 272 func (g *ClassGen) GenC() { 273 g.Printf(classesCHeader) 274 for _, cls := range g.classes { 275 g.Printf("static jclass class_%s;\n", cls.JNIName) 276 if _, ok := g.goClsMap[cls.Name]; ok { 277 g.Printf("static jclass sclass_%s;\n", cls.JNIName) 278 } 279 for _, fs := range cls.Funcs { 280 for _, f := range fs.Funcs { 281 if !f.Public || !g.isFuncSupported(f) { 282 continue 283 } 284 g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName) 285 } 286 } 287 for _, fs := range cls.AllMethods { 288 for _, f := range fs.Funcs { 289 if g.isFuncSupported(f) { 290 g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName) 291 if _, ok := g.goClsMap[cls.Name]; ok { 292 g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName) 293 } 294 } 295 } 296 } 297 g.genC(cls) 298 } 299 g.Printf("\n") 300 g.Printf("void init_proxies() {\n") 301 g.Indent() 302 g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(g.classes)) 303 g.Printf("jclass clazz;\n") 304 for _, cls := range g.classes { 305 g.Printf("clazz = go_seq_find_class(%q);\n", strings.Replace(cls.FindName, ".", "/", -1)) 306 g.Printf("if (clazz != NULL) {\n") 307 g.Indent() 308 g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName) 309 if _, ok := g.goClsMap[cls.Name]; ok { 310 g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName) 311 g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName) 312 } 313 for _, fs := range cls.Funcs { 314 for _, f := range fs.Funcs { 315 if !f.Public || !g.isFuncSupported(f) { 316 continue 317 } 318 g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName) 319 if f.Constructor { 320 g.Printf("go_seq_get_method_id(clazz, \"<init>\", %q);\n", f.Desc) 321 } else { 322 g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc) 323 } 324 } 325 } 326 for _, fs := range cls.AllMethods { 327 for _, f := range fs.Funcs { 328 if g.isFuncSupported(f) { 329 g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc) 330 if _, ok := g.goClsMap[cls.Name]; ok { 331 g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc) 332 } 333 } 334 } 335 } 336 g.Outdent() 337 g.Printf("}\n") 338 } 339 g.Printf("go_seq_pop_local_frame(env);\n") 340 g.Outdent() 341 g.Printf("}\n\n") 342 for _, cls := range g.classes { 343 for _, fs := range cls.AllMethods { 344 for _, f := range fs.Funcs { 345 if !g.isFuncSupported(f) { 346 continue 347 } 348 g.genCMethodDecl("cproxy", cls.JNIName, f) 349 g.genCMethodBody(cls, f, false) 350 if _, ok := g.goClsMap[cls.Name]; ok { 351 g.genCMethodDecl("csuper", cls.JNIName, f) 352 g.genCMethodBody(cls, f, true) 353 } 354 } 355 } 356 } 357 } 358 359 func (g *ClassGen) GenInterfaces() { 360 g.Printf(classesPkgHeader) 361 for _, cls := range g.classes { 362 g.genInterface(cls) 363 } 364 } 365 366 func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) { 367 g.Printf(" {\n") 368 g.Indent() 369 // Add 1 for the 'this' argument 370 g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)+1) 371 g.Printf("// Must be a Java object\n") 372 g.Printf("jobject _this = go_seq_from_refnum(env, this, NULL, NULL);\n") 373 for i, a := range f.Params { 374 g.genCToJava(fmt.Sprintf("a%d", i), a) 375 } 376 if f.Ret != nil { 377 g.Printf("%s res = ", f.Ret.JNIType()) 378 } 379 g.Printf("(*env)->Call") 380 if virtual { 381 g.Printf("Nonvirtual") 382 } 383 if f.Ret != nil { 384 g.Printf(f.Ret.JNICallType()) 385 } else { 386 g.Printf("Void") 387 } 388 g.Printf("Method(env, _this, ") 389 if virtual { 390 g.Printf("sclass_%s, sm_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) 391 } else { 392 g.Printf("m_%s_%s", cls.JNIName, f.JNIName) 393 } 394 for i := range f.Params { 395 g.Printf(", _a%d", i) 396 } 397 g.Printf(");\n") 398 g.Printf("jobject _exc = go_seq_get_exception(env);\n") 399 g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") 400 if f.Ret != nil { 401 g.genCRetClear("res", f.Ret, "_exc") 402 g.genJavaToC("res", f.Ret) 403 } 404 g.Printf("go_seq_pop_local_frame(env);\n") 405 if f.Ret != nil { 406 g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) 407 g.Printf("return __res;\n") 408 } else { 409 g.Printf("return _exc_ref;\n") 410 } 411 g.Outdent() 412 g.Printf("}\n\n") 413 } 414 415 func initialUpper(s string) string { 416 if s == "" { 417 return "" 418 } 419 r, n := utf8.DecodeRuneInString(s) 420 return string(unicode.ToUpper(r)) + s[n:] 421 } 422 423 func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) { 424 g.Printf("(") 425 for i, a := range fs.Params { 426 if i > 0 { 427 g.Printf(", ") 428 } 429 g.Printf("a%d ", i) 430 if i == len(fs.Params)-1 && fs.Variadic { 431 g.Printf("...") 432 } 433 g.Printf(g.goType(a, local)) 434 } 435 g.Printf(")") 436 if fs.Throws { 437 if fs.HasRet { 438 g.Printf(" (%s, error)", g.goType(fs.Ret, local)) 439 } else { 440 g.Printf(" error") 441 } 442 } else if fs.HasRet { 443 g.Printf(" %s", g.goType(fs.Ret, local)) 444 } 445 } 446 447 func (g *ClassGen) genC(cls *java.Class) { 448 for _, fs := range cls.Funcs { 449 for _, f := range fs.Funcs { 450 if !f.Public || !g.isFuncSupported(f) { 451 continue 452 } 453 g.genCFuncDecl(cls.JNIName, f) 454 g.Printf(" {\n") 455 g.Indent() 456 g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)) 457 for i, a := range f.Params { 458 g.genCToJava(fmt.Sprintf("a%d", i), a) 459 } 460 if f.Constructor { 461 g.Printf("jobject res = (*env)->NewObject(env") 462 } else if f.Ret != nil { 463 g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType()) 464 } else { 465 g.Printf("(*env)->CallStaticVoidMethod(env") 466 } 467 g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName) 468 for i := range f.Params { 469 g.Printf(", _a%d", i) 470 } 471 g.Printf(");\n") 472 g.Printf("jobject _exc = go_seq_get_exception(env);\n") 473 g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n") 474 if f.Ret != nil { 475 g.genCRetClear("res", f.Ret, "_exc") 476 g.genJavaToC("res", f.Ret) 477 } 478 g.Printf("go_seq_pop_local_frame(env);\n") 479 if f.Ret != nil { 480 g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType()) 481 g.Printf("return __res;\n") 482 } else { 483 g.Printf("return _exc_ref;\n") 484 } 485 g.Outdent() 486 g.Printf("}\n\n") 487 } 488 } 489 } 490 491 func (g *ClassGen) genH(cls *java.Class) { 492 for _, fs := range cls.Funcs { 493 for _, f := range fs.Funcs { 494 if !f.Public || !g.isFuncSupported(f) { 495 continue 496 } 497 g.Printf("extern ") 498 g.genCFuncDecl(cls.JNIName, f) 499 g.Printf(";\n") 500 } 501 } 502 } 503 504 func (g *ClassGen) genCMethodDecl(prefix, jniName string, f *java.Func) { 505 if f.Ret != nil { 506 g.Printf("ret_%s", f.Ret.CType()) 507 } else { 508 // Return only the exception, if any 509 g.Printf("jint") 510 } 511 g.Printf(" %s_%s_%s(jint this", prefix, jniName, f.JNIName) 512 for i, a := range f.Params { 513 g.Printf(", %s a%d", a.CType(), i) 514 } 515 g.Printf(")") 516 } 517 518 func (g *ClassGen) genCFuncDecl(jniName string, f *java.Func) { 519 if f.Ret != nil { 520 g.Printf("ret_%s", f.Ret.CType()) 521 } else { 522 // Return only the exception, if any 523 g.Printf("jint") 524 } 525 g.Printf(" cproxy_s_%s_%s(", jniName, f.JNIName) 526 for i, a := range f.Params { 527 if i > 0 { 528 g.Printf(", ") 529 } 530 g.Printf("%s a%d", a.CType(), i) 531 } 532 g.Printf(")") 533 } 534 535 func (g *ClassGen) genGo(cls *java.Class) { 536 g.Printf("var class_%s C.jclass\n\n", cls.JNIName) 537 g.Printf("func init_%s() {\n", cls.JNIName) 538 g.Indent() 539 g.Printf("cls := C.CString(%q)\n", strings.Replace(cls.FindName, ".", "/", -1)) 540 g.Printf("clazz := C.go_seq_find_class(cls)\n") 541 g.Printf("C.free(unsafe.Pointer(cls))\n") 542 // Before Go 1.11 clazz was a pointer value, an uintptr after. 543 g.Printf("if uintptr(clazz) == 0 {\n") 544 g.Printf(" return\n") 545 g.Printf("}\n") 546 g.Printf("class_%s = clazz\n", cls.JNIName) 547 for _, fs := range cls.Funcs { 548 var supported bool 549 for _, f := range fs.Funcs { 550 if f.Public && g.isFuncSupported(f) { 551 supported = true 552 break 553 } 554 } 555 if !supported { 556 continue 557 } 558 g.Printf("%s.%s = func", cls.PkgName, fs.GoName) 559 g.genFuncDecl(false, fs) 560 g.genFuncBody(cls, fs, "cproxy_s", true) 561 } 562 g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name)) 563 g.Indent() 564 g.Printf("t := reflect.TypeOf((*proxy_class_%s)(nil))\n", cls.JNIName) 565 g.Printf("cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_%s)\n", cls.JNIName) 566 g.Printf("ref := C.jint(_seq.ToRefNum(cv))\n") 567 g.Printf("if C.go_seq_isinstanceof(ref, class_%s) != 1 {\n", cls.JNIName) 568 g.Printf(" panic(fmt.Errorf(\"%%T is not an instance of %%s\", v, %q))\n", cls.Name) 569 g.Printf("}\n") 570 g.Printf("return cv\n") 571 g.Outdent() 572 g.Printf("}\n") 573 g.Outdent() 574 g.Printf("}\n\n") 575 g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName) 576 g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", cls.JNIName) 577 for _, fs := range cls.AllMethods { 578 if !g.isFuncSetSupported(fs) { 579 continue 580 } 581 g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName) 582 g.genFuncDecl(false, fs) 583 g.genFuncBody(cls, fs, "cproxy", false) 584 } 585 if cls.Throwable { 586 g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName) 587 g.Printf(" return p.ToString()\n") 588 g.Printf("}\n") 589 } 590 if goName, ok := g.goClsMap[cls.Name]; ok { 591 g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name)) 592 g.Printf(" return &super_%s{p}\n", cls.JNIName) 593 g.Printf("}\n\n") 594 g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName) 595 g.Printf("func (p *proxy_class_%s) Unwrap() interface{} {\n", cls.JNIName) 596 g.Indent() 597 g.Printf("goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__()))\n") 598 g.Printf("return _seq.FromRefNum(int32(goRefnum)).Get().(*%s)\n", goName) 599 g.Outdent() 600 g.Printf("}\n\n") 601 for _, fs := range cls.AllMethods { 602 if !g.isFuncSetSupported(fs) { 603 continue 604 } 605 g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName) 606 g.genFuncDecl(false, fs) 607 g.genFuncBody(cls, fs, "csuper", false) 608 } 609 } 610 } 611 612 // genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically, 613 // by inspecting the number of arguments (if the FuncSet contains varying parameter counts), 614 // and their types. 615 func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) { 616 maxp := len(fs.Funcs[0].Params) 617 minp := maxp 618 // sort the function variants into argument sizes. 619 buckets := make(map[int][]*java.Func) 620 numF := 0 621 for _, f := range fs.Funcs { 622 if !g.isFuncSupported(f) { 623 continue 624 } 625 numF++ 626 n := len(f.Params) 627 if n < minp { 628 minp = n 629 } else if n > maxp { 630 maxp = n 631 } 632 buckets[n] = append(buckets[n], f) 633 } 634 g.Printf(" {\n") 635 g.Indent() 636 if len(buckets) != 1 { 637 // Switch over the number of arguments. 638 g.Printf("switch %d + len(a%d) {\n", minp, minp) 639 } 640 for i := minp; i <= maxp; i++ { 641 funcs := buckets[i] 642 if len(funcs) == 0 { 643 continue 644 } 645 if len(buckets) != 1 { 646 g.Printf("case %d:\n", i) 647 g.Indent() 648 } 649 for _, f := range funcs { 650 if len(funcs) > 1 { 651 g.Printf("{\n") 652 g.Indent() 653 } 654 var argNames []string 655 var preds []string 656 for i, a := range f.Params { 657 var ct *java.Type 658 var argName string 659 if i >= minp { 660 argName = fmt.Sprintf("a%d[%d]", minp, i-minp) 661 ct = fs.Params[minp] 662 } else { 663 argName = fmt.Sprintf("a%d", i) 664 ct = fs.Params[i] 665 } 666 if !reflect.DeepEqual(ct, a) { 667 g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false)) 668 argName = fmt.Sprintf("_a%d", i) 669 preds = append(preds, fmt.Sprintf("ok%d", i)) 670 } 671 argNames = append(argNames, argName) 672 } 673 if len(preds) > 0 { 674 g.Printf("if %s {\n", strings.Join(preds, " && ")) 675 g.Indent() 676 } 677 for i, a := range f.Params { 678 g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient) 679 } 680 g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName) 681 if !static { 682 g.Printf("C.jint(p.Bind_proxy_refnum__())") 683 } 684 for i := range f.Params { 685 if !static || i > 0 { 686 g.Printf(", ") 687 } 688 g.Printf("__a%d", i) 689 } 690 g.Printf(")\n") 691 g.genFuncRet(fs, f, numF > 1) 692 if len(preds) > 0 { 693 g.Outdent() 694 g.Printf("}\n") 695 } 696 if len(funcs) > 1 { 697 g.Outdent() 698 g.Printf("}\n") 699 } 700 } 701 if len(buckets) != 1 { 702 g.Outdent() 703 } 704 } 705 if len(buckets) != 1 { 706 g.Printf("}\n") 707 } 708 if numF > 1 { 709 g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name) 710 } 711 g.Outdent() 712 g.Printf("}\n\n") 713 } 714 715 func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func, mustReturn bool) { 716 if f.Ret != nil { 717 g.genRead("_res", "res.res", f.Ret, modeRetained) 718 g.genRefRead("_exc", "res.exc", "error", "proxy_error", true) 719 } else { 720 g.genRefRead("_exc", "res", "error", "proxy_error", true) 721 } 722 if !fs.Throws { 723 g.Printf("if (_exc != nil) { panic(_exc) }\n") 724 if fs.HasRet { 725 if f.Ret != nil { 726 g.Printf("return _res\n") 727 } else { 728 // The variant doesn't return a value, but the common 729 // signature does. Use nil as a placeholder return value. 730 g.Printf("return nil\n") 731 } 732 } else if mustReturn { 733 // If there are overloaded variants, return here to avoid the fallback 734 // panic generated in genFuncBody. 735 g.Printf("return\n") 736 } 737 } else { 738 if fs.HasRet { 739 if f.Ret != nil { 740 g.Printf("return _res, _exc\n") 741 } else { 742 // As above, use a nil placeholder return value. 743 g.Printf("return nil, _exc\n") 744 } 745 } else { 746 g.Printf("return _exc\n") 747 } 748 } 749 } 750 751 func (g *ClassGen) genRead(to, from string, t *java.Type, mode varMode) { 752 switch t.Kind { 753 case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double: 754 g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from) 755 case java.Boolean: 756 g.Printf("%s := %s != C.JNI_FALSE\n", to, from) 757 case java.String: 758 g.Printf("%s := decodeString(%s)\n", to, from) 759 case java.Array: 760 if t.Elem.Kind != java.Byte { 761 panic("unsupported array type") 762 } 763 g.Printf("%s := toSlice(%s, %v)\n", to, from, mode == modeRetained) 764 case java.Object: 765 _, hasProxy := g.imported[t.Class] 766 g.genRefRead(to, from, g.goType(t, false), "proxy_class_"+flattenName(t.Class), hasProxy) 767 default: 768 panic("invalid kind") 769 } 770 } 771 772 func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasProxy bool) { 773 g.Printf("var %s %s\n", to, intfName) 774 g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from) 775 g.Printf("if %s_ref != nil {\n", to) 776 g.Printf(" if %s < 0 { // go object\n", from) 777 g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName) 778 g.Printf(" } else { // foreign object\n") 779 if hasProxy { 780 g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to) 781 } else { 782 g.Printf(" %s = %s_ref\n", to, to) 783 } 784 g.Printf(" }\n") 785 g.Printf("}\n") 786 } 787 788 func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) { 789 switch t.Kind { 790 case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double: 791 g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v) 792 case java.Boolean: 793 g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst) 794 g.Printf("if %s {\n", v) 795 g.Printf(" %s = C.jboolean(C.JNI_TRUE)\n", dst) 796 g.Printf("}\n") 797 case java.String: 798 g.Printf("%s := encodeString(%s)\n", dst, v) 799 case java.Array: 800 if t.Elem.Kind != java.Byte { 801 panic("unsupported array type") 802 } 803 g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained) 804 case java.Object: 805 g.Printf("var %s C.jint = _seq.NullRefNum\n", dst) 806 g.Printf("if %s != nil {\n", v) 807 g.Printf(" %s = C.jint(_seq.ToRefNum(%s))\n", dst, v) 808 g.Printf("}\n") 809 default: 810 panic("invalid kind") 811 } 812 } 813 814 // genCRetClear clears the result value from a JNI call if an exception was 815 // raised. 816 func (g *ClassGen) genCRetClear(v string, t *java.Type, exc string) { 817 g.Printf("if (%s != NULL) {\n", exc) 818 g.Indent() 819 switch t.Kind { 820 case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: 821 g.Printf("%s = 0;\n", v) 822 default: 823 // Assume a nullable type. It will break if we missed a type. 824 g.Printf("%s = NULL;\n", v) 825 } 826 g.Outdent() 827 g.Printf("}\n") 828 } 829 830 func (g *ClassGen) genJavaToC(v string, t *java.Type) { 831 switch t.Kind { 832 case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: 833 g.Printf("%s _%s = %s;\n", t.JNIType(), v, v) 834 case java.String: 835 g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", v, v) 836 case java.Array: 837 if t.Elem.Kind != java.Byte { 838 panic("unsupported array type") 839 } 840 g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, 1);\n", v, v) 841 case java.Object: 842 g.Printf("jint _%s = go_seq_to_refnum(env, %s);\n", v, v) 843 default: 844 panic("invalid kind") 845 } 846 } 847 848 func (g *ClassGen) genCToJava(v string, t *java.Type) { 849 switch t.Kind { 850 case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean: 851 g.Printf("%s _%s = %s;\n", t.JNIType(), v, v) 852 case java.String: 853 g.Printf("jstring _%s = go_seq_to_java_string(env, %s);\n", v, v) 854 case java.Array: 855 if t.Elem.Kind != java.Byte { 856 panic("unsupported array type") 857 } 858 g.Printf("jbyteArray _%s = go_seq_to_java_bytearray(env, %s, 0);\n", v, v) 859 case java.Object: 860 g.Printf("jobject _%s = go_seq_from_refnum(env, %s, NULL, NULL);\n", v, v) 861 default: 862 panic("invalid kind") 863 } 864 } 865 866 func goClsName(n string) string { 867 return initialUpper(strings.Replace(n, ".", "_", -1)) 868 } 869 870 func (g *ClassGen) genInterface(cls *java.Class) { 871 g.Printf("type %s interface {\n", goClsName(cls.Name)) 872 g.Indent() 873 // Methods 874 for _, fs := range cls.AllMethods { 875 if !g.isFuncSetSupported(fs) { 876 continue 877 } 878 g.Printf(fs.GoName) 879 g.genFuncDecl(true, fs) 880 g.Printf("\n") 881 } 882 if goName, ok := g.goClsMap[cls.Name]; ok { 883 g.Printf("Super() %s\n", goClsName(cls.Name)) 884 g.Printf("// Unwrap returns the Go object this Java instance\n") 885 g.Printf("// is wrapping.\n") 886 g.Printf("// The return value is a %s, but the delclared type is\n", goName) 887 g.Printf("// interface{} to avoid import cycles.\n") 888 g.Printf("Unwrap() interface{}\n") 889 } 890 if cls.Throwable { 891 g.Printf("Error() string\n") 892 } 893 g.Outdent() 894 g.Printf("}\n\n") 895 } 896 897 // Flatten java class names. "java.package.Class$Inner" is converted to 898 // "java_package_Class_Inner" 899 func flattenName(n string) string { 900 return strings.Replace(strings.Replace(n, ".", "_", -1), "$", "_", -1) 901 } 902 903 var ( 904 classesPkgHeader = `// File is generated by gobind. Do not edit. 905 906 package Java 907 908 // Used to silence this package not used errors 909 const Dummy = 0 910 911 ` 912 classesCHeader = `// File is generated by gobind. Do not edit. 913 914 #include <jni.h> 915 #include "seq.h" 916 #include "classes.h" 917 918 ` 919 classesHHeader = `// File is generated by gobind. Do not edit. 920 921 #include <jni.h> 922 #include "seq.h" 923 924 extern void init_proxies(); 925 926 ` 927 928 javaImplHeader = `// File is generated by gobind. Do not edit. 929 930 ` 931 932 classesGoHeader = `// File is generated by gobind. Do not edit. 933 934 package main 935 936 /* 937 #include <stdlib.h> // for free() 938 #include <jni.h> 939 #include "seq.h" 940 #include "classes.h" 941 */ 942 import "C" 943 944 import ( 945 "Java" 946 _seq "golang.org/x/mobile/bind/seq" 947 ) 948 949 ` 950 )