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