github.com/SkycoinProject/gomobile@v0.0.0-20190312151609-d3739f865fa6/bind/genclasses.go (about)

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