github.com/champo/mobile@v0.0.0-20190107162257-dc0771356504/bind/genjava.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 package bind 6 7 import ( 8 "fmt" 9 "go/constant" 10 "go/types" 11 "html" 12 "math" 13 "reflect" 14 "regexp" 15 "strings" 16 17 "golang.org/x/mobile/internal/importers/java" 18 ) 19 20 // TODO(crawshaw): disallow basic android java type names in exported symbols. 21 // TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime. 22 23 type JavaGen struct { 24 // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go 25 // package name to create the full Java package name. 26 JavaPkg string 27 28 *Generator 29 30 jstructs map[*types.TypeName]*javaClassInfo 31 clsMap map[string]*java.Class 32 // Constructors is a map from Go struct types to a list 33 // of exported constructor functions for the type, on the form 34 // func New<Type>(...) *Type 35 constructors map[*types.TypeName][]*types.Func 36 } 37 38 type javaClassInfo struct { 39 // The Java class this class extends. 40 extends *java.Class 41 // All Java classes and interfaces this class extends and implements. 42 supers []*java.Class 43 methods map[string]*java.FuncSet 44 // Does the class need a default no-arg constructor 45 genNoargCon bool 46 } 47 48 // Init intializes the embedded Generator and initializes the Java class information 49 // needed to generate structs that extend Java classes and interfaces. 50 func (g *JavaGen) Init(classes []*java.Class) { 51 g.Generator.Init() 52 g.clsMap = make(map[string]*java.Class) 53 for _, cls := range classes { 54 g.clsMap[cls.Name] = cls 55 } 56 g.jstructs = make(map[*types.TypeName]*javaClassInfo) 57 g.constructors = make(map[*types.TypeName][]*types.Func) 58 for _, s := range g.structs { 59 classes := embeddedJavaClasses(s.t) 60 if len(classes) == 0 { 61 continue 62 } 63 inf := &javaClassInfo{ 64 methods: make(map[string]*java.FuncSet), 65 genNoargCon: true, // java.lang.Object has a no-arg constructor 66 } 67 for _, n := range classes { 68 cls := g.clsMap[n] 69 for _, fs := range cls.AllMethods { 70 hasMeth := false 71 for _, f := range fs.Funcs { 72 if !f.Final { 73 hasMeth = true 74 } 75 } 76 if hasMeth { 77 inf.methods[fs.GoName] = fs 78 } 79 } 80 inf.supers = append(inf.supers, cls) 81 if !cls.Interface { 82 if inf.extends != nil { 83 g.errorf("%s embeds more than one Java class; only one is allowed.", s.obj) 84 } 85 if cls.Final { 86 g.errorf("%s embeds final Java class %s", s.obj, cls.Name) 87 } 88 inf.extends = cls 89 inf.genNoargCon = cls.HasNoArgCon 90 } 91 } 92 g.jstructs[s.obj] = inf 93 } 94 for _, f := range g.funcs { 95 if t := g.constructorType(f); t != nil { 96 jinf := g.jstructs[t] 97 if jinf != nil { 98 sig := f.Type().(*types.Signature) 99 jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0 100 } 101 g.constructors[t] = append(g.constructors[t], f) 102 } 103 } 104 } 105 106 func (j *javaClassInfo) toJavaType(T types.Type) *java.Type { 107 switch T := T.(type) { 108 case *types.Basic: 109 var kind java.TypeKind 110 switch T.Kind() { 111 case types.Bool, types.UntypedBool: 112 kind = java.Boolean 113 case types.Uint8: 114 kind = java.Byte 115 case types.Int16: 116 kind = java.Short 117 case types.Int32, types.UntypedRune: // types.Rune 118 kind = java.Int 119 case types.Int64, types.UntypedInt: 120 kind = java.Long 121 case types.Float32: 122 kind = java.Float 123 case types.Float64, types.UntypedFloat: 124 kind = java.Double 125 case types.String, types.UntypedString: 126 kind = java.String 127 default: 128 return nil 129 } 130 return &java.Type{Kind: kind} 131 case *types.Slice: 132 switch e := T.Elem().(type) { 133 case *types.Basic: 134 switch e.Kind() { 135 case types.Uint8: // Byte. 136 return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}} 137 } 138 } 139 return nil 140 case *types.Named: 141 if isJavaType(T) { 142 return &java.Type{Kind: java.Object, Class: classNameFor(T)} 143 } 144 } 145 return nil 146 } 147 148 // lookupMethod searches the Java class descriptor for a method 149 // that matches the Go method. 150 func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func { 151 jm := j.methods[m.Name()] 152 if jm == nil { 153 // If an exact match is not found, try the method with trailing underscores 154 // stripped. This way, name clashes can be avoided when overriding multiple 155 // overloaded methods from Go. 156 base := strings.TrimRight(m.Name(), "_") 157 jm = j.methods[base] 158 if jm == nil { 159 return nil 160 } 161 } 162 // A name match was found. Now use the parameter and return types to locate 163 // the correct variant. 164 sig := m.Type().(*types.Signature) 165 params := sig.Params() 166 // Convert Go parameter types to their Java counterparts, if possible. 167 var jparams []*java.Type 168 i := 0 169 if hasThis { 170 i = 1 171 } 172 for ; i < params.Len(); i++ { 173 jparams = append(jparams, j.toJavaType(params.At(i).Type())) 174 } 175 var ret *java.Type 176 var throws bool 177 if results := sig.Results(); results.Len() > 0 { 178 ret = j.toJavaType(results.At(0).Type()) 179 if results.Len() > 1 { 180 throws = isErrorType(results.At(1).Type()) 181 } 182 } 183 loop: 184 for _, f := range jm.Funcs { 185 if len(f.Params) != len(jparams) { 186 continue 187 } 188 if throws != (f.Throws != "") { 189 continue 190 } 191 if !reflect.DeepEqual(ret, f.Ret) { 192 continue 193 } 194 for i, p := range f.Params { 195 if !reflect.DeepEqual(p, jparams[i]) { 196 continue loop 197 } 198 } 199 return f 200 } 201 return nil 202 } 203 204 // ClassNames returns the list of names of the generated Java classes and interfaces. 205 func (g *JavaGen) ClassNames() []string { 206 var names []string 207 for _, s := range g.structs { 208 names = append(names, g.javaTypeName(s.obj.Name())) 209 } 210 for _, iface := range g.interfaces { 211 names = append(names, g.javaTypeName(iface.obj.Name())) 212 } 213 return names 214 } 215 216 func (g *JavaGen) GenClass(idx int) error { 217 ns := len(g.structs) 218 if idx < ns { 219 s := g.structs[idx] 220 g.genStruct(s) 221 } else { 222 iface := g.interfaces[idx-ns] 223 g.genInterface(iface) 224 } 225 if len(g.err) > 0 { 226 return g.err 227 } 228 return nil 229 } 230 231 func (g *JavaGen) genProxyImpl(name string) { 232 g.Printf("private final int refnum;\n\n") 233 g.Printf("@Override public final int incRefnum() {\n") 234 g.Printf(" Seq.incGoRef(refnum, this);\n") 235 g.Printf(" return refnum;\n") 236 g.Printf("}\n\n") 237 } 238 239 func (g *JavaGen) genStruct(s structInfo) { 240 pkgPath := "" 241 if g.Pkg != nil { 242 pkgPath = g.Pkg.Path() 243 } 244 n := g.javaTypeName(s.obj.Name()) 245 g.Printf(javaPreamble, g.javaPkgName(g.Pkg), n, g.gobindOpts(), pkgPath) 246 247 fields := exportedFields(s.t) 248 methods := exportedMethodSet(types.NewPointer(s.obj.Type())) 249 250 var impls []string 251 jinf := g.jstructs[s.obj] 252 if jinf != nil { 253 impls = append(impls, "Seq.GoObject") 254 for _, cls := range jinf.supers { 255 if cls.Interface { 256 impls = append(impls, g.javaTypeName(cls.Name)) 257 } 258 } 259 } else { 260 impls = append(impls, "Seq.Proxy") 261 } 262 263 pT := types.NewPointer(s.obj.Type()) 264 for _, iface := range g.allIntf { 265 if types.AssignableTo(pT, iface.obj.Type()) { 266 n := iface.obj.Name() 267 if p := iface.obj.Pkg(); p != g.Pkg { 268 if n == JavaClassName(p) { 269 n = n + "_" 270 } 271 n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n) 272 } else { 273 n = g.javaTypeName(n) 274 } 275 impls = append(impls, n) 276 } 277 } 278 279 doc := g.docs[n] 280 g.javadoc(doc.Doc()) 281 g.Printf("public final class %s", n) 282 if jinf != nil { 283 if jinf.extends != nil { 284 g.Printf(" extends %s", g.javaTypeName(jinf.extends.Name)) 285 } 286 } 287 if len(impls) > 0 { 288 g.Printf(" implements %s", strings.Join(impls, ", ")) 289 } 290 g.Printf(" {\n") 291 g.Indent() 292 293 g.Printf("static { %s.touch(); }\n\n", g.className()) 294 g.genProxyImpl(n) 295 cons := g.constructors[s.obj] 296 for _, f := range cons { 297 if !g.isSigSupported(f.Type()) { 298 g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name()) 299 continue 300 } 301 g.genConstructor(f, n, jinf != nil) 302 } 303 if jinf == nil || jinf.genNoargCon { 304 // constructor for Go instantiated instances. 305 g.Printf("%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n) 306 if len(cons) == 0 { 307 // Generate default no-arg constructor 308 g.Printf("public %s() { this.refnum = __New(); Seq.trackGoRef(refnum, this); }\n\n", n) 309 g.Printf("private static native int __New();\n\n") 310 } 311 } 312 313 for _, f := range fields { 314 if t := f.Type(); !g.isSupported(t) { 315 g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t) 316 continue 317 } 318 319 fdoc := doc.Member(f.Name()) 320 g.javadoc(fdoc) 321 g.Printf("public final native %s get%s();\n", g.javaType(f.Type()), f.Name()) 322 g.javadoc(fdoc) 323 g.Printf("public final native void set%s(%s v);\n\n", f.Name(), g.javaType(f.Type())) 324 } 325 326 var isStringer bool 327 for _, m := range methods { 328 if !g.isSigSupported(m.Type()) { 329 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name()) 330 continue 331 } 332 g.javadoc(doc.Member(m.Name())) 333 var jm *java.Func 334 hasThis := false 335 if jinf != nil { 336 hasThis = g.hasThis(n, m) 337 jm = jinf.lookupMethod(m, hasThis) 338 if jm != nil { 339 g.Printf("@Override ") 340 } 341 } 342 g.Printf("public native ") 343 g.genFuncSignature(m, jm, hasThis) 344 t := m.Type().(*types.Signature) 345 isStringer = isStringer || (m.Name() == "String" && t.Params().Len() == 0 && t.Results().Len() == 1 && 346 types.Identical(t.Results().At(0).Type(), types.Typ[types.String])) 347 } 348 349 if jinf == nil { 350 g.genObjectMethods(n, fields, isStringer) 351 } 352 353 g.Outdent() 354 g.Printf("}\n\n") 355 } 356 357 // javaTypeName returns the class name of a given Go type name. If 358 // the type name clashes with the package class name, an underscore is 359 // appended. 360 func (g *JavaGen) javaTypeName(n string) string { 361 if n == JavaClassName(g.Pkg) { 362 return n + "_" 363 } 364 return n 365 } 366 367 func (g *JavaGen) javadoc(doc string) { 368 if doc == "" { 369 return 370 } 371 // JavaDoc expects HTML-escaped documentation. 372 g.Printf("/**\n * %s */\n", html.EscapeString(doc)) 373 } 374 375 // hasThis reports whether a method has an implicit "this" parameter. 376 func (g *JavaGen) hasThis(sName string, m *types.Func) bool { 377 sig := m.Type().(*types.Signature) 378 params := sig.Params() 379 if params.Len() == 0 { 380 return false 381 } 382 v := params.At(0) 383 if v.Name() != "this" { 384 return false 385 } 386 t, ok := v.Type().(*types.Named) 387 if !ok { 388 return false 389 } 390 obj := t.Obj() 391 pkg := obj.Pkg() 392 if pkgFirstElem(pkg) != "Java" { 393 return false 394 } 395 clsName := classNameFor(t) 396 exp := g.javaPkgName(g.Pkg) + "." + sName 397 if clsName != exp { 398 g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp) 399 return false 400 } 401 return true 402 } 403 404 func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) { 405 g.javadoc(g.docs[f.Name()].Doc()) 406 g.Printf("public %s(", n) 407 g.genFuncArgs(f, nil, false) 408 g.Printf(") {\n") 409 g.Indent() 410 sig := f.Type().(*types.Signature) 411 params := sig.Params() 412 if jcls { 413 g.Printf("super(") 414 for i := 0; i < params.Len(); i++ { 415 if i > 0 { 416 g.Printf(", ") 417 } 418 g.Printf(g.paramName(params, i)) 419 } 420 g.Printf(");\n") 421 } 422 g.Printf("this.refnum = ") 423 g.Printf("__%s(", f.Name()) 424 for i := 0; i < params.Len(); i++ { 425 if i > 0 { 426 g.Printf(", ") 427 } 428 g.Printf(g.paramName(params, i)) 429 } 430 g.Printf(");\n") 431 g.Printf("Seq.trackGoRef(refnum, this);\n") 432 g.Outdent() 433 g.Printf("}\n\n") 434 g.Printf("private static native int __%s(", f.Name()) 435 g.genFuncArgs(f, nil, false) 436 g.Printf(");\n\n") 437 } 438 439 // genFuncArgs generated Java function arguments declaration for the function f. 440 // If the supplied overridden java function is supplied, genFuncArgs omits the implicit 441 // this argument. 442 func (g *JavaGen) genFuncArgs(f *types.Func, jm *java.Func, hasThis bool) { 443 sig := f.Type().(*types.Signature) 444 params := sig.Params() 445 first := 0 446 if hasThis { 447 // Skip the implicit this argument to the Go method 448 first = 1 449 } 450 for i := first; i < params.Len(); i++ { 451 if i > first { 452 g.Printf(", ") 453 } 454 v := params.At(i) 455 name := g.paramName(params, i) 456 jt := g.javaType(v.Type()) 457 g.Printf("%s %s", jt, name) 458 } 459 } 460 461 func (g *JavaGen) genObjectMethods(n string, fields []*types.Var, isStringer bool) { 462 g.Printf("@Override public boolean equals(Object o) {\n") 463 g.Indent() 464 g.Printf("if (o == null || !(o instanceof %s)) {\n return false;\n}\n", n) 465 g.Printf("%s that = (%s)o;\n", n, n) 466 for _, f := range fields { 467 if t := f.Type(); !g.isSupported(t) { 468 g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t) 469 continue 470 } 471 nf := f.Name() 472 g.Printf("%s this%s = get%s();\n", g.javaType(f.Type()), nf, nf) 473 g.Printf("%s that%s = that.get%s();\n", g.javaType(f.Type()), nf, nf) 474 if isJavaPrimitive(f.Type()) { 475 g.Printf("if (this%s != that%s) {\n return false;\n}\n", nf, nf) 476 } else { 477 g.Printf("if (this%s == null) {\n", nf) 478 g.Indent() 479 g.Printf("if (that%s != null) {\n return false;\n}\n", nf) 480 g.Outdent() 481 g.Printf("} else if (!this%s.equals(that%s)) {\n return false;\n}\n", nf, nf) 482 } 483 } 484 g.Printf("return true;\n") 485 g.Outdent() 486 g.Printf("}\n\n") 487 488 g.Printf("@Override public int hashCode() {\n") 489 g.Printf(" return java.util.Arrays.hashCode(new Object[] {") 490 idx := 0 491 for _, f := range fields { 492 if t := f.Type(); !g.isSupported(t) { 493 continue 494 } 495 if idx > 0 { 496 g.Printf(", ") 497 } 498 idx++ 499 g.Printf("get%s()", f.Name()) 500 } 501 g.Printf("});\n") 502 g.Printf("}\n\n") 503 504 g.Printf("@Override public String toString() {\n") 505 g.Indent() 506 if isStringer { 507 g.Printf("return string();\n") 508 } else { 509 g.Printf("StringBuilder b = new StringBuilder();\n") 510 g.Printf(`b.append("%s").append("{");`, n) 511 g.Printf("\n") 512 for _, f := range fields { 513 if t := f.Type(); !g.isSupported(t) { 514 continue 515 } 516 n := f.Name() 517 g.Printf(`b.append("%s:").append(get%s()).append(",");`, n, n) 518 g.Printf("\n") 519 } 520 g.Printf(`return b.append("}").toString();`) 521 g.Printf("\n") 522 } 523 g.Outdent() 524 g.Printf("}\n") 525 } 526 527 func (g *JavaGen) genInterface(iface interfaceInfo) { 528 pkgPath := "" 529 if g.Pkg != nil { 530 pkgPath = g.Pkg.Path() 531 } 532 g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.javaTypeName(iface.obj.Name()), g.gobindOpts(), pkgPath) 533 534 var exts []string 535 numM := iface.t.NumMethods() 536 for _, other := range g.allIntf { 537 // Only extend interfaces with fewer methods to avoid circular references 538 if other.t.NumMethods() < numM && types.AssignableTo(iface.t, other.t) { 539 n := other.obj.Name() 540 if p := other.obj.Pkg(); p != g.Pkg { 541 if n == JavaClassName(p) { 542 n = n + "_" 543 } 544 n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n) 545 } else { 546 n = g.javaTypeName(n) 547 } 548 exts = append(exts, n) 549 } 550 } 551 doc := g.docs[iface.obj.Name()] 552 g.javadoc(doc.Doc()) 553 g.Printf("public interface %s", g.javaTypeName(iface.obj.Name())) 554 if len(exts) > 0 { 555 g.Printf(" extends %s", strings.Join(exts, ", ")) 556 } 557 g.Printf(" {\n") 558 g.Indent() 559 560 for _, m := range iface.summary.callable { 561 if !g.isSigSupported(m.Type()) { 562 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) 563 continue 564 } 565 g.javadoc(doc.Member(m.Name())) 566 g.Printf("public ") 567 g.genFuncSignature(m, nil, false) 568 } 569 570 g.Printf("\n") 571 572 g.Outdent() 573 g.Printf("}\n\n") 574 } 575 576 func isJavaPrimitive(T types.Type) bool { 577 b, ok := T.(*types.Basic) 578 if !ok { 579 return false 580 } 581 switch b.Kind() { 582 case types.Bool, types.Uint8, types.Float32, types.Float64, 583 types.Int, types.Int8, types.Int16, types.Int32, types.Int64: 584 return true 585 } 586 return false 587 } 588 589 // jniType returns a string that can be used as a JNI type. 590 func (g *JavaGen) jniType(T types.Type) string { 591 switch T := T.(type) { 592 case *types.Basic: 593 switch T.Kind() { 594 case types.Bool, types.UntypedBool: 595 return "jboolean" 596 case types.Int: 597 return "jlong" 598 case types.Int8: 599 return "jbyte" 600 case types.Int16: 601 return "jshort" 602 case types.Int32, types.UntypedRune: // types.Rune 603 return "jint" 604 case types.Int64, types.UntypedInt: 605 return "jlong" 606 case types.Uint8: // types.Byte 607 // TODO(crawshaw): Java bytes are signed, so this is 608 // questionable, but vital. 609 return "jbyte" 610 // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: 611 case types.Float32: 612 return "jfloat" 613 case types.Float64, types.UntypedFloat: 614 return "jdouble" 615 case types.String, types.UntypedString: 616 return "jstring" 617 default: 618 g.errorf("unsupported basic type: %s", T) 619 return "TODO" 620 } 621 case *types.Slice: 622 return "jbyteArray" 623 624 case *types.Pointer: 625 if _, ok := T.Elem().(*types.Named); ok { 626 return g.jniType(T.Elem()) 627 } 628 g.errorf("unsupported pointer to type: %s", T) 629 case *types.Named: 630 return "jobject" 631 default: 632 g.errorf("unsupported jniType: %#+v, %s\n", T, T) 633 } 634 return "TODO" 635 } 636 637 func (g *JavaGen) javaBasicType(T *types.Basic) string { 638 switch T.Kind() { 639 case types.Bool, types.UntypedBool: 640 return "boolean" 641 case types.Int: 642 return "long" 643 case types.Int8: 644 return "byte" 645 case types.Int16: 646 return "short" 647 case types.Int32, types.UntypedRune: // types.Rune 648 return "int" 649 case types.Int64, types.UntypedInt: 650 return "long" 651 case types.Uint8: // types.Byte 652 // TODO(crawshaw): Java bytes are signed, so this is 653 // questionable, but vital. 654 return "byte" 655 // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: 656 case types.Float32: 657 return "float" 658 case types.Float64, types.UntypedFloat: 659 return "double" 660 case types.String, types.UntypedString: 661 return "String" 662 default: 663 g.errorf("unsupported basic type: %s", T) 664 return "TODO" 665 } 666 } 667 668 // javaType returns a string that can be used as a Java type. 669 func (g *JavaGen) javaType(T types.Type) string { 670 if isErrorType(T) { 671 // The error type is usually translated into an exception in 672 // Java, however the type can be exposed in other ways, such 673 // as an exported field. 674 return "java.lang.Exception" 675 } else if isJavaType(T) { 676 return classNameFor(T) 677 } 678 switch T := T.(type) { 679 case *types.Basic: 680 return g.javaBasicType(T) 681 case *types.Slice: 682 elem := g.javaType(T.Elem()) 683 return elem + "[]" 684 685 case *types.Pointer: 686 if _, ok := T.Elem().(*types.Named); ok { 687 return g.javaType(T.Elem()) 688 } 689 g.errorf("unsupported pointer to type: %s", T) 690 case *types.Named: 691 n := T.Obj() 692 nPkg := n.Pkg() 693 if !isErrorType(T) && !g.validPkg(nPkg) { 694 g.errorf("type %s is in %s, which is not bound", n.Name(), nPkg) 695 break 696 } 697 // TODO(crawshaw): more checking here 698 clsName := n.Name() 699 if nPkg != g.Pkg { 700 if clsName == JavaClassName(nPkg) { 701 clsName += "_" 702 } 703 return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), clsName) 704 } else { 705 return g.javaTypeName(clsName) 706 } 707 default: 708 g.errorf("unsupported javaType: %#+v, %s\n", T, T) 709 } 710 return "TODO" 711 } 712 713 func (g *JavaGen) genJNIFuncSignature(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) { 714 sig := o.Type().(*types.Signature) 715 res := sig.Results() 716 717 var ret string 718 switch res.Len() { 719 case 2: 720 ret = g.jniType(res.At(0).Type()) 721 case 1: 722 if isErrorType(res.At(0).Type()) { 723 ret = "void" 724 } else { 725 ret = g.jniType(res.At(0).Type()) 726 } 727 case 0: 728 ret = "void" 729 default: 730 g.errorf("too many result values: %s", o) 731 return 732 } 733 734 g.Printf("JNIEXPORT %s JNICALL\n", ret) 735 g.Printf("Java_%s_", g.jniPkgName()) 736 if sName != "" { 737 if proxy { 738 g.Printf(java.JNIMangle(g.className())) 739 // 0024 is the mangled form of $, for naming inner classes. 740 g.Printf("_00024proxy%s", sName) 741 } else { 742 g.Printf(java.JNIMangle(g.javaTypeName(sName))) 743 } 744 } else { 745 g.Printf(java.JNIMangle(g.className())) 746 } 747 g.Printf("_") 748 if jm != nil { 749 g.Printf(jm.JNIName) 750 } else { 751 oName := javaNameReplacer(lowerFirst(o.Name())) 752 g.Printf(java.JNIMangle(oName)) 753 } 754 g.Printf("(JNIEnv* env, ") 755 if sName != "" { 756 g.Printf("jobject __this__") 757 } else { 758 g.Printf("jclass _clazz") 759 } 760 params := sig.Params() 761 i := 0 762 if isjava && params.Len() > 0 && params.At(0).Name() == "this" { 763 // Skip the implicit this argument, if any. 764 i = 1 765 } 766 for ; i < params.Len(); i++ { 767 g.Printf(", ") 768 v := sig.Params().At(i) 769 name := g.paramName(params, i) 770 jt := g.jniType(v.Type()) 771 g.Printf("%s %s", jt, name) 772 } 773 g.Printf(")") 774 } 775 776 func (g *JavaGen) jniPkgName() string { 777 return strings.Replace(java.JNIMangle(g.javaPkgName(g.Pkg)), ".", "_", -1) 778 } 779 780 var javaLetterDigitRE = regexp.MustCompile(`[0-9a-zA-Z$_]`) 781 782 func (g *JavaGen) paramName(params *types.Tuple, pos int) string { 783 name := basicParamName(params, pos) 784 if !javaLetterDigitRE.MatchString(name) { 785 name = fmt.Sprintf("p%d", pos) 786 } 787 return javaNameReplacer(name) 788 } 789 790 func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) { 791 sig := o.Type().(*types.Signature) 792 res := sig.Results() 793 794 var returnsError bool 795 var ret string 796 switch res.Len() { 797 case 2: 798 if !isErrorType(res.At(1).Type()) { 799 g.errorf("second result value must be of type error: %s", o) 800 return 801 } 802 returnsError = true 803 ret = g.javaType(res.At(0).Type()) 804 case 1: 805 if isErrorType(res.At(0).Type()) { 806 returnsError = true 807 ret = "void" 808 } else { 809 ret = g.javaType(res.At(0).Type()) 810 } 811 case 0: 812 ret = "void" 813 default: 814 g.errorf("too many result values: %s", o) 815 return 816 } 817 818 g.Printf("%s ", ret) 819 if jm != nil { 820 g.Printf(jm.Name) 821 } else { 822 g.Printf(javaNameReplacer(lowerFirst(o.Name()))) 823 } 824 g.Printf("(") 825 g.genFuncArgs(o, jm, hasThis) 826 g.Printf(")") 827 if returnsError { 828 if jm != nil { 829 if jm.Throws == "" { 830 g.errorf("%s declares an error return value but the overriden method does not throw", o) 831 return 832 } 833 g.Printf(" throws %s", jm.Throws) 834 } else { 835 g.Printf(" throws Exception") 836 } 837 } 838 g.Printf(";\n") 839 } 840 841 func (g *JavaGen) genVar(o *types.Var) { 842 if t := o.Type(); !g.isSupported(t) { 843 g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) 844 return 845 } 846 jType := g.javaType(o.Type()) 847 848 doc := g.docs[o.Name()].Doc() 849 // setter 850 g.javadoc(doc) 851 g.Printf("public static native void set%s(%s v);\n", o.Name(), jType) 852 853 // getter 854 g.javadoc(doc) 855 g.Printf("public static native %s get%s();\n\n", jType, o.Name()) 856 } 857 858 // genCRetClear clears the result value from a JNI call if an exception was 859 // raised. 860 func (g *JavaGen) genCRetClear(varName string, t types.Type, exc string) { 861 g.Printf("if (%s != NULL) {\n", exc) 862 g.Indent() 863 switch t := t.(type) { 864 case *types.Basic: 865 switch t.Kind() { 866 case types.String: 867 g.Printf("%s = NULL;\n", varName) 868 default: 869 g.Printf("%s = 0;\n", varName) 870 } 871 case *types.Slice, *types.Named, *types.Pointer: 872 g.Printf("%s = NULL;\n", varName) 873 } 874 g.Outdent() 875 g.Printf("}\n") 876 } 877 878 func (g *JavaGen) genJavaToC(varName string, t types.Type, mode varMode) { 879 switch t := t.(type) { 880 case *types.Basic: 881 switch t.Kind() { 882 case types.String: 883 g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", varName, varName) 884 default: 885 g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) 886 } 887 case *types.Slice: 888 switch e := t.Elem().(type) { 889 case *types.Basic: 890 switch e.Kind() { 891 case types.Uint8: // Byte. 892 g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) 893 default: 894 g.errorf("unsupported type: %s", t) 895 } 896 default: 897 g.errorf("unsupported type: %s", t) 898 } 899 case *types.Named: 900 switch u := t.Underlying().(type) { 901 case *types.Interface: 902 g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) 903 default: 904 g.errorf("unsupported named type: %s / %T", u, u) 905 } 906 case *types.Pointer: 907 g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) 908 default: 909 g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) 910 } 911 } 912 913 func (g *JavaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) { 914 switch t := t.(type) { 915 case *types.Basic: 916 switch t.Kind() { 917 case types.String: 918 g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName) 919 case types.Bool: 920 g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName) 921 default: 922 g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) 923 } 924 case *types.Slice: 925 switch e := t.Elem().(type) { 926 case *types.Basic: 927 switch e.Kind() { 928 case types.Uint8: // Byte. 929 g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, toCFlag(mode == modeRetained)) 930 default: 931 g.errorf("unsupported type: %s", t) 932 } 933 default: 934 g.errorf("unsupported type: %s", t) 935 } 936 case *types.Pointer: 937 // TODO(crawshaw): test *int 938 // TODO(crawshaw): test **Generator 939 switch t := t.Elem().(type) { 940 case *types.Named: 941 g.genFromRefnum(toName, fromName, t, t.Obj()) 942 default: 943 g.errorf("unsupported type %s", t) 944 } 945 case *types.Named: 946 switch t.Underlying().(type) { 947 case *types.Interface, *types.Pointer: 948 g.genFromRefnum(toName, fromName, t, t.Obj()) 949 default: 950 g.errorf("unsupported, direct named type %s", t) 951 } 952 default: 953 g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) 954 } 955 } 956 957 func (g *JavaGen) genFromRefnum(toName, fromName string, t types.Type, o *types.TypeName) { 958 oPkg := o.Pkg() 959 isJava := isJavaType(o.Type()) 960 if !isErrorType(o.Type()) && !g.validPkg(oPkg) && !isJava { 961 g.errorf("type %s is defined in package %s, which is not bound", t, oPkg) 962 return 963 } 964 p := pkgPrefix(oPkg) 965 g.Printf("jobject %s = go_seq_from_refnum(env, %s, ", toName, fromName) 966 if isJava { 967 g.Printf("NULL, NULL") 968 } else { 969 g.Printf("proxy_class_%s_%s, proxy_class_%s_%s_cons", p, o.Name(), p, o.Name()) 970 } 971 g.Printf(");\n") 972 } 973 974 func (g *JavaGen) gobindOpts() string { 975 opts := []string{"-lang=java"} 976 if g.JavaPkg != "" { 977 opts = append(opts, "-javapkg="+g.JavaPkg) 978 } 979 return strings.Join(opts, " ") 980 } 981 982 var javaNameReplacer = newNameSanitizer([]string{ 983 "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", 984 "class", "const", "continue", "default", "do", "double", "else", "enum", 985 "extends", "final", "finally", "float", "for", "goto", "if", "implements", 986 "import", "instanceof", "int", "interface", "long", "native", "new", "package", 987 "private", "protected", "public", "return", "short", "static", "strictfp", 988 "super", "switch", "synchronized", "this", "throw", "throws", "transient", 989 "try", "void", "volatile", "while", "false", "null", "true"}) 990 991 func (g *JavaGen) javaPkgName(pkg *types.Package) string { 992 return JavaPkgName(g.JavaPkg, pkg) 993 } 994 995 // JavaPkgName returns the Java package name for a Go package 996 // given a pkg prefix. If the prefix is empty, "go" is used 997 // instead. 998 func JavaPkgName(pkgPrefix string, pkg *types.Package) string { 999 if pkg == nil { 1000 return "go" 1001 } 1002 s := javaNameReplacer(pkg.Name()) 1003 if pkgPrefix == "" { 1004 return s 1005 } 1006 return pkgPrefix + "." + s 1007 } 1008 1009 func (g *JavaGen) className() string { 1010 return JavaClassName(g.Pkg) 1011 } 1012 1013 // JavaClassName returns the name of the Java class that 1014 // contains Go package level identifiers. 1015 func JavaClassName(pkg *types.Package) string { 1016 if pkg == nil { 1017 return "Universe" 1018 } 1019 return javaNameReplacer(strings.Title(pkg.Name())) 1020 } 1021 1022 func (g *JavaGen) genConst(o *types.Const) { 1023 if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) { 1024 g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type()) 1025 return 1026 } 1027 // TODO(hyangah): should const names use upper cases + "_"? 1028 // TODO(hyangah): check invalid names. 1029 jType := g.javaType(o.Type()) 1030 val := o.Val().ExactString() 1031 switch b := o.Type().(*types.Basic); b.Kind() { 1032 case types.Int64, types.UntypedInt: 1033 i, exact := constant.Int64Val(o.Val()) 1034 if !exact { 1035 g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType) 1036 return 1037 } 1038 val = fmt.Sprintf("%dL", i) 1039 1040 case types.Float32: 1041 f, _ := constant.Float32Val(o.Val()) 1042 val = fmt.Sprintf("%gf", f) 1043 1044 case types.Float64, types.UntypedFloat: 1045 f, _ := constant.Float64Val(o.Val()) 1046 if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 { 1047 g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType) 1048 return 1049 } 1050 val = fmt.Sprintf("%g", f) 1051 } 1052 g.javadoc(g.docs[o.Name()].Doc()) 1053 g.Printf("public static final %s %s = %s;\n", g.javaType(o.Type()), o.Name(), val) 1054 } 1055 1056 func (g *JavaGen) genJNIField(o *types.TypeName, f *types.Var) { 1057 if t := f.Type(); !g.isSupported(t) { 1058 g.Printf("// skipped field %s with unsupported type: %s\n\n", o.Name(), t) 1059 return 1060 } 1061 n := java.JNIMangle(g.javaTypeName(o.Name())) 1062 // setter 1063 g.Printf("JNIEXPORT void JNICALL\n") 1064 g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()), g.jniType(f.Type())) 1065 g.Indent() 1066 g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n") 1067 g.genJavaToC("v", f.Type(), modeRetained) 1068 g.Printf("proxy%s_%s_%s_Set(o, _v);\n", g.pkgPrefix, o.Name(), f.Name()) 1069 g.genRelease("v", f.Type(), modeRetained) 1070 g.Outdent() 1071 g.Printf("}\n\n") 1072 1073 // getter 1074 g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type())) 1075 g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name())) 1076 g.Indent() 1077 g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n") 1078 g.Printf("%s r0 = ", g.cgoType(f.Type())) 1079 g.Printf("proxy%s_%s_%s_Get(o);\n", g.pkgPrefix, o.Name(), f.Name()) 1080 g.genCToJava("_r0", "r0", f.Type(), modeRetained) 1081 g.Printf("return _r0;\n") 1082 g.Outdent() 1083 g.Printf("}\n\n") 1084 } 1085 1086 func (g *JavaGen) genJNIVar(o *types.Var) { 1087 if t := o.Type(); !g.isSupported(t) { 1088 g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t) 1089 return 1090 } 1091 n := java.JNIMangle(g.javaTypeName(o.Name())) 1092 // setter 1093 g.Printf("JNIEXPORT void JNICALL\n") 1094 g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n, g.jniType(o.Type())) 1095 g.Indent() 1096 g.genJavaToC("v", o.Type(), modeRetained) 1097 g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) 1098 g.genRelease("v", o.Type(), modeRetained) 1099 g.Outdent() 1100 g.Printf("}\n\n") 1101 1102 // getter 1103 g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type())) 1104 g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n) 1105 g.Indent() 1106 g.Printf("%s r0 = ", g.cgoType(o.Type())) 1107 g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) 1108 g.genCToJava("_r0", "r0", o.Type(), modeRetained) 1109 g.Printf("return _r0;\n") 1110 g.Outdent() 1111 g.Printf("}\n\n") 1112 } 1113 1114 func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { 1115 if !g.isSigSupported(f.Type()) { 1116 return 1117 } 1118 sig := f.Type().(*types.Signature) 1119 res := sig.Results() 1120 1121 g.Printf("JNIEXPORT jint JNICALL\n") 1122 g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__"+f.Name())) 1123 params := sig.Params() 1124 for i := 0; i < params.Len(); i++ { 1125 v := params.At(i) 1126 jt := g.jniType(v.Type()) 1127 g.Printf(", %s %s", jt, g.paramName(params, i)) 1128 } 1129 g.Printf(") {\n") 1130 g.Indent() 1131 for i := 0; i < params.Len(); i++ { 1132 name := g.paramName(params, i) 1133 g.genJavaToC(name, params.At(i).Type(), modeTransient) 1134 } 1135 // Constructors always return a mandatory *T and an optional error 1136 if res.Len() == 1 { 1137 g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name()) 1138 } else { 1139 g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name()) 1140 } 1141 for i := 0; i < params.Len(); i++ { 1142 if i > 0 { 1143 g.Printf(", ") 1144 } 1145 g.Printf("_%s", g.paramName(params, i)) 1146 } 1147 g.Printf(");\n") 1148 for i := 0; i < params.Len(); i++ { 1149 g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) 1150 } 1151 // Extract multi returns and handle errors 1152 if res.Len() == 2 { 1153 g.Printf("int32_t refnum = res.r0;\n") 1154 g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained) 1155 g.Printf("go_seq_maybe_throw_exception(env, _err);\n") 1156 } 1157 g.Printf("return refnum;\n") 1158 g.Outdent() 1159 g.Printf("}\n\n") 1160 } 1161 1162 func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) { 1163 if !g.isSigSupported(o.Type()) { 1164 n := o.Name() 1165 if sName != "" { 1166 n = sName + "." + n 1167 } 1168 g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n) 1169 return 1170 } 1171 g.genJNIFuncSignature(o, sName, jm, proxy, isjava) 1172 1173 g.Printf(" {\n") 1174 g.Indent() 1175 g.genJNIFuncBody(o, sName, jm, isjava) 1176 g.Outdent() 1177 g.Printf("}\n\n") 1178 } 1179 1180 func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) { 1181 sig := o.Type().(*types.Signature) 1182 res := sig.Results() 1183 if sName != "" { 1184 g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n") 1185 } 1186 params := sig.Params() 1187 first := 0 1188 if isjava && params.Len() > 0 && params.At(0).Name() == "this" { 1189 // Start after the implicit this argument. 1190 first = 1 1191 g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0)) 1192 } 1193 for i := first; i < params.Len(); i++ { 1194 name := g.paramName(params, i) 1195 g.genJavaToC(name, params.At(i).Type(), modeTransient) 1196 } 1197 resPrefix := "" 1198 if res.Len() > 0 { 1199 if res.Len() == 1 { 1200 g.Printf("%s r0 = ", g.cgoType(res.At(0).Type())) 1201 } else { 1202 resPrefix = "res." 1203 g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name()) 1204 } 1205 } 1206 g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name()) 1207 if sName != "" { 1208 g.Printf("o") 1209 } 1210 // Pass all arguments, including the implicit this argument. 1211 for i := 0; i < params.Len(); i++ { 1212 if i > 0 || sName != "" { 1213 g.Printf(", ") 1214 } 1215 g.Printf("_%s", g.paramName(params, i)) 1216 } 1217 g.Printf(");\n") 1218 for i := first; i < params.Len(); i++ { 1219 g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) 1220 } 1221 for i := 0; i < res.Len(); i++ { 1222 tn := fmt.Sprintf("_r%d", i) 1223 t := res.At(i).Type() 1224 g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained) 1225 } 1226 // Go backwards so that any exception is thrown before 1227 // the return. 1228 for i := res.Len() - 1; i >= 0; i-- { 1229 t := res.At(i).Type() 1230 if !isErrorType(t) { 1231 g.Printf("return _r%d;\n", i) 1232 } else { 1233 g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i) 1234 } 1235 } 1236 } 1237 1238 // genRelease cleans up arguments that weren't copied in genJavaToC. 1239 func (g *JavaGen) genRelease(varName string, t types.Type, mode varMode) { 1240 switch t := t.(type) { 1241 case *types.Basic: 1242 case *types.Slice: 1243 switch e := t.Elem().(type) { 1244 case *types.Basic: 1245 switch e.Kind() { 1246 case types.Uint8: // Byte. 1247 if mode == modeTransient { 1248 g.Printf("go_seq_release_byte_array(env, %s, _%s.ptr);\n", varName, varName) 1249 } 1250 } 1251 } 1252 } 1253 } 1254 1255 func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) { 1256 if !g.isSigSupported(m.Type()) { 1257 g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName) 1258 return 1259 } 1260 sig := m.Type().(*types.Signature) 1261 params := sig.Params() 1262 res := sig.Results() 1263 g.genInterfaceMethodSignature(m, oName, false, g.paramName) 1264 g.Indent() 1265 g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len()) 1266 g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName) 1267 for i := 0; i < params.Len(); i++ { 1268 pn := g.paramName(params, i) 1269 g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient) 1270 } 1271 if res.Len() > 0 && !isErrorType(res.At(0).Type()) { 1272 t := res.At(0).Type() 1273 g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t)) 1274 } else { 1275 g.Printf("(*env)->CallVoidMethod(env, o, ") 1276 } 1277 g.Printf("mid_%s_%s", oName, m.Name()) 1278 for i := 0; i < params.Len(); i++ { 1279 g.Printf(", _%s", g.paramName(params, i)) 1280 } 1281 g.Printf(");\n") 1282 var retName string 1283 if res.Len() > 0 { 1284 t := res.At(0).Type() 1285 if res.Len() == 2 || isErrorType(t) { 1286 g.Printf("jobject exc = go_seq_get_exception(env);\n") 1287 errType := types.Universe.Lookup("error").Type() 1288 g.genJavaToC("exc", errType, modeRetained) 1289 retName = "_exc" 1290 } 1291 if !isErrorType(t) { 1292 if res.Len() == 2 { 1293 g.genCRetClear("res", t, "exc") 1294 } 1295 g.genJavaToC("res", t, modeRetained) 1296 retName = "_res" 1297 } 1298 1299 if res.Len() > 1 { 1300 g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name()) 1301 g.Printf(" _res, _exc\n") 1302 g.Printf("};\n") 1303 retName = "sres" 1304 } 1305 } 1306 g.Printf("go_seq_pop_local_frame(env);\n") 1307 if retName != "" { 1308 g.Printf("return %s;\n", retName) 1309 } 1310 g.Outdent() 1311 g.Printf("}\n\n") 1312 } 1313 1314 func (g *JavaGen) GenH() error { 1315 pkgPath := "" 1316 if g.Pkg != nil { 1317 pkgPath = g.Pkg.Path() 1318 } 1319 g.Printf(hPreamble, g.gobindOpts(), pkgPath, g.className()) 1320 for _, iface := range g.interfaces { 1321 g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name()) 1322 g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name()) 1323 g.Printf("\n") 1324 for _, m := range iface.summary.callable { 1325 if !g.isSigSupported(m.Type()) { 1326 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) 1327 continue 1328 } 1329 g.genInterfaceMethodSignature(m, iface.obj.Name(), true, g.paramName) 1330 g.Printf("\n") 1331 } 1332 } 1333 for _, s := range g.structs { 1334 g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name()) 1335 g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name()) 1336 } 1337 g.Printf("#endif\n") 1338 if len(g.err) > 0 { 1339 return g.err 1340 } 1341 return nil 1342 } 1343 1344 func (g *JavaGen) jniCallType(t types.Type) string { 1345 switch t := t.(type) { 1346 case *types.Basic: 1347 switch t.Kind() { 1348 case types.Bool, types.UntypedBool: 1349 return "Boolean" 1350 case types.Int: 1351 return "Long" 1352 case types.Int8, types.Uint8: // types.Byte 1353 return "Byte" 1354 case types.Int16: 1355 return "Short" 1356 case types.Int32, types.UntypedRune: // types.Rune 1357 return "Int" 1358 case types.Int64, types.UntypedInt: 1359 return "Long" 1360 case types.Float32: 1361 return "Float" 1362 case types.Float64, types.UntypedFloat: 1363 return "Double" 1364 case types.String, types.UntypedString: 1365 return "Object" 1366 default: 1367 g.errorf("unsupported basic type: %s", t) 1368 } 1369 case *types.Slice: 1370 return "Object" 1371 case *types.Pointer: 1372 if _, ok := t.Elem().(*types.Named); ok { 1373 return g.jniCallType(t.Elem()) 1374 } 1375 g.errorf("unsupported pointer to type: %s", t) 1376 case *types.Named: 1377 return "Object" 1378 default: 1379 return "Object" 1380 } 1381 return "TODO" 1382 } 1383 1384 func (g *JavaGen) jniClassSigPrefix(pkg *types.Package) string { 1385 return strings.Replace(g.javaPkgName(pkg), ".", "/", -1) + "/" 1386 } 1387 1388 func (g *JavaGen) jniSigType(T types.Type) string { 1389 if isErrorType(T) { 1390 return "Ljava/lang/Exception;" 1391 } 1392 switch T := T.(type) { 1393 case *types.Basic: 1394 switch T.Kind() { 1395 case types.Bool, types.UntypedBool: 1396 return "Z" 1397 case types.Int: 1398 return "J" 1399 case types.Int8: 1400 return "B" 1401 case types.Int16: 1402 return "S" 1403 case types.Int32, types.UntypedRune: // types.Rune 1404 return "I" 1405 case types.Int64, types.UntypedInt: 1406 return "J" 1407 case types.Uint8: // types.Byte 1408 return "B" 1409 case types.Float32: 1410 return "F" 1411 case types.Float64, types.UntypedFloat: 1412 return "D" 1413 case types.String, types.UntypedString: 1414 return "Ljava/lang/String;" 1415 default: 1416 g.errorf("unsupported basic type: %s", T) 1417 return "TODO" 1418 } 1419 case *types.Slice: 1420 return "[" + g.jniSigType(T.Elem()) 1421 case *types.Pointer: 1422 if _, ok := T.Elem().(*types.Named); ok { 1423 return g.jniSigType(T.Elem()) 1424 } 1425 g.errorf("unsupported pointer to type: %s", T) 1426 case *types.Named: 1427 return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + g.javaTypeName(T.Obj().Name()) + ";" 1428 default: 1429 g.errorf("unsupported jniType: %#+v, %s\n", T, T) 1430 } 1431 return "TODO" 1432 } 1433 1434 func (g *JavaGen) GenC() error { 1435 var pkgName, pkgPath string 1436 if g.Pkg != nil { 1437 pkgName = g.Pkg.Name() 1438 pkgPath = g.Pkg.Path() 1439 } else { 1440 pkgName = "universe" 1441 } 1442 g.Printf(cPreamble, g.gobindOpts(), pkgPath) 1443 g.Printf("#include %q\n", pkgName+".h") 1444 if g.Pkg != nil { 1445 for _, pkg := range g.Pkg.Imports() { 1446 if g.validPkg(pkg) { 1447 g.Printf("#include \"%s.h\"\n", pkg.Name()) 1448 } 1449 } 1450 } 1451 g.Printf("\n") 1452 1453 for _, iface := range g.interfaces { 1454 g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name()) 1455 g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name()) 1456 for _, m := range iface.summary.callable { 1457 if !g.isSigSupported(m.Type()) { 1458 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) 1459 continue 1460 } 1461 g.Printf("static jmethodID mid_%s_%s;\n", iface.obj.Name(), m.Name()) 1462 } 1463 } 1464 for _, s := range g.structs { 1465 g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name()) 1466 g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name()) 1467 } 1468 g.Printf("\n") 1469 g.Printf("JNIEXPORT void JNICALL\n") 1470 g.Printf("Java_%s_%s__1init(JNIEnv *env, jclass _unused) {\n", g.jniPkgName(), java.JNIMangle(g.className())) 1471 g.Indent() 1472 g.Printf("jclass clazz;\n") 1473 for _, s := range g.structs { 1474 if jinf, ok := g.jstructs[s.obj]; ok { 1475 // Leave the class and constructor NULL for Java classes with no 1476 // default constructor. 1477 if !jinf.genNoargCon { 1478 continue 1479 } 1480 } 1481 g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+g.javaTypeName(s.obj.Name())) 1482 g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name()) 1483 g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, s.obj.Name()) 1484 } 1485 for _, iface := range g.interfaces { 1486 pkg := iface.obj.Pkg() 1487 g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+JavaClassName(pkg)+"$proxy"+iface.obj.Name()) 1488 g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name()) 1489 g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, iface.obj.Name()) 1490 if isErrorType(iface.obj.Type()) { 1491 // As a special case, Java Exceptions are passed to Go pretending to implement the Go error interface. 1492 // To complete the illusion, use the Throwable.getMessage method for proxied calls to the error.Error method. 1493 g.Printf("clazz = (*env)->FindClass(env, \"java/lang/Throwable\");\n") 1494 g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n") 1495 continue 1496 } 1497 g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+g.javaTypeName(iface.obj.Name())) 1498 for _, m := range iface.summary.callable { 1499 if !g.isSigSupported(m.Type()) { 1500 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name()) 1501 continue 1502 } 1503 sig := m.Type().(*types.Signature) 1504 res := sig.Results() 1505 retSig := "V" 1506 if res.Len() > 0 { 1507 if t := res.At(0).Type(); !isErrorType(t) { 1508 retSig = g.jniSigType(t) 1509 } 1510 } 1511 var jniParams string 1512 params := sig.Params() 1513 for i := 0; i < params.Len(); i++ { 1514 jniParams += g.jniSigType(params.At(i).Type()) 1515 } 1516 g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n", 1517 iface.obj.Name(), m.Name(), javaNameReplacer(lowerFirst(m.Name())), jniParams, retSig) 1518 } 1519 g.Printf("\n") 1520 } 1521 g.Outdent() 1522 g.Printf("}\n\n") 1523 for _, f := range g.funcs { 1524 g.genJNIFunc(f, "", nil, false, false) 1525 } 1526 for _, s := range g.structs { 1527 sName := s.obj.Name() 1528 cons := g.constructors[s.obj] 1529 jinf := g.jstructs[s.obj] 1530 for _, f := range cons { 1531 g.genJNIConstructor(f, sName) 1532 } 1533 if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) { 1534 g.Printf("JNIEXPORT jint JNICALL\n") 1535 g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__New")) 1536 g.Indent() 1537 g.Printf("return new_%s_%s();\n", g.pkgPrefix, sName) 1538 g.Outdent() 1539 g.Printf("}\n\n") 1540 } 1541 1542 for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) { 1543 var jm *java.Func 1544 if jinf != nil { 1545 jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m)) 1546 } 1547 g.genJNIFunc(m, sName, jm, false, jinf != nil) 1548 } 1549 for _, f := range exportedFields(s.t) { 1550 g.genJNIField(s.obj, f) 1551 } 1552 } 1553 for _, iface := range g.interfaces { 1554 for _, m := range iface.summary.callable { 1555 g.genJNIFunc(m, iface.obj.Name(), nil, true, false) 1556 g.genMethodInterfaceProxy(iface.obj.Name(), m) 1557 } 1558 } 1559 for _, v := range g.vars { 1560 g.genJNIVar(v) 1561 } 1562 if len(g.err) > 0 { 1563 return g.err 1564 } 1565 return nil 1566 } 1567 1568 func (g *JavaGen) GenJava() error { 1569 pkgPath := "" 1570 if g.Pkg != nil { 1571 pkgPath = g.Pkg.Path() 1572 } 1573 g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.className(), g.gobindOpts(), pkgPath) 1574 1575 g.Printf("public abstract class %s {\n", g.className()) 1576 g.Indent() 1577 g.Printf("static {\n") 1578 g.Indent() 1579 g.Printf("Seq.touch(); // for loading the native library\n") 1580 if g.Pkg != nil { 1581 for _, p := range g.Pkg.Imports() { 1582 if g.validPkg(p) { 1583 g.Printf("%s.%s.touch();\n", g.javaPkgName(p), JavaClassName(p)) 1584 } 1585 } 1586 } 1587 g.Printf("_init();\n") 1588 g.Outdent() 1589 g.Printf("}\n\n") 1590 g.Printf("private %s() {} // uninstantiable\n\n", g.className()) 1591 g.Printf("// touch is called from other bound packages to initialize this package\n") 1592 g.Printf("public static void touch() {}\n\n") 1593 g.Printf("private static native void _init();\n\n") 1594 1595 for _, iface := range g.interfaces { 1596 n := iface.obj.Name() 1597 g.Printf("private static final class proxy%s", n) 1598 if isErrorType(iface.obj.Type()) { 1599 g.Printf(" extends Exception") 1600 } 1601 g.Printf(" implements Seq.Proxy, %s {\n", g.javaTypeName(n)) 1602 g.Indent() 1603 g.genProxyImpl("proxy" + n) 1604 g.Printf("proxy%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n) 1605 1606 if isErrorType(iface.obj.Type()) { 1607 g.Printf("@Override public String getMessage() { return error(); }\n\n") 1608 } 1609 for _, m := range iface.summary.callable { 1610 if !g.isSigSupported(m.Type()) { 1611 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name()) 1612 continue 1613 } 1614 g.Printf("public native ") 1615 g.genFuncSignature(m, nil, false) 1616 } 1617 1618 g.Outdent() 1619 g.Printf("}\n") 1620 } 1621 1622 g.Printf("\n") 1623 1624 for _, c := range g.constants { 1625 g.genConst(c) 1626 } 1627 g.Printf("\n") 1628 for _, v := range g.vars { 1629 g.genVar(v) 1630 } 1631 for _, f := range g.funcs { 1632 if !g.isSigSupported(f.Type()) { 1633 g.Printf("// skipped function %s with unsupported parameter or return types\n\n", f.Name()) 1634 continue 1635 } 1636 g.Printf("public static native ") 1637 g.genFuncSignature(f, nil, false) 1638 } 1639 1640 g.Outdent() 1641 g.Printf("}\n") 1642 1643 if len(g.err) > 0 { 1644 return g.err 1645 } 1646 return nil 1647 } 1648 1649 // embeddedJavaClasses returns the possible empty list of Java types embedded 1650 // in the given struct type. 1651 func embeddedJavaClasses(t *types.Struct) []string { 1652 clsSet := make(map[string]struct{}) 1653 var classes []string 1654 for i := 0; i < t.NumFields(); i++ { 1655 f := t.Field(i) 1656 if !f.Exported() { 1657 continue 1658 } 1659 if t := f.Type(); isJavaType(t) { 1660 cls := classNameFor(t) 1661 if _, exists := clsSet[cls]; !exists { 1662 clsSet[cls] = struct{}{} 1663 classes = append(classes, cls) 1664 } 1665 } 1666 } 1667 return classes 1668 } 1669 1670 func classNameFor(t types.Type) string { 1671 obj := t.(*types.Named).Obj() 1672 pkg := obj.Pkg() 1673 return strings.Replace(pkg.Path()[len("Java/"):], "/", ".", -1) + "." + obj.Name() 1674 } 1675 1676 func isJavaType(t types.Type) bool { 1677 return typePkgFirstElem(t) == "Java" 1678 } 1679 1680 const ( 1681 javaPreamble = `// Java class %[1]s.%[2]s is a proxy for talking to a Go program. 1682 // gobind %[3]s %[4]s 1683 // 1684 // File is generated by gobind. Do not edit. 1685 package %[1]s; 1686 1687 import go.Seq; 1688 1689 ` 1690 cPreamble = `// JNI functions for the Go <=> Java bridge. 1691 // gobind %[1]s %[2]s 1692 // 1693 // File is generated by gobind. Do not edit. 1694 1695 #include <android/log.h> 1696 #include <stdint.h> 1697 #include "seq.h" 1698 #include "_cgo_export.h" 1699 ` 1700 1701 hPreamble = `// JNI function headers for the Go <=> Java bridge. 1702 // gobind %[1]s %[2]s 1703 // 1704 // File is generated by gobind. Do not edit. 1705 1706 #ifndef __%[3]s_H__ 1707 #define __%[3]s_H__ 1708 1709 #include <jni.h> 1710 1711 ` 1712 )