| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package bind
- import (
- "fmt"
- "path"
- "reflect"
- "strings"
- "unicode"
- "unicode/utf8"
- "golang.org/x/mobile/internal/importers"
- "golang.org/x/mobile/internal/importers/java"
- )
- type (
- // ClassGen generates Go and C stubs for Java classes so import statements
- // on the form
- //
- //
- // import "Java/classpath/to/Class"
- //
- // will work.
- ClassGen struct {
- *Printer
- // JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go
- // package name to create the full Java package name.
- JavaPkg string
- imported map[string]struct{}
- // The list of imported Java classes
- classes []*java.Class
- // The list of Go package paths with Java interfaces inside
- jpkgs []string
- // For each Go package path, the list of Java classes.
- typePkgs map[string][]*java.Class
- // For each Go package path, the Java class with static functions
- // or constants.
- clsPkgs map[string]*java.Class
- // goClsMap is the map of Java class names to Go type names, qualified with package name. Go types
- // that implement Java classes need Super methods and Unwrap methods.
- goClsMap map[string]string
- // goClsImports is the list of imports of user packages that contains the Go types implementing Java
- // classes.
- goClsImports []string
- }
- )
- func (g *ClassGen) isSupported(t *java.Type) bool {
- switch t.Kind {
- case java.Array:
- // TODO: Support all array types
- return t.Elem.Kind == java.Byte
- default:
- return true
- }
- }
- func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool {
- for _, f := range fs.Funcs {
- if g.isFuncSupported(f) {
- return true
- }
- }
- return false
- }
- func (g *ClassGen) isFuncSupported(f *java.Func) bool {
- for _, a := range f.Params {
- if !g.isSupported(a) {
- return false
- }
- }
- if f.Ret != nil {
- return g.isSupported(f.Ret)
- }
- return true
- }
- func (g *ClassGen) goType(t *java.Type, local bool) string {
- if t == nil {
- // interface{} is used for parameters types for overloaded methods
- // where no common ancestor type exists.
- return "interface{}"
- }
- switch t.Kind {
- case java.Int:
- return "int32"
- case java.Boolean:
- return "bool"
- case java.Short:
- return "int16"
- case java.Char:
- return "uint16"
- case java.Byte:
- return "byte"
- case java.Long:
- return "int64"
- case java.Float:
- return "float32"
- case java.Double:
- return "float64"
- case java.String:
- return "string"
- case java.Array:
- return "[]" + g.goType(t.Elem, local)
- case java.Object:
- name := goClsName(t.Class)
- if !local {
- name = "Java." + name
- }
- return name
- default:
- panic("invalid kind")
- }
- }
- // Init initializes the class wrapper generator. Classes is the
- // list of classes to wrap, goClasses is the list of Java classes
- // implemented in Go.
- func (g *ClassGen) Init(classes []*java.Class, goClasses []importers.Struct) {
- g.goClsMap = make(map[string]string)
- impMap := make(map[string]struct{})
- for _, s := range goClasses {
- n := s.Pkg + "." + s.Name
- jn := n
- if g.JavaPkg != "" {
- jn = g.JavaPkg + "." + jn
- }
- g.goClsMap[jn] = n
- if _, exists := impMap[s.PkgPath]; !exists {
- impMap[s.PkgPath] = struct{}{}
- g.goClsImports = append(g.goClsImports, s.PkgPath)
- }
- }
- g.classes = classes
- g.imported = make(map[string]struct{})
- g.typePkgs = make(map[string][]*java.Class)
- g.clsPkgs = make(map[string]*java.Class)
- pkgSet := make(map[string]struct{})
- for _, cls := range classes {
- g.imported[cls.Name] = struct{}{}
- clsPkg := strings.Replace(cls.Name, ".", "/", -1)
- g.clsPkgs[clsPkg] = cls
- typePkg := path.Dir(clsPkg)
- g.typePkgs[typePkg] = append(g.typePkgs[typePkg], cls)
- if _, exists := pkgSet[clsPkg]; !exists {
- pkgSet[clsPkg] = struct{}{}
- g.jpkgs = append(g.jpkgs, clsPkg)
- }
- if _, exists := pkgSet[typePkg]; !exists {
- pkgSet[typePkg] = struct{}{}
- g.jpkgs = append(g.jpkgs, typePkg)
- }
- }
- }
- // Packages return the list of Go packages to be generated.
- func (g *ClassGen) Packages() []string {
- return g.jpkgs
- }
- func (g *ClassGen) GenPackage(idx int) {
- jpkg := g.jpkgs[idx]
- g.Printf(gobindPreamble)
- g.Printf("package %s\n\n", path.Base(jpkg))
- g.Printf("import \"Java\"\n\n")
- g.Printf("const _ = Java.Dummy\n\n")
- for _, cls := range g.typePkgs[jpkg] {
- g.Printf("type %s Java.%s\n", cls.PkgName, goClsName(cls.Name))
- }
- if cls, ok := g.clsPkgs[jpkg]; ok {
- g.Printf("const (\n")
- g.Indent()
- // Constants
- for _, v := range cls.Vars {
- if g.isSupported(v.Type) && v.Constant() {
- g.Printf("%s = %s\n", initialUpper(v.Name), v.Val)
- }
- }
- g.Outdent()
- g.Printf(")\n\n")
- g.Printf("var (\n")
- g.Indent()
- // Functions
- loop:
- for _, fs := range cls.Funcs {
- for _, f := range fs.Funcs {
- if f.Public && g.isFuncSupported(f) {
- g.Printf("%s func", fs.GoName)
- g.genFuncDecl(false, fs)
- g.Printf("\n")
- continue loop
- }
- }
- }
- g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name)
- g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n")
- g.Printf("// not extend or implement %s.\n", cls.Name)
- g.Printf("Cast func(v interface{}) Java.%s\n", goClsName(cls.Name))
- g.Outdent()
- g.Printf(")\n\n")
- }
- }
- func (g *ClassGen) GenGo() {
- g.Printf(classesGoHeader)
- for _, cls := range g.classes {
- pkgName := strings.Replace(cls.Name, ".", "/", -1)
- g.Printf("import %q\n", "Java/"+pkgName)
- }
- for _, imp := range g.goClsImports {
- g.Printf("import %q\n", imp)
- }
- if len(g.classes) > 0 {
- g.Printf("import \"unsafe\"\n\n")
- g.Printf("import \"reflect\"\n\n")
- g.Printf("import \"fmt\"\n\n")
- }
- g.Printf("type proxy interface { Bind_proxy_refnum__() int32 }\n\n")
- g.Printf("// Suppress unused package error\n\n")
- g.Printf("var _ = _seq.FromRefNum\n")
- g.Printf("const _ = Java.Dummy\n\n")
- g.Printf("//export initClasses\n")
- g.Printf("func initClasses() {\n")
- g.Indent()
- g.Printf("C.init_proxies()\n")
- for _, cls := range g.classes {
- g.Printf("init_%s()\n", cls.JNIName)
- }
- g.Outdent()
- g.Printf("}\n\n")
- for _, cls := range g.classes {
- g.genGo(cls)
- }
- }
- func (g *ClassGen) GenH() {
- g.Printf(classesHHeader)
- for _, tn := range []string{"jint", "jboolean", "jshort", "jchar", "jbyte", "jlong", "jfloat", "jdouble", "nstring", "nbyteslice"} {
- g.Printf("typedef struct ret_%s {\n", tn)
- g.Printf(" %s res;\n", tn)
- g.Printf(" jint exc;\n")
- g.Printf("} ret_%s;\n", tn)
- }
- g.Printf("\n")
- for _, cls := range g.classes {
- for _, fs := range cls.AllMethods {
- for _, f := range fs.Funcs {
- if !g.isFuncSupported(f) {
- continue
- }
- g.Printf("extern ")
- g.genCMethodDecl("cproxy", cls.JNIName, f)
- g.Printf(";\n")
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("extern ")
- g.genCMethodDecl("csuper", cls.JNIName, f)
- g.Printf(";\n")
- }
- }
- }
- }
- for _, cls := range g.classes {
- g.genH(cls)
- }
- }
- func (g *ClassGen) GenC() {
- g.Printf(classesCHeader)
- for _, cls := range g.classes {
- g.Printf("static jclass class_%s;\n", cls.JNIName)
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("static jclass sclass_%s;\n", cls.JNIName)
- }
- for _, fs := range cls.Funcs {
- for _, f := range fs.Funcs {
- if !f.Public || !g.isFuncSupported(f) {
- continue
- }
- g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName)
- }
- }
- for _, fs := range cls.AllMethods {
- for _, f := range fs.Funcs {
- if g.isFuncSupported(f) {
- g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName)
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName)
- }
- }
- }
- }
- g.genC(cls)
- }
- g.Printf("\n")
- g.Printf("void init_proxies() {\n")
- g.Indent()
- g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(g.classes))
- g.Printf("jclass clazz;\n")
- for _, cls := range g.classes {
- g.Printf("clazz = go_seq_find_class(%q);\n", strings.Replace(cls.FindName, ".", "/", -1))
- g.Printf("if (clazz != NULL) {\n")
- g.Indent()
- g.Printf("class_%s = (*env)->NewGlobalRef(env, clazz);\n", cls.JNIName)
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName)
- g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName)
- }
- for _, fs := range cls.Funcs {
- for _, f := range fs.Funcs {
- if !f.Public || !g.isFuncSupported(f) {
- continue
- }
- g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName)
- if f.Constructor {
- g.Printf("go_seq_get_method_id(clazz, \"<init>\", %q);\n", f.Desc)
- } else {
- g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc)
- }
- }
- }
- for _, fs := range cls.AllMethods {
- for _, f := range fs.Funcs {
- if g.isFuncSupported(f) {
- g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc)
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc)
- }
- }
- }
- }
- g.Outdent()
- g.Printf("}\n")
- }
- g.Printf("go_seq_pop_local_frame(env);\n")
- g.Outdent()
- g.Printf("}\n\n")
- for _, cls := range g.classes {
- for _, fs := range cls.AllMethods {
- for _, f := range fs.Funcs {
- if !g.isFuncSupported(f) {
- continue
- }
- g.genCMethodDecl("cproxy", cls.JNIName, f)
- g.genCMethodBody(cls, f, false)
- if _, ok := g.goClsMap[cls.Name]; ok {
- g.genCMethodDecl("csuper", cls.JNIName, f)
- g.genCMethodBody(cls, f, true)
- }
- }
- }
- }
- }
- func (g *ClassGen) GenInterfaces() {
- g.Printf(classesPkgHeader)
- for _, cls := range g.classes {
- g.genInterface(cls)
- }
- }
- func (g *ClassGen) genCMethodBody(cls *java.Class, f *java.Func, virtual bool) {
- g.Printf(" {\n")
- g.Indent()
- // Add 1 for the 'this' argument
- g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params)+1)
- g.Printf("// Must be a Java object\n")
- g.Printf("jobject _this = go_seq_from_refnum(env, this, NULL, NULL);\n")
- for i, a := range f.Params {
- g.genCToJava(fmt.Sprintf("a%d", i), a)
- }
- if f.Ret != nil {
- g.Printf("%s res = ", f.Ret.JNIType())
- }
- g.Printf("(*env)->Call")
- if virtual {
- g.Printf("Nonvirtual")
- }
- if f.Ret != nil {
- g.Printf(f.Ret.JNICallType())
- } else {
- g.Printf("Void")
- }
- g.Printf("Method(env, _this, ")
- if virtual {
- g.Printf("sclass_%s, sm_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
- } else {
- g.Printf("m_%s_%s", cls.JNIName, f.JNIName)
- }
- for i := range f.Params {
- g.Printf(", _a%d", i)
- }
- g.Printf(");\n")
- g.Printf("jobject _exc = go_seq_get_exception(env);\n")
- g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
- if f.Ret != nil {
- g.genCRetClear("res", f.Ret, "_exc")
- g.genJavaToC("res", f.Ret)
- }
- g.Printf("go_seq_pop_local_frame(env);\n")
- if f.Ret != nil {
- g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
- g.Printf("return __res;\n")
- } else {
- g.Printf("return _exc_ref;\n")
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- func initialUpper(s string) string {
- if s == "" {
- return ""
- }
- r, n := utf8.DecodeRuneInString(s)
- return string(unicode.ToUpper(r)) + s[n:]
- }
- func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) {
- g.Printf("(")
- for i, a := range fs.Params {
- if i > 0 {
- g.Printf(", ")
- }
- g.Printf("a%d ", i)
- if i == len(fs.Params)-1 && fs.Variadic {
- g.Printf("...")
- }
- g.Printf(g.goType(a, local))
- }
- g.Printf(")")
- if fs.Throws {
- if fs.HasRet {
- g.Printf(" (%s, error)", g.goType(fs.Ret, local))
- } else {
- g.Printf(" error")
- }
- } else if fs.HasRet {
- g.Printf(" %s", g.goType(fs.Ret, local))
- }
- }
- func (g *ClassGen) genC(cls *java.Class) {
- for _, fs := range cls.Funcs {
- for _, f := range fs.Funcs {
- if !f.Public || !g.isFuncSupported(f) {
- continue
- }
- g.genCFuncDecl(cls.JNIName, f)
- g.Printf(" {\n")
- g.Indent()
- g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params))
- for i, a := range f.Params {
- g.genCToJava(fmt.Sprintf("a%d", i), a)
- }
- if f.Constructor {
- g.Printf("jobject res = (*env)->NewObject(env")
- } else if f.Ret != nil {
- g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType())
- } else {
- g.Printf("(*env)->CallStaticVoidMethod(env")
- }
- g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
- for i := range f.Params {
- g.Printf(", _a%d", i)
- }
- g.Printf(");\n")
- g.Printf("jobject _exc = go_seq_get_exception(env);\n")
- g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
- if f.Ret != nil {
- g.genCRetClear("res", f.Ret, "_exc")
- g.genJavaToC("res", f.Ret)
- }
- g.Printf("go_seq_pop_local_frame(env);\n")
- if f.Ret != nil {
- g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
- g.Printf("return __res;\n")
- } else {
- g.Printf("return _exc_ref;\n")
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- }
- }
- func (g *ClassGen) genH(cls *java.Class) {
- for _, fs := range cls.Funcs {
- for _, f := range fs.Funcs {
- if !f.Public || !g.isFuncSupported(f) {
- continue
- }
- g.Printf("extern ")
- g.genCFuncDecl(cls.JNIName, f)
- g.Printf(";\n")
- }
- }
- }
- func (g *ClassGen) genCMethodDecl(prefix, jniName string, f *java.Func) {
- if f.Ret != nil {
- g.Printf("ret_%s", f.Ret.CType())
- } else {
- // Return only the exception, if any
- g.Printf("jint")
- }
- g.Printf(" %s_%s_%s(jint this", prefix, jniName, f.JNIName)
- for i, a := range f.Params {
- g.Printf(", %s a%d", a.CType(), i)
- }
- g.Printf(")")
- }
- func (g *ClassGen) genCFuncDecl(jniName string, f *java.Func) {
- if f.Ret != nil {
- g.Printf("ret_%s", f.Ret.CType())
- } else {
- // Return only the exception, if any
- g.Printf("jint")
- }
- g.Printf(" cproxy_s_%s_%s(", jniName, f.JNIName)
- for i, a := range f.Params {
- if i > 0 {
- g.Printf(", ")
- }
- g.Printf("%s a%d", a.CType(), i)
- }
- g.Printf(")")
- }
- func (g *ClassGen) genGo(cls *java.Class) {
- g.Printf("var class_%s C.jclass\n\n", cls.JNIName)
- g.Printf("func init_%s() {\n", cls.JNIName)
- g.Indent()
- g.Printf("cls := C.CString(%q)\n", strings.Replace(cls.FindName, ".", "/", -1))
- g.Printf("clazz := C.go_seq_find_class(cls)\n")
- g.Printf("C.free(unsafe.Pointer(cls))\n")
- // Before Go 1.11 clazz was a pointer value, an uintptr after.
- g.Printf("if uintptr(clazz) == 0 {\n")
- g.Printf(" return\n")
- g.Printf("}\n")
- g.Printf("class_%s = clazz\n", cls.JNIName)
- for _, fs := range cls.Funcs {
- var supported bool
- for _, f := range fs.Funcs {
- if f.Public && g.isFuncSupported(f) {
- supported = true
- break
- }
- }
- if !supported {
- continue
- }
- g.Printf("%s.%s = func", cls.PkgName, fs.GoName)
- g.genFuncDecl(false, fs)
- g.genFuncBody(cls, fs, "cproxy_s", true)
- }
- g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name))
- g.Indent()
- g.Printf("t := reflect.TypeOf((*proxy_class_%s)(nil))\n", cls.JNIName)
- g.Printf("cv := reflect.ValueOf(v).Convert(t).Interface().(*proxy_class_%s)\n", cls.JNIName)
- g.Printf("ref := C.jint(_seq.ToRefNum(cv))\n")
- g.Printf("if C.go_seq_isinstanceof(ref, class_%s) != 1 {\n", cls.JNIName)
- g.Printf(" panic(fmt.Errorf(\"%%T is not an instance of %%s\", v, %q))\n", cls.Name)
- g.Printf("}\n")
- g.Printf("return cv\n")
- g.Outdent()
- g.Printf("}\n")
- g.Outdent()
- g.Printf("}\n\n")
- g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName)
- g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 {\n", cls.JNIName)
- g.Indent()
- g.Printf("return (*_seq.Ref)(p).Bind_IncNum()\n")
- g.Outdent()
- g.Printf("}\n\n")
- for _, fs := range cls.AllMethods {
- if !g.isFuncSetSupported(fs) {
- continue
- }
- g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName)
- g.genFuncDecl(false, fs)
- g.genFuncBody(cls, fs, "cproxy", false)
- }
- if cls.Throwable {
- g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName)
- g.Printf(" return p.ToString()\n")
- g.Printf("}\n")
- }
- if goName, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("func (p *proxy_class_%s) Super() Java.%s {\n", cls.JNIName, goClsName(cls.Name))
- g.Printf(" return &super_%s{p}\n", cls.JNIName)
- g.Printf("}\n\n")
- g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName)
- g.Printf("func (p *proxy_class_%s) Unwrap() interface{} {\n", cls.JNIName)
- g.Indent()
- g.Printf("goRefnum := C.go_seq_unwrap(C.jint(p.Bind_proxy_refnum__()))\n")
- g.Printf("return _seq.FromRefNum(int32(goRefnum)).Get().(*%s)\n", goName)
- g.Outdent()
- g.Printf("}\n\n")
- for _, fs := range cls.AllMethods {
- if !g.isFuncSetSupported(fs) {
- continue
- }
- g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName)
- g.genFuncDecl(false, fs)
- g.genFuncBody(cls, fs, "csuper", false)
- }
- }
- }
- // genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically,
- // by inspecting the number of arguments (if the FuncSet contains varying parameter counts),
- // and their types.
- func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) {
- maxp := len(fs.Funcs[0].Params)
- minp := maxp
- // sort the function variants into argument sizes.
- buckets := make(map[int][]*java.Func)
- numF := 0
- for _, f := range fs.Funcs {
- if !g.isFuncSupported(f) {
- continue
- }
- numF++
- n := len(f.Params)
- if n < minp {
- minp = n
- } else if n > maxp {
- maxp = n
- }
- buckets[n] = append(buckets[n], f)
- }
- g.Printf(" {\n")
- g.Indent()
- if len(buckets) != 1 {
- // Switch over the number of arguments.
- g.Printf("switch %d + len(a%d) {\n", minp, minp)
- }
- for i := minp; i <= maxp; i++ {
- funcs := buckets[i]
- if len(funcs) == 0 {
- continue
- }
- if len(buckets) != 1 {
- g.Printf("case %d:\n", i)
- g.Indent()
- }
- for _, f := range funcs {
- if len(funcs) > 1 {
- g.Printf("{\n")
- g.Indent()
- }
- var argNames []string
- var preds []string
- for i, a := range f.Params {
- var ct *java.Type
- var argName string
- if i >= minp {
- argName = fmt.Sprintf("a%d[%d]", minp, i-minp)
- ct = fs.Params[minp]
- } else {
- argName = fmt.Sprintf("a%d", i)
- ct = fs.Params[i]
- }
- if !reflect.DeepEqual(ct, a) {
- g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false))
- argName = fmt.Sprintf("_a%d", i)
- preds = append(preds, fmt.Sprintf("ok%d", i))
- }
- argNames = append(argNames, argName)
- }
- if len(preds) > 0 {
- g.Printf("if %s {\n", strings.Join(preds, " && "))
- g.Indent()
- }
- for i, a := range f.Params {
- g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient)
- }
- g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName)
- if !static {
- g.Printf("C.jint(p.Bind_proxy_refnum__())")
- }
- for i := range f.Params {
- if !static || i > 0 {
- g.Printf(", ")
- }
- g.Printf("__a%d", i)
- }
- g.Printf(")\n")
- g.genFuncRet(fs, f, numF > 1)
- if len(preds) > 0 {
- g.Outdent()
- g.Printf("}\n")
- }
- if len(funcs) > 1 {
- g.Outdent()
- g.Printf("}\n")
- }
- }
- if len(buckets) != 1 {
- g.Outdent()
- }
- }
- if len(buckets) != 1 {
- g.Printf("}\n")
- }
- if numF > 1 {
- g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name)
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func, mustReturn bool) {
- if f.Ret != nil {
- g.genRead("_res", "res.res", f.Ret, modeRetained)
- g.genRefRead("_exc", "res.exc", "error", "proxy_error", true)
- } else {
- g.genRefRead("_exc", "res", "error", "proxy_error", true)
- }
- if !fs.Throws {
- g.Printf("if (_exc != nil) { panic(_exc) }\n")
- if fs.HasRet {
- if f.Ret != nil {
- g.Printf("return _res\n")
- } else {
- // The variant doesn't return a value, but the common
- // signature does. Use nil as a placeholder return value.
- g.Printf("return nil\n")
- }
- } else if mustReturn {
- // If there are overloaded variants, return here to avoid the fallback
- // panic generated in genFuncBody.
- g.Printf("return\n")
- }
- } else {
- if fs.HasRet {
- if f.Ret != nil {
- g.Printf("return _res, _exc\n")
- } else {
- // As above, use a nil placeholder return value.
- g.Printf("return nil, _exc\n")
- }
- } else {
- g.Printf("return _exc\n")
- }
- }
- }
- func (g *ClassGen) genRead(to, from string, t *java.Type, mode varMode) {
- switch t.Kind {
- case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
- g.Printf("%s := %s(%s)\n", to, g.goType(t, false), from)
- case java.Boolean:
- g.Printf("%s := %s != C.JNI_FALSE\n", to, from)
- case java.String:
- g.Printf("%s := decodeString(%s)\n", to, from)
- case java.Array:
- if t.Elem.Kind != java.Byte {
- panic("unsupported array type")
- }
- g.Printf("%s := toSlice(%s, %v)\n", to, from, mode == modeRetained)
- case java.Object:
- _, hasProxy := g.imported[t.Class]
- g.genRefRead(to, from, g.goType(t, false), "proxy_class_"+flattenName(t.Class), hasProxy)
- default:
- panic("invalid kind")
- }
- }
- func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasProxy bool) {
- g.Printf("var %s %s\n", to, intfName)
- g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", to, from)
- g.Printf("if %s_ref != nil {\n", to)
- g.Printf(" if %s < 0 { // go object\n", from)
- g.Printf(" %s = %s_ref.Get().(%s)\n", to, to, intfName)
- g.Printf(" } else { // foreign object\n")
- if hasProxy {
- g.Printf(" %s = (*%s)(%s_ref)\n", to, proxyName, to)
- } else {
- g.Printf(" %s = %s_ref\n", to, to)
- }
- g.Printf(" }\n")
- g.Printf("}\n")
- }
- func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) {
- switch t.Kind {
- case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
- g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v)
- case java.Boolean:
- g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst)
- g.Printf("if %s {\n", v)
- g.Printf(" %s = C.jboolean(C.JNI_TRUE)\n", dst)
- g.Printf("}\n")
- case java.String:
- g.Printf("%s := encodeString(%s)\n", dst, v)
- case java.Array:
- if t.Elem.Kind != java.Byte {
- panic("unsupported array type")
- }
- g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained)
- case java.Object:
- g.Printf("var %s C.jint = _seq.NullRefNum\n", dst)
- g.Printf("if %s != nil {\n", v)
- g.Printf(" %s = C.jint(_seq.ToRefNum(%s))\n", dst, v)
- g.Printf("}\n")
- default:
- panic("invalid kind")
- }
- }
- // genCRetClear clears the result value from a JNI call if an exception was
- // raised.
- func (g *ClassGen) genCRetClear(v string, t *java.Type, exc string) {
- g.Printf("if (%s != NULL) {\n", exc)
- g.Indent()
- switch t.Kind {
- case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
- g.Printf("%s = 0;\n", v)
- default:
- // Assume a nullable type. It will break if we missed a type.
- g.Printf("%s = NULL;\n", v)
- }
- g.Outdent()
- g.Printf("}\n")
- }
- func (g *ClassGen) genJavaToC(v string, t *java.Type) {
- switch t.Kind {
- case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
- g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
- case java.String:
- g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", v, v)
- case java.Array:
- if t.Elem.Kind != java.Byte {
- panic("unsupported array type")
- }
- g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, 1);\n", v, v)
- case java.Object:
- g.Printf("jint _%s = go_seq_to_refnum(env, %s);\n", v, v)
- default:
- panic("invalid kind")
- }
- }
- func (g *ClassGen) genCToJava(v string, t *java.Type) {
- switch t.Kind {
- case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double, java.Boolean:
- g.Printf("%s _%s = %s;\n", t.JNIType(), v, v)
- case java.String:
- g.Printf("jstring _%s = go_seq_to_java_string(env, %s);\n", v, v)
- case java.Array:
- if t.Elem.Kind != java.Byte {
- panic("unsupported array type")
- }
- g.Printf("jbyteArray _%s = go_seq_to_java_bytearray(env, %s, 0);\n", v, v)
- case java.Object:
- g.Printf("jobject _%s = go_seq_from_refnum(env, %s, NULL, NULL);\n", v, v)
- default:
- panic("invalid kind")
- }
- }
- func goClsName(n string) string {
- return initialUpper(strings.Replace(n, ".", "_", -1))
- }
- func (g *ClassGen) genInterface(cls *java.Class) {
- g.Printf("type %s interface {\n", goClsName(cls.Name))
- g.Indent()
- // Methods
- for _, fs := range cls.AllMethods {
- if !g.isFuncSetSupported(fs) {
- continue
- }
- g.Printf(fs.GoName)
- g.genFuncDecl(true, fs)
- g.Printf("\n")
- }
- if goName, ok := g.goClsMap[cls.Name]; ok {
- g.Printf("Super() %s\n", goClsName(cls.Name))
- g.Printf("// Unwrap returns the Go object this Java instance\n")
- g.Printf("// is wrapping.\n")
- g.Printf("// The return value is a %s, but the delclared type is\n", goName)
- g.Printf("// interface{} to avoid import cycles.\n")
- g.Printf("Unwrap() interface{}\n")
- }
- if cls.Throwable {
- g.Printf("Error() string\n")
- }
- g.Outdent()
- g.Printf("}\n\n")
- }
- // Flatten java class names. "java.package.Class$Inner" is converted to
- // "java_package_Class_Inner"
- func flattenName(n string) string {
- return strings.Replace(strings.Replace(n, ".", "_", -1), "$", "_", -1)
- }
- var (
- classesPkgHeader = gobindPreamble + `
- package Java
- // Used to silence this package not used errors
- const Dummy = 0
- `
- classesCHeader = gobindPreamble + `
- #include <jni.h>
- #include "seq.h"
- #include "classes.h"
- `
- classesHHeader = gobindPreamble + `
- #include <jni.h>
- #include "seq.h"
- extern void init_proxies();
- `
- javaImplHeader = gobindPreamble
- classesGoHeader = gobindPreamble + `
- package main
- /*
- #include <stdlib.h> // for free()
- #include <jni.h>
- #include "seq.h"
- #include "classes.h"
- */
- import "C"
- import (
- "Java"
- _seq "golang.org/x/mobile/bind/seq"
- )
- `
- )
|