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