diff --git a/bind/bind.go b/bind/bind.go index 2f84d50..2990e0c 100644 --- a/bind/bind.go +++ b/bind/bind.go @@ -20,22 +20,48 @@ import ( "io" ) +type fileType int + +const ( + Java fileType = iota + JavaC + JavaH + + ObjcM + ObjcH + ObjcGoH +) + // GenJava generates a Java API from a Go package. -func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package, javaPkg string) error { +func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package, javaPkg string, ft fileType) error { if javaPkg == "" { javaPkg = javaPkgName(pkg.Name()) } buf := new(bytes.Buffer) g := &javaGen{ - printer: &printer{buf: buf, indentEach: []byte(" ")}, - fset: fset, - pkg: pkg, javaPkg: javaPkg, + generator: &generator{ + printer: &printer{buf: buf, indentEach: []byte(" ")}, + fset: fset, + pkg: pkg, + }, } - if err := g.gen(); err != nil { + g.init() + var err error + switch ft { + case Java: + err = g.genJava() + case JavaC: + err = g.genC() + case JavaH: + err = g.genH() + default: + panic("invalid fileType") + } + if err != nil { return err } - _, err := io.Copy(w, buf) + _, err = io.Copy(w, buf) return err } @@ -43,10 +69,13 @@ func GenJava(w io.Writer, fset *token.FileSet, pkg *types.Package, javaPkg strin func GenGo(w io.Writer, fset *token.FileSet, pkg *types.Package) error { buf := new(bytes.Buffer) g := &goGen{ - printer: &printer{buf: buf, indentEach: []byte("\t")}, - fset: fset, - pkg: pkg, + &generator{ + printer: &printer{buf: buf, indentEach: []byte("\t")}, + fset: fset, + pkg: pkg, + }, } + g.init() if err := g.gen(); err != nil { return err } @@ -61,23 +90,31 @@ func GenGo(w io.Writer, fset *token.FileSet, pkg *types.Package) error { } // GenObjc generates the Objective-C API from a Go package. -func GenObjc(w io.Writer, fset *token.FileSet, pkg *types.Package, prefix string, isHeader bool) error { +func GenObjc(w io.Writer, fset *token.FileSet, pkg *types.Package, prefix string, ft fileType) error { if prefix == "" { prefix = "Go" } buf := new(bytes.Buffer) g := &objcGen{ - printer: &printer{buf: buf, indentEach: []byte("\t")}, - fset: fset, - pkg: pkg, - prefix: prefix, + generator: &generator{ + printer: &printer{buf: buf, indentEach: []byte("\t")}, + fset: fset, + pkg: pkg, + }, + prefix: prefix, } + g.init() var err error - if isHeader { + switch ft { + case ObjcH: err = g.genH() - } else { + case ObjcM: err = g.genM() + case ObjcGoH: + err = g.genGoH() + default: + panic("invalid fileType") } if err != nil { return err diff --git a/bind/bind_test.go b/bind/bind_test.go index eb6c52f..2a9c480 100644 --- a/bind/bind_test.go +++ b/bind/bind_test.go @@ -89,17 +89,18 @@ func writeTempFile(t *testing.T, name string, contents []byte) string { } func TestGenObjc(t *testing.T) { - var suffixes = map[bool]string{ - true: ".objc.h.golden", - false: ".objc.m.golden", + var suffixes = map[fileType]string{ + ObjcH: ".objc.h.golden", + ObjcM: ".objc.m.golden", + ObjcGoH: ".objc.go.h.golden", } for _, filename := range tests { pkg := typeCheck(t, filename) - for isHeader, suffix := range suffixes { + for typ, suffix := range suffixes { var buf bytes.Buffer - if err := GenObjc(&buf, fset, pkg, "", isHeader); err != nil { + if err := GenObjc(&buf, fset, pkg, "", typ); err != nil { t.Errorf("%s: %v", filename, err) continue } @@ -121,26 +122,34 @@ func TestGenObjc(t *testing.T) { } func TestGenJava(t *testing.T) { + var suffixes = map[fileType]string{ + Java: ".java.golden", + JavaC: ".java.c.golden", + JavaH: ".java.h.golden", + } + for _, filename := range tests { - var buf bytes.Buffer pkg := typeCheck(t, filename) - if err := GenJava(&buf, fset, pkg, ""); err != nil { - t.Errorf("%s: %v", filename, err) - continue - } - out := writeTempFile(t, "java", buf.Bytes()) - defer os.Remove(out) - golden := filename[:len(filename)-len(".go")] + ".java.golden" - if diffstr := diff(golden, out); diffstr != "" { - t.Errorf("%s: does not match Java golden:\n%s", filename, diffstr) - - if *updateFlag { - t.Logf("Updating %s...", golden) - if err := exec.Command("/bin/cp", out, golden).Run(); err != nil { - t.Errorf("Update failed: %s", err) - } + for typ, suffix := range suffixes { + var buf bytes.Buffer + if err := GenJava(&buf, fset, pkg, "", typ); err != nil { + t.Errorf("%s: %v", filename, err) + continue } + out := writeTempFile(t, "generated"+suffix, buf.Bytes()) + defer os.Remove(out) + golden := filename[:len(filename)-len(".go")] + suffix + if diffstr := diff(golden, out); diffstr != "" { + t.Errorf("%s: does not match Java golden:\n%s", filename, diffstr) + if *updateFlag { + t.Logf("Updating %s...", golden) + if err := exec.Command("/bin/cp", out, golden).Run(); err != nil { + t.Errorf("Update failed: %s", err) + } + } + + } } } } @@ -180,15 +189,27 @@ func TestCustomPrefix(t *testing.T) { }{ { "testdata/customprefix.java.golden", - func(w io.Writer) error { return GenJava(w, fset, pkg, "com.example") }, + func(w io.Writer) error { return GenJava(w, fset, pkg, "com.example", Java) }, + }, + { + "testdata/customprefix.java.h.golden", + func(w io.Writer) error { return GenJava(w, fset, pkg, "com.example", JavaH) }, + }, + { + "testdata/customprefix.java.c.golden", + func(w io.Writer) error { return GenJava(w, fset, pkg, "com.example", JavaC) }, + }, + { + "testdata/customprefix.objc.go.h.golden", + func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", ObjcGoH) }, }, { "testdata/customprefix.objc.h.golden", - func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", isHeader) }, + func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", ObjcH) }, }, { "testdata/customprefix.objc.m.golden", - func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", !isHeader) }, + func(w io.Writer) error { return GenObjc(w, fset, pkg, "EX", ObjcM) }, }, } diff --git a/bind/gen.go b/bind/gen.go new file mode 100644 index 0000000..6d4cb4f --- /dev/null +++ b/bind/gen.go @@ -0,0 +1,247 @@ +// Copyright 2015 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 ( + "bytes" + "fmt" + "go/token" + "go/types" + "io" + "regexp" +) + +type ( + ErrorList []error + + // varMode describes the lifetime of an argument or + // return value. Modes are used to guide the conversion + // of string and byte slice values accross the language + // barrier. The same conversion mode must be used for + // both the conversion before a foreign call and the + // corresponding conversion after the call. + // See the mode* constants for a description of + // each mode. + varMode int +) + +const ( + // modeTransient are for function arguments that + // are not used after the function returns. + // Transient strings and byte slices don't need copying + // when passed accross the language barrier. + modeTransient varMode = iota + // modeRetained are for function arguments that are + // used after the function returns. Retained strings + // don't need an intermediate copy, while byte slices do. + modeRetained + // modeReturned are for values that are returned to the + // caller of a function. Returned values are always copied. + modeReturned +) + +func (m varMode) copyString() bool { + return m == modeReturned +} + +func (m varMode) copySlice() bool { + return m == modeReturned || m == modeRetained +} + +func (list ErrorList) Error() string { + buf := new(bytes.Buffer) + for i, err := range list { + if i > 0 { + buf.WriteRune('\n') + } + io.WriteString(buf, err.Error()) + } + return buf.String() +} + +type generator struct { + *printer + fset *token.FileSet + pkg *types.Package + err ErrorList + + // fields set by init. + pkgName string + // pkgPrefix is a prefix for disambiguating + // function names for binding multiple packages + pkgPrefix string + funcs []*types.Func + constants []*types.Const + vars []*types.Var + + interfaces []interfaceInfo + structs []structInfo + otherNames []*types.TypeName +} + +func (g *generator) init() { + g.pkgName = g.pkg.Name() + // TODO(elias.naur): Avoid (and test) name clashes from multiple packages + // with the same name. Perhaps use the index from the order the package is + // generated. + g.pkgPrefix = g.pkgName + + scope := g.pkg.Scope() + hasExported := false + for _, name := range scope.Names() { + obj := scope.Lookup(name) + if !obj.Exported() { + continue + } + hasExported = true + switch obj := obj.(type) { + case *types.Func: + if isCallable(obj) { + g.funcs = append(g.funcs, obj) + } + case *types.TypeName: + named := obj.Type().(*types.Named) + switch t := named.Underlying().(type) { + case *types.Struct: + g.structs = append(g.structs, structInfo{obj, t}) + case *types.Interface: + g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)}) + default: + g.otherNames = append(g.otherNames, obj) + } + case *types.Const: + if _, ok := obj.Type().(*types.Basic); !ok { + g.errorf("unsupported exported const for %s: %T", obj.Name(), obj) + continue + } + g.constants = append(g.constants, obj) + case *types.Var: + g.vars = append(g.vars, obj) + default: + g.errorf("unsupported exported type for %s: %T", obj.Name(), obj) + } + } + if !hasExported { + g.errorf("no exported names in the package %q", g.pkg.Path()) + } +} + +func (_ *generator) toCFlag(v bool) int { + if v { + return 1 + } + return 0 +} + +func (g *generator) errorf(format string, args ...interface{}) { + g.err = append(g.err, fmt.Errorf(format, args...)) +} + +// cgoType returns the name of a Cgo type suitable for converting a value of +// the given type. +func (g *generator) cgoType(t types.Type) string { + if isErrorType(t) { + return g.cgoType(types.Typ[types.String]) + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.Bool, types.UntypedBool: + return "char" + case types.Int: + return "nint" + case types.Int8: + return "int8_t" + case types.Int16: + return "int16_t" + case types.Int32, types.UntypedRune: // types.Rune + return "int32_t" + case types.Int64, types.UntypedInt: + return "int64_t" + case types.Uint8: // types.Byte + return "uint8_t" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "float" + case types.Float64, types.UntypedFloat: + return "double" + case types.String: + return "nstring" + default: + panic(fmt.Sprintf("unsupported basic type: %s", t)) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + return "nbyteslice" + default: + panic(fmt.Sprintf("unsupported slice type: %s", t)) + } + default: + panic(fmt.Sprintf("unsupported slice type: %s", t)) + } + case *types.Pointer: + if _, ok := t.Elem().(*types.Named); ok { + return g.cgoType(t.Elem()) + } + panic(fmt.Sprintf("unsupported pointer to type: %s", t)) + case *types.Named: + return "int32_t" + default: + panic(fmt.Sprintf("unsupported type: %s", t)) + } +} + +func (g *generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool) { + sig := m.Type().(*types.Signature) + params := sig.Params() + res := sig.Results() + + if res.Len() == 0 { + g.Printf("void ") + } else { + if res.Len() == 1 { + g.Printf("%s ", g.cgoType(res.At(0).Type())) + } else { + if header { + g.Printf("typedef struct cproxy%s_%s_%s_return {\n", g.pkgPrefix, iName, m.Name()) + g.Indent() + for i := 0; i < res.Len(); i++ { + t := res.At(i).Type() + g.Printf("%s r%d;\n", g.cgoType(t), i) + } + g.Outdent() + g.Printf("} cproxy%s_%s_%s_return;\n", g.pkgPrefix, iName, m.Name()) + } + g.Printf("struct cproxy%s_%s_%s_return ", g.pkgPrefix, iName, m.Name()) + } + } + g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name()) + for i := 0; i < params.Len(); i++ { + t := params.At(i).Type() + g.Printf(", %s %s", g.cgoType(t), paramName(params, i)) + } + g.Printf(")") + if header { + g.Printf(";\n") + } else { + g.Printf(" {\n") + } +} + +var paramRE = regexp.MustCompile(`^p[0-9]*$`) + +// paramName replaces incompatible name with a p0-pN name. +// Missing names, or existing names of the form p[0-9] are incompatible. +// TODO(crawshaw): Replace invalid unicode names. +func paramName(params *types.Tuple, pos int) string { + name := params.At(pos).Name() + if name == "" || name[0] == '_' || paramRE.MatchString(name) { + name = fmt.Sprintf("p%d", pos) + } + return name +} diff --git a/bind/gengo.go b/bind/gengo.go index d4eebc8..5a85e92 100644 --- a/bind/gengo.go +++ b/bind/gengo.go @@ -6,46 +6,48 @@ package bind import ( "fmt" - "go/token" "go/types" "strings" ) type goGen struct { - *printer - fset *token.FileSet - pkg *types.Package - err ErrorList + *generator } -func (g *goGen) errorf(format string, args ...interface{}) { - g.err = append(g.err, fmt.Errorf(format, args...)) -} - -const goPreamble = `// Package go_%s is an autogenerated binder stub for package %s. -// gobind -lang=go %s +const ( + goPreamble = `// Package gomobile_bind is an autogenerated binder stub for package %[1]s. +// gobind -lang=go %[2]s // // File is generated by gobind. Do not edit. -package go_%s +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "%[1]s.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" - %q + %[2]q ) -` +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum -func (g *goGen) genPreamble() { - n := g.pkg.Name() - g.Printf(goPreamble, n, n, g.pkg.Path(), n, g.pkg.Path()) -} +` +) func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { sig := o.Type().(*types.Signature) params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) - g.genRead("param_"+paramName(params, i), "in", p.Type()) + pn := "param_" + paramName(params, i) + g.genRead("_"+pn, pn, p.Type(), modeTransient) } res := sig.Results() @@ -53,20 +55,14 @@ func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { g.errorf("functions and methods must return either zero or one values, and optionally an error") return } - returnsValue := false - returnsError := false - if res.Len() == 1 { - if isErrorType(res.At(0).Type()) { - returnsError = true - g.Printf("err := ") - } else { - returnsValue = true - g.Printf("res := ") + if res.Len() > 0 { + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("res_%d", i) } - } else if res.Len() == 2 { - returnsValue = true - returnsError = true - g.Printf("res, err := ") + g.Printf(" := ") } g.Printf("%s.%s(", selectorLHS, o.Name()) @@ -74,56 +70,128 @@ func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { if i > 0 { g.Printf(", ") } - g.Printf("param_%s", paramName(params, i)) + g.Printf("_param_%s", paramName(params, i)) } g.Printf(")\n") - if returnsValue { - g.genWrite("res", "out", res.At(0).Type()) + for i := 0; i < res.Len(); i++ { + pn := fmt.Sprintf("res_%d", i) + g.genWrite("_"+pn, pn, res.At(i).Type(), modeReturned) } - if returnsError { - g.genWrite("err", "out", res.At(res.Len()-1).Type()) + if res.Len() > 0 { + g.Printf("return ") + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("_res_%d", i) + } + g.Printf("\n") } } -func (g *goGen) genWrite(valName, seqName string, T types.Type) { - if isErrorType(T) { - g.Printf("if %s == nil {\n", valName) - g.Printf(" %s.WriteString(\"\");\n", seqName) +func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { + if isErrorType(t) { + g.Printf("var %s_str string\n", toVar) + g.Printf("if %s == nil {\n", fromVar) + g.Printf(" %s_str = \"\"\n", toVar) g.Printf("} else {\n") - g.Printf(" %s.WriteString(%s.Error());\n", seqName, valName) + g.Printf(" %s_str = %s.Error()\n", toVar, fromVar) g.Printf("}\n") + g.genWrite(toVar, toVar+"_str", types.Typ[types.String], mode) return } - switch T := T.(type) { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("%s := encodeString(%s, %v)\n", toVar, fromVar, mode.copyString()) + case types.Bool: + g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t)) + g.Printf("if %s { %s = 1 }\n", fromVar, toVar) + default: + g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode.copySlice()) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator - switch T := T.Elem().(type) { + switch t := t.Elem().(type) { case *types.Named: - obj := T.Obj() + obj := t.Obj() if obj.Pkg() != g.pkg { - g.errorf("type %s not defined in %s", T, g.pkg) + g.errorf("type %s not defined in %s", t, g.pkg) return } - g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) + g.genToRefNum(toVar, fromVar) default: - g.errorf("unsupported type %s", T) + g.errorf("unsupported type %s", t) } case *types.Named: - switch u := T.Underlying().(type) { + switch u := t.Underlying().(type) { case *types.Interface, *types.Pointer: - g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) + g.genToRefNum(toVar, fromVar) default: - g.errorf("unsupported, direct named type %s: %s", T, u) + g.errorf("unsupported, direct named type %s: %s", t, u) } default: - g.Printf("%s.Write%s(%s);\n", seqName, seqType(T), valName) + g.errorf("unsupported type %s", t) } } +// genToRefNum generates Go code for converting a variable to its refnum. +// Note that the nil-check cannot be lifted into seq.ToRefNum, because a nil +// struct pointer does not convert to a nil interface. +func (g *goGen) genToRefNum(toVar, fromVar string) { + g.Printf("var %s C.int32_t = _seq.NullRefNum\n", toVar) + g.Printf("if %s != nil {\n", fromVar) + g.Printf(" %s = C.int32_t(_seq.ToRefNum(%s))\n", toVar, fromVar) + g.Printf("}\n") +} + +func (g *goGen) genFuncSignature(o *types.Func, objName string) { + g.Printf("//export proxy%s_%s_%s\n", g.pkgPrefix, objName, o.Name()) + g.Printf("func proxy%s_%s_%s(", g.pkgPrefix, objName, o.Name()) + if objName != "" { + g.Printf("refnum C.int32_t") + } + sig := o.Type().(*types.Signature) + params := sig.Params() + for i := 0; i < params.Len(); i++ { + if objName != "" || i > 0 { + g.Printf(", ") + } + p := params.At(i) + g.Printf("param_%s C.%s", paramName(params, i), g.cgoType(p.Type())) + } + g.Printf(") ") + res := sig.Results() + if res.Len() > 0 { + g.Printf("(") + for i := 0; i < res.Len(); i++ { + if i > 0 { + g.Printf(", ") + } + g.Printf("C.%s", g.cgoType(res.At(i).Type())) + } + g.Printf(") ") + } + g.Printf("{\n") +} + func (g *goGen) genFunc(o *types.Func) { - g.Printf("func proxy_%s(out, in *_seq.Buffer) {\n", o.Name()) + g.genFuncSignature(o, "") g.Indent() g.genFuncBody(o, g.pkg.Name()) g.Outdent() @@ -134,62 +202,38 @@ func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) { fields := exportedFields(T) methods := exportedMethodSet(types.NewPointer(obj.Type())) - g.Printf("const (\n") - g.Indent() - g.Printf("proxy%s_Descriptor = \"go.%s.%s\"\n", obj.Name(), g.pkg.Name(), obj.Name()) - for i, f := range fields { - g.Printf("proxy%s_%s_Get_Code = 0x%x0f\n", obj.Name(), f.Name(), i) - g.Printf("proxy%s_%s_Set_Code = 0x%x1f\n", obj.Name(), f.Name(), i) - } - for i, m := range methods { - g.Printf("proxy%s_%s_Code = 0x%x0c\n", obj.Name(), m.Name(), i) - } - g.Outdent() - g.Printf(")\n\n") - g.Printf("type proxy%s _seq.Ref\n\n", obj.Name()) for _, f := range fields { - g.Printf("func proxy%s_%s_Set(out, in *_seq.Buffer) {\n", obj.Name(), f.Name()) + g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name()) + g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) g.Indent() - g.Printf("ref := in.ReadRef()\n") - g.genRead("v", "in", f.Type()) - g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name(), f.Name()) + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") + g.genRead("_v", "v", f.Type(), modeRetained) + g.Printf("ref.Get().(*%s.%s).%s = _v\n", g.pkg.Name(), obj.Name(), f.Name()) g.Outdent() g.Printf("}\n\n") - g.Printf("func proxy%s_%s_Get(out, in *_seq.Buffer) {\n", obj.Name(), f.Name()) + g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name()) + g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type())) g.Indent() - g.Printf("ref := in.ReadRef()\n") + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(), f.Name()) - g.genWrite("v", "out", f.Type()) + g.genWrite("_v", "v", f.Type(), modeReturned) + g.Printf("return _v\n") g.Outdent() g.Printf("}\n\n") } for _, m := range methods { - g.Printf("func proxy%s_%s(out, in *_seq.Buffer) {\n", obj.Name(), m.Name()) + g.genFuncSignature(m, obj.Name()) g.Indent() - g.Printf("ref := in.ReadRef()\n") + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(*%s.%s)\n", g.pkg.Name(), obj.Name()) g.genFuncBody(m, "v") g.Outdent() g.Printf("}\n\n") } - - g.Printf("func init() {\n") - g.Indent() - for _, f := range fields { - n := f.Name() - g.Printf("_seq.Register(proxy%s_Descriptor, proxy%s_%s_Set_Code, proxy%s_%s_Set)\n", obj.Name(), obj.Name(), n, obj.Name(), n) - g.Printf("_seq.Register(proxy%s_Descriptor, proxy%s_%s_Get_Code, proxy%s_%s_Get)\n", obj.Name(), obj.Name(), n, obj.Name(), n) - } - for _, m := range methods { - n := m.Name() - g.Printf("_seq.Register(proxy%s_Descriptor, proxy%s_%s_Code, proxy%s_%s)\n", obj.Name(), obj.Name(), n, obj.Name(), n) - } - g.Outdent() - g.Printf("}\n\n") } func (g *goGen) genVar(o *types.Var) { @@ -199,61 +243,42 @@ func (g *goGen) genVar(o *types.Var) { // var I int // - // func var_setI(out, in *_seq.Buffer) - g.Printf("func var_set%s(out, in *_seq.Buffer) {\n", o.Name()) + // func var_setI(v int) + g.Printf("//export var_set%s_%s\n", g.pkgPrefix, o.Name()) + g.Printf("func var_set%s_%s(v C.%s) {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) g.Indent() - g.genRead("v", "in", o.Type()) - g.Printf("%s = v\n", v) + g.genRead("_v", "v", o.Type(), modeRetained) + g.Printf("%s = _v\n", v) g.Outdent() g.Printf("}\n") - // func var_getI(out, in *_seq.Buffer) - g.Printf("func var_get%s(out, in *_seq.Buffer) {\n", o.Name()) + // func var_getI() int + g.Printf("//export var_get%s_%s\n", g.pkgPrefix, o.Name()) + g.Printf("func var_get%s_%s() C.%s {\n", g.pkgPrefix, o.Name(), g.cgoType(o.Type())) g.Indent() - g.genWrite(v, "out", o.Type()) + g.Printf("v := %s\n", v) + g.genWrite("_v", "v", o.Type(), modeReturned) + g.Printf("return _v\n") g.Outdent() g.Printf("}\n") } func (g *goGen) genInterface(obj *types.TypeName) { iface := obj.Type().(*types.Named).Underlying().(*types.Interface) - ifaceDesc := fmt.Sprintf("go.%s.%s", g.pkg.Name(), obj.Name()) summary := makeIfaceSummary(iface) - // Descriptor and code for interface methods. - g.Printf("const (\n") - g.Indent() - g.Printf("proxy%s_Descriptor = %q\n", obj.Name(), ifaceDesc) - for i, m := range summary.callable { - g.Printf("proxy%s_%s_Code = 0x%x0a\n", obj.Name(), m.Name(), i+1) - } - g.Outdent() - g.Printf(")\n\n") - // Define the entry points. for _, m := range summary.callable { - g.Printf("func proxy%s_%s(out, in *_seq.Buffer) {\n", obj.Name(), m.Name()) + g.genFuncSignature(m, obj.Name()) g.Indent() - g.Printf("ref := in.ReadRef()\n") + g.Printf("ref := _seq.FromRefNum(int32(refnum))\n") g.Printf("v := ref.Get().(%s.%s)\n", g.pkg.Name(), obj.Name()) g.genFuncBody(m, "v") g.Outdent() g.Printf("}\n\n") } - // Register the method entry points. - if len(summary.callable) > 0 { - g.Printf("func init() {\n") - g.Indent() - for _, m := range summary.callable { - g.Printf("_seq.Register(proxy%s_Descriptor, proxy%s_%s_Code, proxy%s_%s)\n", - obj.Name(), obj.Name(), m.Name(), obj.Name(), m.Name()) - } - g.Outdent() - g.Printf("}\n\n") - } - // Define a proxy interface. if !summary.implementable { // The interface defines an unexported method or a method that @@ -261,10 +286,9 @@ func (g *goGen) genInterface(obj *types.TypeName) { // for such a type. return } - g.Printf("type proxy%s _seq.Ref\n\n", obj.Name()) + g.Printf("type proxy%s_%s _seq.Ref\n\n", g.pkgPrefix, obj.Name()) - for i := 0; i < iface.NumMethods(); i++ { - m := iface.Method(i) + for _, m := range summary.callable { sig := m.Type().(*types.Signature) params := sig.Params() res := sig.Results() @@ -275,12 +299,12 @@ func (g *goGen) genInterface(obj *types.TypeName) { continue } - g.Printf("func (p *proxy%s) %s(", obj.Name(), m.Name()) + g.Printf("func (p *proxy%s_%s) %s(", g.pkgPrefix, obj.Name(), m.Name()) for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } - g.Printf("%s %s", paramName(params, i), g.typeString(params.At(i).Type())) + g.Printf("param_%s %s", paramName(params, i), g.typeString(params.At(i).Type())) } g.Printf(") ") @@ -292,35 +316,69 @@ func (g *goGen) genInterface(obj *types.TypeName) { g.Printf(" {\n") g.Indent() - g.Printf("in := new(_seq.Buffer)\n") for i := 0; i < params.Len(); i++ { - g.genWrite(paramName(params, i), "in", params.At(i).Type()) + pn := "param_" + paramName(params, i) + g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient) } - if res.Len() == 0 { - g.Printf("_seq.Transact((*_seq.Ref)(p), %q, proxy%s_%s_Code, in)\n", ifaceDesc, obj.Name(), m.Name()) - } else { - g.Printf("out := _seq.Transact((*_seq.Ref)(p), %q, proxy%s_%s_Code, in)\n", ifaceDesc, obj.Name(), m.Name()) - var rvs []string - for i := 0; i < res.Len(); i++ { - rv := fmt.Sprintf("res_%d", i) - g.genRead(rv, "out", res.At(i).Type()) - rvs = append(rvs, rv) + if res.Len() > 0 { + g.Printf("res := ") + } + g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Num)", g.pkgPrefix, obj.Name(), m.Name()) + for i := 0; i < params.Len(); i++ { + g.Printf(", _param_%s", paramName(params, i)) + } + g.Printf(")\n") + var retName string + if res.Len() > 0 { + if res.Len() == 1 { + T := res.At(0).Type() + g.genRead("_res", "res", T, modeReturned) + retName = "_res" + } else { + var rvs []string + for i := 0; i < res.Len(); i++ { + rv := fmt.Sprintf("res_%d", i) + g.genRead(rv, fmt.Sprintf("res.r%d", i), res.At(i).Type(), modeReturned) + rvs = append(rvs, rv) + } + retName = strings.Join(rvs, ", ") } - g.Printf("return %s\n", strings.Join(rvs, ",")) + g.Printf("return %s\n", retName) } - g.Outdent() g.Printf("}\n\n") } } -func (g *goGen) genRead(valName, seqName string, typ types.Type) { +func (g *goGen) genRead(toVar, fromVar string, typ types.Type, mode varMode) { if isErrorType(typ) { - g.Printf("%s := %s.ReadError()\n", valName, seqName) + g.genRead(toVar+"_str", fromVar, types.Typ[types.String], mode) + g.Printf("%s := toError(%s_str)\n", toVar, toVar) return } switch t := typ.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("%s := decodeString(%s, %v)\n", toVar, fromVar, mode.copyString()) + case types.Bool: + g.Printf("%s := %s != 0\n", toVar, fromVar) + default: + g.Printf("%s := %s(%s)\n", toVar, t.Underlying().String(), fromVar) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("%s := toSlice(%s, %v)\n", toVar, fromVar, mode.copySlice()) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } case *types.Pointer: switch u := t.Elem().(type) { case *types.Named: @@ -330,8 +388,8 @@ func (g *goGen) genRead(valName, seqName string, typ types.Type) { return } g.Printf("// Must be a Go object\n") - g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName) - g.Printf("%s := %s_ref.Get().(*%s.%s)\n", valName, valName, g.pkg.Name(), o.Name()) + g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) + g.Printf("%s := %s_ref.Get().(*%s.%s)\n", toVar, toVar, g.pkg.Name(), o.Name()) default: g.errorf("unsupported pointer type %s", t) } @@ -347,20 +405,22 @@ func (g *goGen) genRead(valName, seqName string, typ types.Type) { g.errorf("type %s not defined in %s", t, g.pkg) return } - g.Printf("var %s %s\n", valName, g.typeString(t)) - g.Printf("%s_ref := %s.ReadRef()\n", valName, seqName) - g.Printf("if %s_ref.Num < 0 { // go object \n", valName) - g.Printf(" %s = %s_ref.Get().(%s.%s)\n", valName, valName, g.pkg.Name(), o.Name()) + g.Printf("var %s %s\n", toVar, g.typeString(t)) + g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar) + g.Printf("if %s_ref != nil {\n", toVar) + g.Printf(" if %s_ref.Num < 0 { // go object \n", toVar) + g.Printf(" %s = %s_ref.Get().(%s.%s)\n", toVar, toVar, g.pkg.Name(), o.Name()) if hasProxy { - g.Printf("} else if %s_ref.Num != _seq.NullRefNum { // foreign object \n", valName) - g.Printf(" %s = (*proxy%s)(%s_ref)\n", valName, o.Name(), valName) + g.Printf(" } else { // foreign object \n") + g.Printf(" %s = (*proxy%s_%s)(%s_ref)\n", toVar, g.pkgPrefix, o.Name(), toVar) } + g.Printf(" }\n") g.Printf("}\n") default: g.errorf("unsupported named type %s", t) } default: - g.Printf("%s := %s.Read%s()\n", valName, seqName, seqType(t)) + g.errorf("unsupported type: %s", typ) } } @@ -397,73 +457,20 @@ func (g *goGen) typeString(typ types.Type) string { } func (g *goGen) gen() error { - g.genPreamble() + g.Printf(goPreamble, g.pkg.Name(), g.pkg.Path()) - var funcs, vars []string - - scope := g.pkg.Scope() - names := scope.Names() - - hasExported := false - for _, name := range names { - obj := scope.Lookup(name) - if !obj.Exported() { - continue - } - hasExported = true - - switch obj := obj.(type) { - // TODO(crawshaw): case *types.Var: - case *types.Func: - // TODO(crawshaw): functions that are not implementable from - // another language may still be callable. - if isCallable(obj) { - g.genFunc(obj) - funcs = append(funcs, obj.Name()) - } - case *types.TypeName: - named := obj.Type().(*types.Named) - switch T := named.Underlying().(type) { - case *types.Struct: - g.genStruct(obj, T) - case *types.Interface: - g.genInterface(obj) - } - case *types.Var: - g.genVar(obj) - vars = append(vars, obj.Name()) - case *types.Const: - default: - g.errorf("not yet supported, name for %v / %T", obj, obj) - continue - } + for _, s := range g.structs { + g.genStruct(s.obj, s.t) } - if !hasExported { - g.errorf("no exported names in the package %q", g.pkg.Path()) + for _, intf := range g.interfaces { + g.genInterface(intf.obj) } - - if len(funcs) > 0 { - g.Printf("func init() {\n") - g.Indent() - for i, name := range funcs { - g.Printf("_seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1, name) - } - g.Outdent() - g.Printf("}\n") + for _, v := range g.vars { + g.genVar(v) } - - if len(vars) > 0 { - g.Printf("func init() {\n") - g.Indent() - for _, name := range vars { - varDesc := fmt.Sprintf("%s.%s", g.pkg.Name(), name) - g.Printf("_seq.Register(%q, %d, var_set%s)\n", varDesc, 1, name) - g.Printf("_seq.Register(%q, %d, var_get%s)\n", varDesc, 2, name) - } - g.Outdent() - g.Printf("}\n") + for _, f := range g.funcs { + g.genFunc(f) } - if len(g.err) > 0 { return g.err } diff --git a/bind/genjava.go b/bind/genjava.go index 12cdf6f..0d70995 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -5,103 +5,49 @@ package bind import ( - "bytes" "fmt" "go/constant" - "go/token" "go/types" - "io" "math" - "regexp" "strings" ) // TODO(crawshaw): disallow basic android java type names in exported symbols. // TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime. -type ErrorList []error - -func (list ErrorList) Error() string { - buf := new(bytes.Buffer) - for i, err := range list { - if i > 0 { - buf.WriteRune('\n') - } - io.WriteString(buf, err.Error()) - } - return buf.String() -} - type javaGen struct { - *printer - fset *token.FileSet - pkg *types.Package javaPkg string - err ErrorList + + *generator } -func (g *javaGen) genStruct(obj *types.TypeName, T *types.Struct, intfs []*types.TypeName) { +func (g *javaGen) genStruct(obj *types.TypeName, T *types.Struct) { fields := exportedFields(T) methods := exportedMethodSet(types.NewPointer(obj.Type())) impls := []string{"go.Seq.Object"} pT := types.NewPointer(obj.Type()) - for _, intf := range intfs { - if types.AssignableTo(pT, intf.Type()) { - impls = append(impls, intf.Name()) + for _, iface := range g.interfaces { + if types.AssignableTo(pT, iface.obj.Type()) { + impls = append(impls, iface.obj.Name()) } } g.Printf("public static final class %s implements %s {\n", obj.Name(), strings.Join(impls, ", ")) g.Indent() - g.Printf("private static final String DESCRIPTOR = \"go.%s.%s\";\n", g.pkg.Name(), obj.Name()) - for i, f := range fields { - g.Printf("private static final int FIELD_%s_GET = 0x%x0f;\n", f.Name(), i) - g.Printf("private static final int FIELD_%s_SET = 0x%x1f;\n", f.Name(), i) - } - for i, m := range methods { - g.Printf("private static final int CALL_%s = 0x%x0c;\n", m.Name(), i) - } - g.Printf("\n") - g.Printf("private go.Seq.Ref ref;\n\n") + g.Printf("private final go.Seq.Ref ref;\n\n") n := obj.Name() g.Printf("private %s(go.Seq.Ref ref) { this.ref = ref; }\n\n", n) - g.Printf(`public go.Seq.Ref ref() { return ref; } - -public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); -} - -`) + g.Printf("public final go.Seq.Ref ref() { return ref; }\n\n") for _, f := range fields { - g.Printf("public %s get%s() {\n", g.javaType(f.Type()), f.Name()) - g.Indent() - g.Printf("Seq in = new Seq();\n") - g.Printf("Seq out = new Seq();\n") - g.Printf("in.writeRef(ref);\n") - g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_GET, in, out);\n", f.Name()) - if seqType(f.Type()) == "Ref" { - g.Printf("return new %s(out.read%s);\n", g.javaType(f.Type()), seqRead(f.Type())) - } else { - g.Printf("return out.read%s;\n", seqRead(f.Type())) - } - g.Outdent() - g.Printf("}\n\n") - - g.Printf("public void set%s(%s v) {\n", f.Name(), g.javaType(f.Type())) - g.Indent() - g.Printf("Seq in = new Seq();\n") - g.Printf("in.writeRef(ref);\n") - g.Printf("in.write%s;\n", seqWrite(f.Type(), "v")) - g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_SET, in, null);\n", f.Name()) - g.Outdent() - g.Printf("}\n\n") + g.Printf("public final native %s get%s();\n", g.javaType(f.Type()), f.Name()) + g.Printf("public final native void set%s(%s v);\n\n", f.Name(), g.javaType(f.Type())) } for _, m := range methods { - g.genFunc(m, true) + g.genFuncSignature(m, false, false) } g.Printf("@Override public boolean equals(Object o) {\n") @@ -151,7 +97,7 @@ public void call(int code, go.Seq in, go.Seq out) { g.Printf(`return b.append("}").toString();`) g.Printf("\n") g.Outdent() - g.Printf("}\n\n") + g.Printf("}\n") g.Outdent() g.Printf("}\n\n") @@ -161,134 +107,35 @@ func (g *javaGen) genInterfaceStub(o *types.TypeName, m *types.Interface) { g.Printf("public static abstract class Stub implements %s {\n", o.Name()) g.Indent() - g.Printf("static final String DESCRIPTOR = \"go.%s.%s\";\n\n", g.pkg.Name(), o.Name()) g.Printf("private final go.Seq.Ref ref;\n") g.Printf("public Stub() {\n ref = go.Seq.createRef(this);\n}\n\n") - g.Printf("public go.Seq.Ref ref() { return ref; }\n\n") - - g.Printf("public void call(int code, go.Seq in, go.Seq out) {\n") - g.Indent() - g.Printf("switch (code) {\n") - - for i := 0; i < m.NumMethods(); i++ { - f := m.Method(i) - g.Printf("case Proxy.CALL_%s: {\n", f.Name()) - g.Indent() - - sig := f.Type().(*types.Signature) - params := sig.Params() - for i := 0; i < params.Len(); i++ { - p := sig.Params().At(i) - jt := g.javaType(p.Type()) - g.Printf("%s param_%s;\n", jt, paramName(params, i)) - g.genRead("param_"+paramName(params, i), "in", p.Type()) - } - - res := sig.Results() - var returnsError bool - var numRes = res.Len() - if (res.Len() == 1 && isErrorType(res.At(0).Type())) || - (res.Len() == 2 && isErrorType(res.At(1).Type())) { - numRes -= 1 - returnsError = true - } - - if returnsError { - g.Printf("try {\n") - g.Indent() - } - - if numRes > 0 { - g.Printf("%s result = ", g.javaType(res.At(0).Type())) - } - - g.Printf("this.%s(", f.Name()) - for i := 0; i < params.Len(); i++ { - if i > 0 { - g.Printf(", ") - } - g.Printf("param_%s", paramName(params, i)) - } - g.Printf(");\n") - - if numRes > 0 { - g.Printf("out.write%s;\n", seqWrite(res.At(0).Type(), "result")) - } - if returnsError { - g.Printf("out.writeString(null);\n") - g.Outdent() - g.Printf("} catch (Exception e) {\n") - g.Indent() - if numRes > 0 { - resTyp := res.At(0).Type() - g.Printf("%s result = %s;\n", g.javaType(resTyp), g.javaTypeDefault(resTyp)) - g.Printf("out.write%s;\n", seqWrite(resTyp, "result")) - } - g.Printf("out.writeString(e.getMessage());\n") - g.Outdent() - g.Printf("}\n") - } - g.Printf("return;\n") - g.Outdent() - g.Printf("}\n") - } - - g.Printf("default:\n throw new RuntimeException(\"unknown code: \"+ code);\n") - g.Printf("}\n") - g.Outdent() - g.Printf("}\n") + g.Printf("public final go.Seq.Ref ref() { return ref; }\n\n") g.Outdent() g.Printf("}\n\n") } -const javaProxyPreamble = `static final class Proxy implements %s { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - - private go.Seq.Ref ref; - - Proxy(go.Seq.Ref ref) { this.ref = ref; } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - -` - -func (g *javaGen) genInterface(o *types.TypeName) { - iface := o.Type().(*types.Named).Underlying().(*types.Interface) - - summary := makeIfaceSummary(iface) - - g.Printf("public interface %s extends go.Seq.Object {\n", o.Name()) +func (g *javaGen) genInterface(iface interfaceInfo) { + g.Printf("public interface %s extends go.Seq.Object {\n", iface.obj.Name()) g.Indent() methodSigErr := false - for _, m := range summary.callable { - if err := g.funcSignature(m, false); err != nil { - methodSigErr = true - g.errorf("%v", err) - } - g.Printf(";\n\n") + for _, m := range iface.summary.callable { + g.genFuncSignature(m, false, true) } if methodSigErr { return // skip stub generation, more of the same errors } - if summary.implementable { - g.genInterfaceStub(o, iface) + if iface.summary.implementable { + g.genInterfaceStub(iface.obj, iface.t) } - g.Printf(javaProxyPreamble, o.Name()) + g.Printf(javaProxyPreamble, iface.obj.Name()) g.Indent() - for _, m := range summary.callable { - g.genFunc(m, true) - } - for i, m := range summary.callable { - g.Printf("static final int CALL_%s = 0x%x0a;\n", m.Name(), i+1) + for _, m := range iface.summary.callable { + g.genFuncSignature(m, false, false) } g.Outdent() @@ -311,6 +158,91 @@ func isJavaPrimitive(T types.Type) bool { return false } +// jniType returns a string that can be used as a JNI type. +func (g *javaGen) jniType(T types.Type) string { + if isErrorType(T) { + // The error type is usually translated into an exception in + // Java, however the type can be exposed in other ways, such + // as an exported field. + return g.jniType(types.Typ[types.String]) + } + switch T := T.(type) { + case *types.Basic: + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "jboolean" + case types.Int: + return "jlong" + case types.Int8: + return "jbyte" + case types.Int16: + return "jshort" + case types.Int32, types.UntypedRune: // types.Rune + return "jint" + case types.Int64, types.UntypedInt: + return "jlong" + case types.Uint8: // types.Byte + // TODO(crawshaw): Java bytes are signed, so this is + // questionable, but vital. + return "jbyte" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "jfloat" + case types.Float64, types.UntypedFloat: + return "jdouble" + case types.String, types.UntypedString: + return "jstring" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } + case *types.Slice: + return "jbyteArray" + + case *types.Pointer: + if _, ok := T.Elem().(*types.Named); ok { + return g.jniType(T.Elem()) + } + panic(fmt.Sprintf("unsupported pointer to type: %s", T)) + case *types.Named: + return "jobject" + default: + g.errorf("unsupported jniType: %#+v, %s\n", T, T) + return "TODO" + } +} + +func (g *javaGen) javaBasicType(T *types.Basic) string { + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "boolean" + case types.Int: + return "long" + case types.Int8: + return "byte" + case types.Int16: + return "short" + case types.Int32, types.UntypedRune: // types.Rune + return "int" + case types.Int64, types.UntypedInt: + return "long" + case types.Uint8: // types.Byte + // TODO(crawshaw): Java bytes are signed, so this is + // questionable, but vital. + return "byte" + // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: + case types.Float32: + return "float" + case types.Float64, types.UntypedFloat: + return "double" + case types.String, types.UntypedString: + return "String" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } +} + // javaType returns a string that can be used as a Java type. func (g *javaGen) javaType(T types.Type) string { if isErrorType(T) { @@ -321,34 +253,7 @@ func (g *javaGen) javaType(T types.Type) string { } switch T := T.(type) { case *types.Basic: - switch T.Kind() { - case types.Bool, types.UntypedBool: - return "boolean" - case types.Int: - return "long" - case types.Int8: - return "byte" - case types.Int16: - return "short" - case types.Int32, types.UntypedRune: // types.Rune - return "int" - case types.Int64, types.UntypedInt: - return "long" - case types.Uint8: // types.Byte - // TODO(crawshaw): Java bytes are signed, so this is - // questionable, but vital. - return "byte" - // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: - case types.Float32: - return "float" - case types.Float64, types.UntypedFloat: - return "double" - case types.String, types.UntypedString: - return "String" - default: - g.errorf("unsupported basic type: %s", T) - return "TODO" - } + return g.javaBasicType(T) case *types.Slice: elem := g.javaType(T.Elem()) return elem + "[]" @@ -375,48 +280,58 @@ func (g *javaGen) javaType(T types.Type) string { } } -// javaTypeDefault returns a string that represents the default value of the mapped java type. -// TODO(hyangah): Combine javaType and javaTypeDefault? -func (g *javaGen) javaTypeDefault(T types.Type) string { - switch T := T.(type) { - case *types.Basic: - switch T.Kind() { - case types.Bool: - return "false" - case types.Int, types.Int8, types.Int16, types.Int32, - types.Int64, types.Uint8: - return "0" - case types.Float32, types.Float64: - return "0.0" - case types.String: - return "null" - default: - g.errorf("unsupported return type: %s", T) - return "TODO" +func (g *javaGen) genJNIFuncSignature(o *types.Func, sName string, proxy bool) { + sig := o.Type().(*types.Signature) + res := sig.Results() + + var ret string + switch res.Len() { + case 2: + ret = g.jniType(res.At(0).Type()) + case 1: + if isErrorType(res.At(0).Type()) { + ret = "void" + } else { + ret = g.jniType(res.At(0).Type()) } - case *types.Slice, *types.Pointer, *types.Named: - return "null" - + case 0: + ret = "void" default: - g.errorf("unsupported javaType: %#+v, %s\n", T, T) - return "TODO" + g.errorf("too many result values: %s", o) + return } + + g.Printf("JNIEXPORT %s JNICALL\n", ret) + g.Printf("Java_%s_%s", g.jniPkgName(), g.className()) + if sName != "" { + // 0024 is the mangled form of $, for naming inner classes. + g.Printf("_00024%s", sName) + if proxy { + g.Printf("_00024Proxy") + } + } + g.Printf("_%s(JNIEnv* env, ", o.Name()) + if sName != "" { + g.Printf("jobject this") + } else { + g.Printf("jclass clazz") + } + params := sig.Params() + for i := 0; i < params.Len(); i++ { + g.Printf(", ") + v := sig.Params().At(i) + name := paramName(params, i) + jt := g.jniType(v.Type()) + g.Printf("%s %s", jt, name) + } + g.Printf(")") } -var paramRE = regexp.MustCompile(`^p[0-9]*$`) - -// paramName replaces incompatible name with a p0-pN name. -// Missing names, or existing names of the form p[0-9] are incompatible. -// TODO(crawshaw): Replace invalid unicode names. -func paramName(params *types.Tuple, pos int) string { - name := params.At(pos).Name() - if name == "" || name == "_" || paramRE.MatchString(name) { - name = fmt.Sprintf("p%d", pos) - } - return name +func (g *javaGen) jniPkgName() string { + return strings.Replace(g.javaPkg, ".", "_", -1) } -func (g *javaGen) funcSignature(o *types.Func, static bool) error { +func (g *javaGen) genFuncSignature(o *types.Func, static, header bool) { sig := o.Type().(*types.Signature) res := sig.Results() @@ -425,7 +340,8 @@ func (g *javaGen) funcSignature(o *types.Func, static bool) error { switch res.Len() { case 2: if !isErrorType(res.At(1).Type()) { - return fmt.Errorf("second result value must be of type error: %s", o) + g.errorf("second result value must be of type error: %s", o) + return } returnsError = true ret = g.javaType(res.At(0).Type()) @@ -439,14 +355,19 @@ func (g *javaGen) funcSignature(o *types.Func, static bool) error { case 0: ret = "void" default: - return fmt.Errorf("too many result values: %s", o) + g.errorf("too many result values: %s", o) + return } g.Printf("public ") if static { g.Printf("static ") } - g.Printf("%s %s(", ret, o.Name()) + if !header { + g.Printf("native ") + } + oName := o.Name() + g.Printf("%s %s(", ret, oName) params := sig.Params() for i := 0; i < params.Len(); i++ { if i > 0 { @@ -461,133 +382,116 @@ func (g *javaGen) funcSignature(o *types.Func, static bool) error { if returnsError { g.Printf(" throws Exception") } - return nil + g.Printf(";\n") } func (g *javaGen) genVar(o *types.Var) { jType := g.javaType(o.Type()) - varDesc := fmt.Sprintf("%s.%s", g.pkg.Name(), o.Name()) // setter - g.Printf("public static void set%s(%s v) {\n", o.Name(), jType) - g.Indent() - g.Printf("Seq in = new Seq();\n") - g.Printf("in.write%s;\n", seqWrite(o.Type(), "v")) - g.Printf("Seq.send(%q, 1, in, null);\n", varDesc) - g.Outdent() - g.Printf("}\n") - g.Printf("\n") + g.Printf("public static native void set%s(%s v);\n", o.Name(), jType) // getter - g.Printf("public static %s get%s() {\n", jType, o.Name()) - g.Indent() - g.Printf("Seq out = new Seq();\n") - g.Printf("Seq.send(%q, 2, null, out);\n", varDesc) - g.Printf("%s ", jType) - g.genRead("v", "out", o.Type()) - g.Printf("return v;\n") - g.Outdent() - g.Printf("}\n") - g.Printf("\n") + g.Printf("public static native %s get%s();\n\n", jType, o.Name()) } -func (g *javaGen) genFunc(o *types.Func, method bool) { - if err := g.funcSignature(o, !method); err != nil { - g.errorf("%v", err) +func (g *javaGen) genJavaToC(varName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genJavaToC(varName, types.Typ[types.String], mode) return } - sig := o.Type().(*types.Signature) - res := sig.Results() - - g.Printf(" {\n") - g.Indent() - g.Printf("go.Seq _in = null;\n") - g.Printf("go.Seq _out = null;\n") - - returnsError := false - var resultType types.Type - if res.Len() > 0 { - if !isErrorType(res.At(0).Type()) { - resultType = res.At(0).Type() + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("nstring _%s = go_seq_from_java_string(env, %s, %d);\n", varName, varName, g.toCFlag(mode.copyString())) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } - if res.Len() > 1 || isErrorType(res.At(0).Type()) { - returnsError = true + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, g.toCFlag(mode.copySlice())) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) } + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) + default: + panic(fmt.Sprintf("unsupported named type: %s / %T", u, u)) + } + case *types.Pointer: + g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } - if resultType != nil || returnsError { - g.Printf("_out = new go.Seq();\n") - } - if resultType != nil { - t := g.javaType(resultType) - g.Printf("%s _result;\n", t) - } - - params := sig.Params() - if method || params.Len() > 0 { - g.Printf("_in = new go.Seq();\n") - } - if method { - g.Printf("_in.writeRef(ref);\n") - } - for i := 0; i < params.Len(); i++ { - p := params.At(i) - g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i))) - } - g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name()) - if resultType != nil { - g.genRead("_result", "_out", resultType) - } - if returnsError { - g.Printf(`String _err = _out.readString(); -if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); -} -`) - } - if resultType != nil { - g.Printf("return _result;\n") - } - g.Outdent() - g.Printf("}\n\n") } -func (g *javaGen) genRead(resName, seqName string, T types.Type) { - switch T := T.(type) { +func (g *javaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genCToJava(toName, fromName, types.Typ[types.String], mode) + return + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName) + case types.Bool: + g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName) + default: + g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, g.toCFlag(mode.copySlice())) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator - switch T := T.Elem().(type) { + switch t := t.Elem().(type) { case *types.Named: - o := T.Obj() + o := t.Obj() if o.Pkg() != g.pkg { - g.errorf("type %s not defined in %s", T, g.pkg) + g.errorf("type %s not defined in %s", t, g.pkg) return } - g.Printf("%s = new %s(%s.readRef());\n", resName, o.Name(), seqName) + g.Printf("jobject %s = go_seq_from_refnum(env, %s, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", toName, fromName, g.pkgPrefix, o.Name(), g.pkgPrefix, o.Name()) default: - g.errorf("unsupported type %s", T) + g.errorf("unsupported type %s", t) } case *types.Named: - switch T.Underlying().(type) { + switch t.Underlying().(type) { case *types.Interface, *types.Pointer: - o := T.Obj() + o := t.Obj() if o.Pkg() != g.pkg { - g.errorf("type %s not defined in %s", T, g.pkg) + g.errorf("type %s not defined in %s", t, g.pkg) return } - g.Printf("%s = new %s.Proxy(%s.readRef());\n", resName, o.Name(), seqName) + g.Printf("jobject %s = go_seq_from_refnum(env, %s, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", toName, fromName, g.pkgPrefix, o.Name(), g.pkgPrefix, o.Name()) default: - g.errorf("unsupported, direct named type %s", T) + g.errorf("unsupported, direct named type %s", t) } default: - g.Printf("%s = %s.read%s();\n", resName, seqName, seqType(T)) + g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) } } -func (g *javaGen) errorf(format string, args ...interface{}) { - g.err = append(g.err, fmt.Errorf(format, args...)) -} - func (g *javaGen) gobindOpts() string { opts := []string{"-lang=java"} if g.javaPkg != javaPkgName(g.pkg.Name()) { @@ -596,16 +500,6 @@ func (g *javaGen) gobindOpts() string { return strings.Join(opts, " ") } -const javaPreamble = `// Java class %[1]s.%[2]s is a proxy for talking to a Go program. -// gobind %[3]s %[4]s -// -// File is generated by gobind. Do not edit. -package %[1]s; - -import go.Seq; - -` - var javaNameReplacer = strings.NewReplacer( "-", "_", ".", "_", @@ -666,73 +560,415 @@ func (g *javaGen) genConst(o *types.Const) { g.Printf("public static final %s %s = %s;\n", g.javaType(o.Type()), o.Name(), val) } -func (g *javaGen) gen() error { +func (g *javaGen) genJNIField(o *types.TypeName, f *types.Var) { + // setter + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s_00024%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), g.className(), o.Name(), f.Name(), g.jniType(f.Type())) + g.Indent() + g.Printf("int32_t o = go_seq_to_refnum(env, this);\n") + g.genJavaToC("v", f.Type(), modeRetained) + g.Printf("proxy%s_%s_%s_Set(o, _v);\n", g.pkgPrefix, o.Name(), f.Name()) + g.genRelease("v", f.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") + + // getter + g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type())) + g.Printf("Java_%s_%s_00024%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), g.className(), o.Name(), f.Name()) + g.Indent() + g.Printf("int32_t o = go_seq_to_refnum(env, this);\n") + g.Printf("%s r0 = ", g.cgoType(f.Type())) + g.Printf("proxy%s_%s_%s_Get(o);\n", g.pkgPrefix, o.Name(), f.Name()) + g.genCToJava("_r0", "r0", f.Type(), modeReturned) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *javaGen) genJNIVar(o *types.Var) { + // setter + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), g.className(), o.Name(), g.jniType(o.Type())) + g.Indent() + g.genJavaToC("v", o.Type(), modeRetained) + g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) + g.genRelease("v", o.Type(), modeRetained) + g.Outdent() + g.Printf("}\n\n") + + // getter + g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type())) + g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), g.className(), o.Name()) + g.Indent() + g.Printf("%s r0 = ", g.cgoType(o.Type())) + g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) + g.genCToJava("_r0", "r0", o.Type(), modeReturned) + g.Printf("return _r0;\n") + g.Outdent() + g.Printf("}\n\n") +} + +func (g *javaGen) genJNIFunc(o *types.Func, sName string, proxy bool) { + g.genJNIFuncSignature(o, sName, proxy) + sig := o.Type().(*types.Signature) + res := sig.Results() + + g.Printf(" {\n") + g.Indent() + + if sName != "" { + g.Printf("int32_t o = go_seq_to_refnum(env, this);\n") + } + params := sig.Params() + for i := 0; i < params.Len(); i++ { + name := paramName(params, i) + g.genJavaToC(name, params.At(i).Type(), modeTransient) + } + resPrefix := "" + if res.Len() > 0 { + if res.Len() == 1 { + g.Printf("%s r0 = ", g.cgoType(res.At(0).Type())) + } else { + resPrefix = "res." + g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name()) + } + } + g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name()) + if sName != "" { + g.Printf("o") + } + for i := 0; i < params.Len(); i++ { + if i > 0 || sName != "" { + g.Printf(", ") + } + g.Printf("_%s", paramName(params, i)) + } + g.Printf(");\n") + for i := 0; i < params.Len(); i++ { + g.genRelease(paramName(params, i), params.At(i).Type(), modeTransient) + } + for i := 0; i < res.Len(); i++ { + tn := fmt.Sprintf("_r%d", i) + t := res.At(i).Type() + g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeReturned) + } + // Go backwards so that any exception is thrown before + // the return. + for i := res.Len() - 1; i >= 0; i-- { + t := res.At(i).Type() + if !isErrorType(t) { + g.Printf("return _r%d;\n", i) + } else { + g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i) + } + } + g.Outdent() + g.Printf("}\n\n") +} + +// genRelease cleans up arguments that weren't copied in genJavaToC. +func (g *javaGen) genRelease(varName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genRelease(varName, types.Typ[types.String], mode) + return + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + if !mode.copyString() { + g.Printf("if (_%s.chars != NULL) {\n", varName) + g.Printf(" (*env)->ReleaseStringChars(env, %s, _%s.chars);\n", varName, varName) + g.Printf("}\n") + } + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + if !mode.copySlice() { + g.Printf("if (_%s.ptr != NULL) {\n", varName) + g.Printf(" (*env)->ReleaseByteArrayElements(env, %s, _%s.ptr, 0);\n", varName, varName) + g.Printf("}\n") + } + } + } + } +} + +func (g *javaGen) genMethodInterfaceProxy(oName string, m *types.Func) { + sig := m.Type().(*types.Signature) + params := sig.Params() + res := sig.Results() + g.genInterfaceMethodSignature(m, oName, false) + g.Indent() + // Push a JNI reference frame with a conservative capacity of two for each per parameter (Seq.Ref and Seq.Object), + // plus extra space for the receiver, the return value, and exception (if any). + g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", 2*params.Len()+10) + 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) + for i := 0; i < params.Len(); i++ { + pn := paramName(params, i) + g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient) + } + if res.Len() > 0 && !isErrorType(res.At(0).Type()) { + t := res.At(0).Type() + g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t)) + } else { + g.Printf("(*env)->CallVoidMethod(env, o, ") + } + g.Printf("mid_%s_%s", oName, m.Name()) + for i := 0; i < params.Len(); i++ { + g.Printf(", _%s", paramName(params, i)) + } + g.Printf(");\n") + var retName string + if res.Len() > 0 { + var rets []string + t := res.At(0).Type() + if !isErrorType(t) { + g.genJavaToC("res", t, modeReturned) + retName = "_res" + rets = append(rets, retName) + } + if res.Len() == 2 || isErrorType(t) { + g.Printf("jstring exc = go_seq_get_exception_message(env);\n") + st := types.Typ[types.String] + g.genJavaToC("exc", st, modeReturned) + retName = "_exc" + rets = append(rets, "_exc") + } + + if res.Len() > 1 { + g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name()) + g.Printf(" %s\n", strings.Join(rets, ", ")) + g.Printf("};\n") + retName = "sres" + } + } + g.Printf("go_seq_pop_local_frame(env);\n") + if retName != "" { + g.Printf("return %s;\n", retName) + } + g.Outdent() + g.Printf("}\n\n") +} + +func (g *javaGen) genH() error { + g.Printf(hPreamble, g.gobindOpts(), g.pkg.Path(), g.className()) + for _, iface := range g.interfaces { + for _, m := range iface.summary.callable { + g.genInterfaceMethodSignature(m, iface.obj.Name(), true) + g.Printf("\n") + } + } + g.Printf("#endif\n") + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *javaGen) jniCallType(t types.Type) string { + if isErrorType(t) { + return g.jniCallType(types.Typ[types.String]) + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.Bool, types.UntypedBool: + return "Boolean" + case types.Int: + return "Long" + case types.Int8, types.Uint8: // types.Byte + return "Byte" + case types.Int16: + return "Short" + case types.Int32, types.UntypedRune: // types.Rune + return "Int" + case types.Int64, types.UntypedInt: + return "Long" + case types.Float32: + return "Float" + case types.Float64, types.UntypedFloat: + return "Double" + case types.String, types.UntypedString: + return "Object" + default: + g.errorf("unsupported basic type: %s", t) + return "TODO" + } + case *types.Slice: + return "Object" + case *types.Pointer: + if _, ok := t.Elem().(*types.Named); ok { + return g.jniCallType(t.Elem()) + } + panic(fmt.Sprintf("unsupported pointer to type: %s", t)) + case *types.Named: + return "Object" + default: + return "Object" + } +} + +func (g *javaGen) jniClassSigType(className string) string { + return strings.Replace(g.javaPkg, ".", "/", -1) + "/" + g.className() + "$" + className +} + +func (g *javaGen) jniSigType(T types.Type) string { + if isErrorType(T) { + return g.jniSigType(types.Typ[types.String]) + } + switch T := T.(type) { + case *types.Basic: + switch T.Kind() { + case types.Bool, types.UntypedBool: + return "Z" + case types.Int: + return "J" + case types.Int8: + return "B" + case types.Int16: + return "S" + case types.Int32, types.UntypedRune: // types.Rune + return "I" + case types.Int64, types.UntypedInt: + return "J" + case types.Uint8: // types.Byte + return "B" + case types.Float32: + return "F" + case types.Float64, types.UntypedFloat: + return "D" + case types.String, types.UntypedString: + return "Ljava/lang/String;" + default: + g.errorf("unsupported basic type: %s", T) + return "TODO" + } + case *types.Slice: + return "[" + g.jniSigType(T.Elem()) + case *types.Pointer: + if _, ok := T.Elem().(*types.Named); ok { + return g.jniSigType(T.Elem()) + } + panic(fmt.Sprintf("unsupported pointer to type: %s", T)) + case *types.Named: + return "L" + g.jniClassSigType(T.Obj().Name()) + ";" + default: + g.errorf("unsupported jniType: %#+v, %s\n", T, T) + return "TODO" + } +} + +func (g *javaGen) genC() error { + g.Printf(cPreamble, g.gobindOpts(), g.pkg.Path(), g.pkg.Name()) + for _, iface := range g.interfaces { + g.Printf("static jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("static jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name()) + for i := 0; i < iface.t.NumMethods(); i++ { + g.Printf("static jmethodID mid_%s_%s;\n", iface.obj.Name(), iface.t.Method(i).Name()) + } + } + for _, s := range g.structs { + g.Printf("static jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name()) + g.Printf("static jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name()) + } + g.Printf("\n") + g.Printf("JNIEXPORT void JNICALL\n") + g.Printf("Java_%s_%s_init(JNIEnv *env, jclass _unused) {\n", g.jniPkgName(), g.className()) + g.Indent() + g.Printf("jclass clazz;\n") + for _, s := range g.structs { + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigType(s.obj.Name())) + g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name()) + g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"\", \"(Lgo/Seq$Ref;)V\");\n", g.pkgPrefix, s.obj.Name()) + } + for _, iface := range g.interfaces { + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigType(iface.obj.Name()+"$Proxy")) + g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"\", \"(Lgo/Seq$Ref;)V\");\n", g.pkgPrefix, iface.obj.Name()) + g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigType(iface.obj.Name())) + for _, m := range iface.summary.callable { + sig := m.Type().(*types.Signature) + res := sig.Results() + retSig := "V" + if res.Len() > 0 { + if t := res.At(0).Type(); !isErrorType(t) { + retSig = g.jniSigType(t) + } + } + var jniParams string + params := sig.Params() + for i := 0; i < params.Len(); i++ { + jniParams += g.jniSigType(params.At(i).Type()) + } + g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n", + iface.obj.Name(), m.Name(), m.Name(), jniParams, retSig) + } + g.Printf("\n") + } + g.Outdent() + g.Printf("}\n\n") + for _, f := range g.funcs { + g.genJNIFunc(f, "", false) + } + for _, s := range g.structs { + sName := s.obj.Name() + for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) { + g.genJNIFunc(m, sName, false) + } + for _, f := range exportedFields(s.t) { + g.genJNIField(s.obj, f) + } + } + for _, iface := range g.interfaces { + for _, m := range iface.summary.callable { + g.genJNIFunc(m, iface.obj.Name(), true) + g.genMethodInterfaceProxy(iface.obj.Name(), m) + } + } + for _, v := range g.vars { + g.genJNIVar(v) + } + if len(g.err) > 0 { + return g.err + } + return nil +} + +func (g *javaGen) genJava() error { g.Printf(javaPreamble, g.javaPkg, g.className(), g.gobindOpts(), g.pkg.Path()) g.Printf("public abstract class %s {\n", g.className()) g.Indent() + g.Printf("static {\n") + g.Indent() + g.Printf("Seq.touch(); // for loading the native library\n") + g.Printf("init();\n") + g.Outdent() + g.Printf("}\n\n") g.Printf("private %s() {} // uninstantiable\n\n", g.className()) + g.Printf("private static native void init();\n\n") - var funcs []string - - scope := g.pkg.Scope() - names := scope.Names() - var objs []types.Object - var intfs []*types.TypeName - hasExported := false - for _, name := range names { - obj := scope.Lookup(name) - if !obj.Exported() { - continue - } - objs = append(objs, obj) - hasExported = true - o, ok := obj.(*types.TypeName) - if !ok { - continue - } - named := obj.Type().(*types.Named) - intf, ok := named.Underlying().(*types.Interface) - if ok && intf.NumMethods() > 0 { - intfs = append(intfs, o) - } + for _, s := range g.structs { + g.genStruct(s.obj, s.t) } - if !hasExported { - g.errorf("no exported names in the package %q", g.pkg.Path()) + for _, iface := range g.interfaces { + g.genInterface(iface) } - for _, obj := range objs { - switch o := obj.(type) { - // TODO(crawshaw): case *types.Var: - case *types.Func: - if isCallable(o) { - g.genFunc(o, false) - funcs = append(funcs, o.Name()) - } - case *types.TypeName: - named := o.Type().(*types.Named) - switch t := named.Underlying().(type) { - case *types.Struct: - g.genStruct(o, t, intfs) - case *types.Interface: - g.genInterface(o) - default: - g.errorf("%s: cannot generate binding for %s: %T", g.fset.Position(o.Pos()), o.Name(), t) - continue - } - case *types.Const: - g.genConst(o) - case *types.Var: - g.genVar(o) - default: - g.errorf("unsupported exported type: %T", obj) - } + for _, c := range g.constants { + g.genConst(c) + } + g.Printf("\n") + for _, v := range g.vars { + g.genVar(v) + } + for _, f := range g.funcs { + g.genFuncSignature(f, true, false) } - for i, name := range funcs { - g.Printf("private static final int CALL_%s = %d;\n", name, i+1) - } - - g.Printf("private static final String DESCRIPTOR = %q;\n", g.pkg.Name()) g.Outdent() g.Printf("}\n") @@ -741,3 +977,47 @@ func (g *javaGen) gen() error { } return nil } + +const ( + javaProxyPreamble = `static final class Proxy implements %s { + private go.Seq.Ref ref; + + Proxy(go.Seq.Ref ref) { this.ref = ref; } + + public final go.Seq.Ref ref() { return ref; } + +` + javaPreamble = `// Java class %[1]s.%[2]s is a proxy for talking to a Go program. +// gobind %[3]s %[4]s +// +// File is generated by gobind. Do not edit. +package %[1]s; + +import go.Seq; + +` + cPreamble = `// JNI functions for the Go <=> Java bridge. +// gobind %[1]s %[2]s +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "%[3]s.h" +#include "_cgo_export.h" + + +` + hPreamble = `// JNI function headers for the Go <=> Java bridge. +// gobind %[1]s %[2]s +// +// File is generated by gobind. Do not edit. + +#ifndef __%[3]s_H__ +#define __%[3]s_H__ + +#include + +` +) diff --git a/bind/genobjc.go b/bind/genobjc.go index a6d1ca1..66dd163 100644 --- a/bind/genobjc.go +++ b/bind/genobjc.go @@ -7,7 +7,6 @@ package bind import ( "fmt" "go/constant" - "go/token" "go/types" "math" "strings" @@ -23,23 +22,12 @@ import ( // TODO(hyangah): error code/domain propagation type objcGen struct { - *printer - fset *token.FileSet - pkg *types.Package - err ErrorList - prefix string // prefix arg passed by flag. // fields set by init. - pkgName string namePrefix string - funcs []*types.Func - constants []*types.Const - vars []*types.Var - interfaces []interfaceInfo - structs []structInfo - otherNames []*types.TypeName + *generator } type interfaceInfo struct { @@ -54,65 +42,36 @@ type structInfo struct { } func (g *objcGen) init() { - g.pkgName = g.pkg.Name() + g.generator.init() g.namePrefix = g.prefix + strings.Title(g.pkgName) - g.funcs = nil - g.constants = nil - g.vars = nil - g.interfaces = nil - g.structs = nil - g.otherNames = nil - - scope := g.pkg.Scope() - hasExported := false - for _, name := range scope.Names() { - obj := scope.Lookup(name) - if !obj.Exported() { - continue - } - hasExported = true - switch obj := obj.(type) { - case *types.Func: - if isCallable(obj) { - g.funcs = append(g.funcs, obj) - } - case *types.TypeName: - named := obj.Type().(*types.Named) - switch t := named.Underlying().(type) { - case *types.Struct: - g.structs = append(g.structs, structInfo{obj, t}) - case *types.Interface: - g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)}) - default: - g.otherNames = append(g.otherNames, obj) - } - case *types.Const: - if _, ok := obj.Type().(*types.Basic); !ok { - g.errorf("unsupported exported const for %s: %T", obj.Name(), obj) - continue - } - g.constants = append(g.constants, obj) - case *types.Var: - g.vars = append(g.vars, obj) - default: - g.errorf("unsupported exported type for %s: %T", obj.Name(), obj) - } - } - if !hasExported { - g.errorf("no exported names in the package %q", g.pkg.Path()) - } } -const objcPreamble = `// Objective-C API for talking to %[1]s Go package. -// gobind %[2]s %[3]s -// -// File is generated by gobind. Do not edit. +func (g *objcGen) genGoH() error { + g.Printf(objcPreamble, g.pkg.Path(), g.gobindOpts(), g.pkg.Path()) + g.Printf("#ifndef __%s_H__\n", g.pkgName) + g.Printf("#define __%s_H__\n\n", g.pkgName) + g.Printf("#include \n") + g.Printf("#include \n") -` + for _, i := range g.interfaces { + if !i.summary.implementable { + continue + } + for _, m := range i.summary.callable { + g.genInterfaceMethodSignature(m, i.obj.Name(), true) + g.Printf("\n") + } + } + + g.Printf("#endif\n") + + if len(g.err) > 0 { + return g.err + } + return nil +} func (g *objcGen) genH() error { - g.init() - g.Printf(objcPreamble, g.pkg.Path(), g.gobindOpts(), g.pkg.Path()) g.Printf("#ifndef __%s%s_H__\n", g.prefix, strings.Title(g.pkgName)) g.Printf("#define __%s%s_H__\n", g.prefix, strings.Title(g.pkgName)) @@ -161,7 +120,7 @@ func (g *objcGen) genH() error { // var if len(g.vars) > 0 { - g.Printf("@interface %s : NSObject \n", g.namePrefix) + g.Printf("@interface %s : NSObject\n", g.namePrefix) for _, obj := range g.vars { objcType := g.objcType(obj.Type()) g.Printf("+ (%s) %s;\n", objcType, lowerFirst(obj.Name())) @@ -195,22 +154,19 @@ func (g *objcGen) gobindOpts() string { } func (g *objcGen) genM() error { - g.init() - g.Printf(objcPreamble, g.pkg.Path(), g.gobindOpts(), g.pkg.Path()) g.Printf("#include %q\n", g.namePrefix+".h") g.Printf("#include \n") g.Printf("#include \"seq.h\"\n") + g.Printf("#include \"_cgo_export.h\"\n") g.Printf("\n") g.Printf("static NSString* errDomain = @\"go.%s\";\n", g.pkg.Path()) g.Printf("\n") + g.Printf(`@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end - g.Printf("@protocol goSeqRefInterface\n") - g.Printf("-(GoSeqRef*) _ref;\n") - g.Printf("@end\n") - g.Printf("\n") - - g.Printf("#define _DESCRIPTOR_ %q\n\n", g.pkgName) +`) // forward declarations skipped from genH for _, i := range g.interfaces { @@ -258,11 +214,6 @@ func (g *objcGen) genM() error { g.Printf("@end\n\n") } - // global functions. - for i, obj := range g.funcs { - g.Printf("#define _CALL_%s_ %d\n", obj.Name(), i+1) - } - g.Printf("\n") for _, obj := range g.funcs { @@ -270,17 +221,18 @@ func (g *objcGen) genM() error { g.Printf("\n") } - // register proxy functions. - if len(needProxy) > 0 { - g.Printf("__attribute__((constructor)) static void init() {\n") - g.Indent() - for _, obj := range needProxy { - g.Printf("go_seq_register_proxy(\"go.%s.%s\", proxy%s%s);\n", g.pkgName, obj.Name(), g.namePrefix, obj.Name()) + for _, i := range g.interfaces { + for _, m := range i.summary.callable { + g.genInterfaceMethodProxy(i.obj, m) } - g.Outdent() - g.Printf("}\n") } + g.Printf("__attribute__((constructor)) static void init() {\n") + g.Indent() + g.Printf("init_seq();\n") + g.Outdent() + g.Printf("}\n") + if len(g.err) > 0 { return g.err } @@ -289,37 +241,31 @@ func (g *objcGen) genM() error { } func (g *objcGen) genVarM(o *types.Var) { - varDesc := fmt.Sprintf("%q", g.pkg.Name()+"."+o.Name()) objcType := g.objcType(o.Type()) // setter - s1 := &funcSummary{ - name: "set" + o.Name(), - ret: "void", - params: []paramInfo{{typ: o.Type(), name: "v"}}, - } - g.Printf("+ (void) %s:(%s)v {\n", s1.name, objcType) + g.Printf("+ (void) set%s:(%s)v {\n", o.Name(), objcType) g.Indent() - g.genFunc(varDesc, "1", s1, false) // false: not instance method. + g.genWrite("v", o.Type(), modeRetained) + g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name()) + g.genRelease("v", o.Type(), modeRetained) g.Outdent() g.Printf("}\n\n") // getter - s2 := &funcSummary{ - name: lowerFirst(o.Name()), - ret: objcType, - retParams: []paramInfo{{typ: o.Type(), name: "ret"}}, - } - g.Printf("+ (%s) %s {\n", s2.ret, s2.name) + g.Printf("+ (%s) %s {\n", objcType, lowerFirst(o.Name())) g.Indent() - g.genFunc(varDesc, "2", s2, false) + g.Printf("%s r0 = ", g.cgoType(o.Type())) + g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name()) + g.genRead("_r0", "r0", o.Type(), modeReturned) + g.Printf("return _r0;\n") g.Outdent() g.Printf("}\n\n") } func (g *objcGen) genConstM(o *types.Const) { cName := fmt.Sprintf("%s%s", g.namePrefix, o.Name()) - cType := g.objcType(o.Type()) + objcType := g.objcType(o.Type()) switch b := o.Type().(*types.Basic); b.Kind() { case types.Bool, types.UntypedBool: @@ -333,12 +279,12 @@ func (g *objcGen) genConstM(o *types.Const) { g.Printf("NSString* const %s = @%s;\n", cName, o.Val().ExactString()) case types.Int, types.Int8, types.Int16, types.Int32: - g.Printf("const %s %s = %s;\n", cType, cName, o.Val()) + g.Printf("const %s %s = %s;\n", objcType, cName, o.Val()) case types.Int64, types.UntypedInt: i, exact := constant.Int64Val(o.Val()) if !exact { - g.errorf("const value %s for %s cannot be represented as %s", o.Val(), o.Name(), cType) + g.errorf("const value %s for %s cannot be represented as %s", o.Val(), o.Name(), objcType) return } if i == math.MinInt64 { @@ -355,7 +301,7 @@ func (g *objcGen) genConstM(o *types.Const) { g.errorf("const value %s for %s cannot be represented as double", o.Val(), o.Name()) return } - g.Printf("const %s %s = %g;\n", cType, cName, f) + g.Printf("const %s %s = %g;\n", objcType, cName, f) default: g.errorf("unsupported const type %s for %s", b, o.Name()) @@ -365,6 +311,7 @@ func (g *objcGen) genConstM(o *types.Const) { type funcSummary struct { name string ret string + sig *types.Signature params, retParams []paramInfo } @@ -374,9 +321,9 @@ type paramInfo struct { } func (g *objcGen) funcSummary(obj *types.Func) *funcSummary { - s := &funcSummary{name: obj.Name()} - sig := obj.Type().(*types.Signature) + s := &funcSummary{name: obj.Name(), sig: sig} + params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) @@ -477,7 +424,7 @@ func (s *funcSummary) callMethod(g *objcGen) string { if i != 0 { key = p.name } - params = append(params, fmt.Sprintf("%s:%s", key, p.name)) + params = append(params, fmt.Sprintf("%s:_%s", key, p.name)) } if !s.returnsVal() { for _, p := range s.retParams { @@ -501,15 +448,6 @@ func (g *objcGen) genFuncH(obj *types.Func) { } } -func (g *objcGen) seqType(typ types.Type) string { - s := seqType(typ) - if s == "String" { - // TODO(hyangah): non utf-8 strings. - s = "UTF8" - } - return s -} - func (g *objcGen) genFuncM(obj *types.Func) { s := g.funcSummary(obj) if s == nil { @@ -517,90 +455,192 @@ func (g *objcGen) genFuncM(obj *types.Func) { } g.Printf("%s {\n", s.asFunc(g)) g.Indent() - g.genFunc("_DESCRIPTOR_", fmt.Sprintf("_CALL_%s_", s.name), s, false) + g.genFunc(s, "") g.Outdent() g.Printf("}\n") } -func (g *objcGen) genGetter(desc string, f *types.Var) { +func (g *objcGen) genGetter(oName string, f *types.Var) { t := f.Type() if isErrorType(t) { t = types.Typ[types.String] } - s := &funcSummary{ - name: lowerFirst(f.Name()), - ret: g.objcType(t), - retParams: []paramInfo{{typ: t, name: "ret_"}}, - } - - g.Printf("- %s {\n", s.asMethod(g)) + g.Printf("- (%s)%s {\n", g.objcType(t), lowerFirst(f.Name())) g.Indent() - g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_GET_", s, true) + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") + g.Printf("%s r0 = ", g.cgoType(f.Type())) + g.Printf("proxy%s_%s_%s_Get(refnum);\n", g.pkgPrefix, oName, f.Name()) + g.genRead("_r0", "r0", f.Type(), modeReturned) + g.Printf("return _r0;\n") g.Outdent() g.Printf("}\n\n") } -func (g *objcGen) genSetter(desc string, f *types.Var) { +func (g *objcGen) genSetter(oName string, f *types.Var) { t := f.Type() if isErrorType(t) { t = types.Typ[types.String] } - s := &funcSummary{ - name: "set" + f.Name(), - ret: "void", - params: []paramInfo{{typ: t, name: "v"}}, - } - g.Printf("- %s {\n", s.asMethod(g)) + g.Printf("- (void)set%s:(%s)v {\n", f.Name(), g.objcType(t)) g.Indent() - g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_SET_", s, true) + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") + g.genWrite("v", f.Type(), modeRetained) + g.Printf("proxy%s_%s_%s_Set(refnum, _v);\n", g.pkgPrefix, oName, f.Name()) + g.genRelease("v", f.Type(), modeRetained) g.Outdent() g.Printf("}\n\n") } -func (g *objcGen) genFunc(pkgDesc, callDesc string, s *funcSummary, isMethod bool) { - g.Printf("GoSeq in_ = {};\n") - g.Printf("GoSeq out_ = {};\n") - if isMethod { - g.Printf("go_seq_writeRef(&in_, self._ref);\n") +func (g *objcGen) genWrite(varName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genWrite(varName, types.Typ[types.String], mode) + return + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", varName, varName) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", varName, varName, g.toCFlag(mode.copySlice())) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + g.genRefWrite(varName, t) + default: + panic(fmt.Sprintf("unsupported named type: %s / %T", u, u)) + } + case *types.Pointer: + g.genRefWrite(varName, t) + default: + g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) + } +} + +func (g *objcGen) genRefWrite(varName string, t types.Type) { + g.Printf("int32_t _%s;\n", varName) + g.Printf("if ([(id)(%s) isKindOfClass:[%s class]]) {\n", varName, g.refTypeBase(t)) + g.Indent() + g.Printf("id %[1]s_proxy = (id)(%[1]s);\n", varName) + g.Printf("_%s = go_seq_go_to_refnum(%s_proxy._ref);\n", varName, varName) + g.Outdent() + g.Printf("} else {\n") + g.Indent() + g.Printf("_%s = go_seq_to_refnum(%s);\n", varName, varName) + g.Outdent() + g.Printf("}\n") +} + +func (g *objcGen) genRefRead(toName, fromName string, t types.Type) { + ptype := g.objcType(t) + g.Printf("%s %s = nil;\n", ptype, toName) + g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", toName, fromName) + g.Printf("if (%s_ref != NULL) {\n", toName) + g.Printf(" %s = %s_ref.obj;\n", toName, toName) + g.Printf(" if (%s == nil) {\n", toName) + g.Printf(" %s = [[%s alloc] initWithRef:%s_ref];\n", toName, g.refTypeBase(t), toName) + g.Printf(" }\n") + g.Printf("}\n") +} + +func (g *objcGen) genRead(toName, fromName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genRead(toName, fromName, types.Typ[types.String], mode) + return + } + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName) + case types.Bool: + g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName) + default: + g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) + } + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, g.toCFlag(mode.copySlice())) + default: + g.errorf("unsupported type: %s", t) + } + default: + g.errorf("unsupported type: %s", t) + } + case *types.Pointer: + switch t := t.Elem().(type) { + case *types.Named: + g.genRefRead(toName, fromName, types.NewPointer(t)) + default: + g.errorf("unsupported type %s", t) + } + case *types.Named: + switch t.Underlying().(type) { + case *types.Interface, *types.Pointer: + g.genRefRead(toName, fromName, t) + default: + g.errorf("unsupported, direct named type %s", t) + } + default: + g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) + } +} + +func (g *objcGen) genFunc(s *funcSummary, objName string) { + if objName != "" { + g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n") } for _, p := range s.params { - st := g.seqType(p.typ) - if st == "Ref" { - g.Printf("if ([(id)(%s) isKindOfClass:[%s class]]) {\n", p.name, g.refTypeBase(p.typ)) - g.Indent() - g.Printf("id %[1]s_proxy = (id)(%[1]s);\n", p.name) - g.Printf("go_seq_writeRef(&in_, %s_proxy._ref);\n", p.name) - g.Outdent() - g.Printf("} else {\n") - g.Indent() - g.Printf("go_seq_writeObjcRef(&in_, %s);\n", p.name) - g.Outdent() - g.Printf("}\n") + g.genWrite(p.name, p.typ, modeTransient) + } + resPrefix := "" + if len(s.retParams) > 0 { + if len(s.retParams) == 1 { + g.Printf("%s r0 = ", g.cgoType(s.retParams[0].typ)) } else { - g.Printf("go_seq_write%s(&in_, %s);\n", st, p.name) + resPrefix = "res." + g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, objName, s.name) } } - g.Printf("go_seq_send(%s, %s, &in_, &out_);\n", pkgDesc, callDesc) - - if s.returnsVal() { - p := s.retParams[0] - if seqTyp := g.seqType(p.typ); seqTyp != "Ref" { - g.Printf("%s %s = go_seq_read%s(&out_);\n", g.objcType(p.typ), p.name, g.seqType(p.typ)) - } else { - ptype := g.objcType(p.typ) - g.Printf("GoSeqRef* %s_ref = go_seq_readRef(&out_);\n", p.name) - g.Printf("%s %s = %s_ref.obj;\n", ptype, p.name, p.name) - g.Printf("if (%s == NULL) {\n", p.name) - g.Indent() - g.Printf("%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) - g.Outdent() - g.Printf("}\n") + g.Printf("proxy%s_%s_%s(", g.pkgPrefix, objName, s.name) + if objName != "" { + g.Printf("refnum") + } + for i, p := range s.params { + if i > 0 || objName != "" { + g.Printf(", ") } - } else { + g.Printf("_%s", p.name) + } + g.Printf(");\n") + for _, p := range s.params { + g.genRelease(p.name, p.typ, modeTransient) + } + + for i, r := range s.retParams { + g.genRead("_"+r.name, fmt.Sprintf("%sr%d", resPrefix, i), r.typ, modeReturned) + } + + if !s.returnsVal() { for _, p := range s.retParams { if isErrorType(p.typ) { - g.Printf("NSString* _%s = go_seq_readUTF8(&out_);\n", p.name) g.Printf("if ([_%s length] != 0 && %s != nil) {\n", p.name, p.name) g.Indent() g.Printf("NSMutableDictionary* details = [NSMutableDictionary dictionary];\n") @@ -608,37 +648,18 @@ func (g *objcGen) genFunc(pkgDesc, callDesc string, s *funcSummary, isMethod boo g.Printf("*%s = [NSError errorWithDomain:errDomain code:1 userInfo:details];\n", p.name) g.Outdent() g.Printf("}\n") - } else if seqTyp := g.seqType(p.typ); seqTyp != "Ref" { - g.Printf("%s %s_val = go_seq_read%s(&out_);\n", g.objcType(p.typ), p.name, g.seqType(p.typ)) - g.Printf("if (%s != NULL) {\n", p.name) - g.Indent() - g.Printf("*%s = %s_val;\n", p.name, p.name) - g.Outdent() - g.Printf("}\n") } else { - g.Printf("GoSeqRef* %s_ref = go_seq_readRef(&out_);\n", p.name) - g.Printf("if (%s != NULL) {\n", p.name) - g.Indent() - g.Printf("*%s = %s_ref.obj;\n", p.name, p.name) - g.Printf("if (*%s == NULL) {\n", p.name) - g.Indent() - g.Printf("*%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) - g.Outdent() - g.Printf("}\n") - g.Outdent() - g.Printf("}\n") + g.Printf("*%s = _%s;\n", p.name, p.name) } } } - g.Printf("go_seq_free(&in_);\n") - g.Printf("go_seq_free(&out_);\n") if n := len(s.retParams); n > 0 { p := s.retParams[n-1] if isErrorType(p.typ) { g.Printf("return ([_%s length] == 0);\n", p.name) } else { - g.Printf("return %s;\n", p.name) + g.Printf("return _%s;\n", p.name) } } } @@ -676,13 +697,6 @@ func (g *objcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) { func (g *objcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { summary := makeIfaceSummary(t) - desc := fmt.Sprintf("_GO_%s_%s", g.pkgName, obj.Name()) - g.Printf("#define %s_DESCRIPTOR_ \"go.%s.%s\"\n", desc, g.pkgName, obj.Name()) - for i, m := range summary.callable { - g.Printf("#define %s_%s_ (0x%x0a)\n", desc, m.Name(), i+1) - } - g.Printf("\n") - // @implementation Interface -- similar to what genStructM does. g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) g.Printf("}\n") @@ -700,61 +714,31 @@ func (g *objcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { s := g.funcSummary(m) g.Printf("- %s {\n", s.asMethod(g)) g.Indent() - g.genFunc(desc+"_DESCRIPTOR_", desc+"_"+m.Name()+"_", s, true) + g.genFunc(s, obj.Name()) g.Outdent() g.Printf("}\n\n") } g.Printf("@end\n") g.Printf("\n") - // proxy function. - if summary.implementable { - g.Printf("static void proxy%s%s(id obj, int code, GoSeq* in, GoSeq* out) {\n", g.namePrefix, obj.Name()) - g.Indent() - g.Printf("switch (code) {\n") - for _, m := range summary.callable { - g.Printf("case %s_%s_: {\n", desc, m.Name()) - g.Indent() - g.genInterfaceMethodProxy(obj, g.funcSummary(m)) - g.Outdent() - g.Printf("} break;\n") - } - g.Printf("default:\n") - g.Indent() - g.Printf("NSLog(@\"unknown code %%x for %s_DESCRIPTOR_\", code);\n", desc) - g.Outdent() - g.Printf("}\n") - g.Outdent() - g.Printf("}\n") - } - return summary.implementable } -func (g *objcGen) genInterfaceMethodProxy(obj *types.TypeName, s *funcSummary) { - g.Printf("id<%[1]s%[2]s> o = (id<%[1]s%[2]s>)(obj);\n", g.namePrefix, obj.Name()) - // read params from GoSeq* inseq +func (g *objcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) { + oName := obj.Name() + s := g.funcSummary(m) + g.genInterfaceMethodSignature(m, oName, false) + g.Indent() + g.Printf("%s o = go_seq_objc_from_refnum(refnum);\n", g.objcType(obj.Type())) for _, p := range s.params { - stype := g.seqType(p.typ) - ptype := g.objcType(p.typ) - if stype == "Ref" { - g.Printf("GoSeqRef* %s_ref = go_seq_readRef(in);\n", p.name) - g.Printf("%s %s = %s_ref.obj;\n", ptype, p.name, p.name) - g.Printf("if (%s == NULL) {\n", p.name) - g.Indent() - g.Printf("%s = [[%s alloc] initWithRef:%s_ref];\n", p.name, g.refTypeBase(p.typ), p.name) - g.Outdent() - g.Printf("}\n") - } else { - g.Printf("%s %s = go_seq_read%s(in);\n", ptype, p.name, stype) - } + g.genRead("_"+p.name, p.name, p.typ, modeTransient) } // call method if !s.returnsVal() { for _, p := range s.retParams { if isErrorType(p.typ) { - g.Printf("NSError* %s = NULL;\n", p.name) + g.Printf("NSError* %s = nil;\n", p.name) } else { g.Printf("%s %s;\n", g.objcType(p.typ), p.name) } @@ -767,63 +751,71 @@ func (g *objcGen) genInterfaceMethodProxy(obj *types.TypeName, s *funcSummary) { g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g)) } - // write result to GoSeq* outseq - if len(s.retParams) == 0 { - return - } - if s.returnsVal() { // len(s.retParams) == 1 && s.retParams[0] != error - p := s.retParams[0] - if stype := g.seqType(p.typ); stype == "Ref" { - g.Printf("if ([(id)(returnVal) isKindOfClass:[%s class]]) {\n", g.refTypeBase(p.typ)) - g.Indent() - g.Printf("idretVal_proxy = (id)(returnVal);\n") - g.Printf("go_seq_writeRef(out, retVal_proxy._ref);\n") - g.Outdent() - g.Printf("} else {\n") - g.Indent() - g.Printf("go_seq_writeRef(out, returnVal);\n") - g.Outdent() - g.Printf("}\n") + if len(s.retParams) > 0 { + if s.returnsVal() { // len(s.retParams) == 1 && s.retParams[0] != error + p := s.retParams[0] + g.genWrite("returnVal", p.typ, modeReturned) + g.Printf("return _returnVal;\n") } else { - g.Printf("go_seq_write%s(out, returnVal);\n", stype) + var rets []string + for i, p := range s.retParams { + if isErrorType(p.typ) { + g.Printf("NSString *%s_str = nil;\n", p.name) + if i == len(s.retParams)-1 { // last param. + g.Printf("if (!returnVal) {\n") + } else { + g.Printf("if (%s != nil) {\n", p.name) + } + g.Indent() + g.Printf("%[1]s_str = [%[1]s localizedDescription];\n", p.name) + g.Printf("if (%[1]s_str == nil || %[1]s_str.length == 0) {\n", p.name) + g.Indent() + g.Printf("%[1]s_str = @\"gobind: unknown error\";\n", p.name) + g.Outdent() + g.Printf("}\n") + g.Outdent() + g.Printf("}\n") + g.genWrite(p.name+"_str", p.typ, modeReturned) + rets = append(rets, fmt.Sprintf("_%s_str", p.name)) + } else { + g.genWrite(p.name, p.typ, modeReturned) + rets = append(rets, "_"+p.name) + } + } + if len(rets) > 1 { + g.Printf("cproxy%s_%s_%s_return _sres = {\n", g.pkgPrefix, oName, m.Name()) + g.Printf(" %s\n", strings.Join(rets, ", ")) + g.Printf("};\n") + g.Printf("return _sres;\n") + } else { + g.Printf("return %s;\n", rets[0]) + } } + } + g.Outdent() + g.Printf("}\n\n") +} + +// genRelease cleans up arguments that weren't copied in genWrite. +func (g *objcGen) genRelease(varName string, t types.Type, mode varMode) { + if isErrorType(t) { + g.genRelease(varName, types.Typ[types.String], mode) return } - for i, p := range s.retParams { - if isErrorType(p.typ) { - if i == len(s.retParams)-1 { // last param. - g.Printf("if (returnVal) {\n") - } else { - g.Printf("if (%s == NULL) {\n", p.name) + switch t := t.(type) { + case *types.Slice: + switch e := t.Elem().(type) { + case *types.Basic: + switch e.Kind() { + case types.Uint8: // Byte. + if !mode.copySlice() { + // If the argument was not mutable, go_seq_from_objc_bytearray created a copy. + // Free it here. + g.Printf("if (![%s isKindOfClass:[NSMutableData class]]) {\n", varName) + g.Printf(" free(_%s.ptr);\n", varName) + g.Printf("}\n") + } } - g.Indent() - g.Printf("go_seq_writeUTF8(out, NULL);\n") - g.Outdent() - g.Printf("} else {\n") - g.Indent() - g.Printf("NSString* %[1]sDesc = [%[1]s localizedDescription];\n", p.name) - g.Printf("if (%[1]sDesc == NULL || %[1]sDesc.length == 0) {\n", p.name) - g.Indent() - g.Printf("%[1]sDesc = @\"gobind: unknown error\";\n", p.name) - g.Outdent() - g.Printf("}\n") - g.Printf("go_seq_writeUTF8(out, %sDesc);\n", p.name) - g.Outdent() - g.Printf("}\n") - } else if seqTyp := g.seqType(p.typ); seqTyp == "Ref" { - // TODO(hyangah): NULL. - g.Printf("if ([(id)(%s) isKindOfClass:[%s class]]) {\n", p.name, g.refTypeBase(p.typ)) - g.Indent() - g.Printf("id%[1]s_proxy = (id)(%[1]s);\n", p.name) - g.Printf("go_seq_writeRef(out, %s_proxy._ref);\n", p.name) - g.Outdent() - g.Printf("} else {\n") - g.Indent() - g.Printf("go_seq_writeObjcRef(out, %s);\n", p.name) - g.Outdent() - g.Printf("}\n") - } else { - g.Printf("go_seq_write%s(out, %s);\n", seqTyp, p.name) } } } @@ -854,16 +846,6 @@ func (g *objcGen) genStructM(obj *types.TypeName, t *types.Struct) { fields := exportedFields(t) methods := exportedMethodSet(types.NewPointer(obj.Type())) - desc := fmt.Sprintf("_GO_%s_%s", g.pkgName, obj.Name()) - g.Printf("#define %s_DESCRIPTOR_ \"go.%s.%s\"\n", desc, g.pkgName, obj.Name()) - for i, f := range fields { - g.Printf("#define %s_FIELD_%s_GET_ (0x%x0f)\n", desc, f.Name(), i) - g.Printf("#define %s_FIELD_%s_SET_ (0x%x1f)\n", desc, f.Name(), i) - } - for i, m := range methods { - g.Printf("#define %s_%s_ (0x%x0c)\n", desc, m.Name(), i) - } - g.Printf("\n") g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) g.Printf("}\n\n") @@ -876,15 +858,15 @@ func (g *objcGen) genStructM(obj *types.TypeName, t *types.Struct) { g.Printf("}\n\n") for _, f := range fields { - g.genGetter(desc, f) - g.genSetter(desc, f) + g.genGetter(obj.Name(), f) + g.genSetter(obj.Name(), f) } for _, m := range methods { s := g.funcSummary(m) g.Printf("- %s {\n", s.asMethod(g)) g.Indent() - g.genFunc(desc+"_DESCRIPTOR_", desc+"_"+m.Name()+"_", s, true) + g.genFunc(s, obj.Name()) g.Outdent() g.Printf("}\n\n") } @@ -1020,3 +1002,12 @@ func lowerFirst(s string) string { } return string(conv) } + +const ( + objcPreamble = `// Objective-C API for talking to %[1]s Go package. +// gobind %[2]s %[3]s +// +// File is generated by gobind. Do not edit. + +` +) diff --git a/bind/java/Seq.java b/bind/java/Seq.java index 77c1900..4681b68 100644 --- a/bind/java/Seq.java +++ b/bind/java/Seq.java @@ -12,6 +12,12 @@ import java.util.logging.Logger; public class Seq { private static Logger log = Logger.getLogger("GoSeq"); + // also known to bind/seq/ref.go and bind/objc/seq_darwin.m + private static final int NULL_REFNUM = 41; + + // use single Ref for null Seq.Object + public static final Ref nullRef = new Ref(NULL_REFNUM, null); + static { // Look for the shim class auto-generated by gomobile bind. // Its only purpose is to call System.loadLibrary. @@ -26,70 +32,34 @@ public class Seq { } catch (IllegalAccessException e) { log.severe("LoadJNI class bad field: " + e); } - - initSeq(); + init(); } - @SuppressWarnings("UnusedDeclaration") - private long memptr; // holds C-allocated pointer + private static native void init(); - public Seq() { - ensure(64); + // Empty method to run class initializer + public static void touch() {} + + private Seq() { + } + + private static void throwException(String msg) throws Exception { // JNI helper + throw new Exception(msg); } // ctx is an android.context.Context. static native void setContext(java.lang.Object ctx); - // Ensure that at least size bytes can be written to the Seq. - // Any existing data in the buffer is preserved. - public native void ensure(int size); - - // Moves the internal buffer offset back to zero. - // Length and contents are maintained. Data can be read after a reset. - public native void resetOffset(); - - public native void log(String label); - - public native boolean readBool(); - public native byte readInt8(); - public native short readInt16(); - public native int readInt32(); - public native long readInt64(); - public long readInt() { return readInt64(); } - - public native float readFloat32(); - public native double readFloat64(); - public native String readUTF16(); - public String readString() { return readUTF16(); } - public native byte[] readByteArray(); - - public native void writeBool(boolean v); - public native void writeInt8(byte v); - public native void writeInt16(short v); - public native void writeInt32(int v); - public native void writeInt64(long v); - public void writeInt(long v) { writeInt64(v); } - - public native void writeFloat32(float v); - public native void writeFloat64(double v); - public native void writeUTF16(String v); - public void writeString(String v) { writeUTF16(v); } - public native void writeByteArray(byte[] v); - - public void writeRef(Ref ref) { - if (ref == null) - ref = RefTracker.nullRef; + public static int incRef(Seq.Object o) { + Ref ref = o.ref(); tracker.inc(ref); - writeInt32(ref.refnum); + return ref.refnum; } - public Ref readRef() { - int refnum = readInt32(); + public static Ref getRef(int refnum) { return tracker.get(refnum); } - static native void initSeq(); - // Informs the Go ref tracker that Java is done with this ref. static native void destroyRef(int refnum); @@ -98,30 +68,9 @@ public class Seq { return tracker.createRef(o); } - // sends a function invocation request to Go. - // - // Blocks until the function completes. - // If the request is for a method, the first element in src is - // a Ref to the receiver. - public static native void send(String descriptor, int code, Seq src, Seq dst); - - protected void finalize() throws Throwable { - super.finalize(); - free(); - } - private native void free(); - - public static Seq recv(Seq in, int code, int refnum) { - Seq out = new Seq(); - if (code == -1) { - // Special signal from seq.FinalizeRef. - tracker.dec(refnum); - return out; - } - - Ref r = tracker.get(refnum); - r.obj.call(code, in, out); - return out; + // decRef is called from seq.FinalizeRef + static void decRef(int refnum) { + tracker.dec(refnum); } // An Object is a Java object that matches a Go object. @@ -133,7 +82,6 @@ public class Seq { // generated abstract Stub. public interface Object { public Ref ref(); - public void call(int code, Seq in, Seq out); } // A Ref is an object tagged with an integer for passing back and @@ -148,11 +96,11 @@ public class Seq { public static final class Ref { // refnum < 0: Go object tracked by Java // refnum > 0: Java object tracked by Go - int refnum; + public final int refnum; int refcnt; // for Java obj: track how many times sent to Go. - public Seq.Object obj; // for Java obj: pointers to the Java obj. + public final Seq.Object obj; // for Java obj: pointers to the Java obj. Ref(int refnum, Seq.Object o) { this.refnum = refnum; @@ -174,10 +122,6 @@ public class Seq { static final class RefTracker { private static final int REF_OFFSET = 42; - private static final int NULL_REFNUM = 41; // also known to bind/seq/ref.go - - // use single Ref for null Seq.Object - private static final Ref nullRef = new Ref(NULL_REFNUM, null); // Next Java object reference number. // @@ -200,7 +144,7 @@ public class Seq { // We don't keep track of the Go object. return; } - if (refnum == nullRef.refnum) { + if (refnum == NULL_REFNUM) { return; } // Count how many times this ref's Java object is passed to Go. @@ -225,7 +169,7 @@ public class Seq { log.severe("dec request for Go object "+ refnum); return; } - if (refnum == nullRef.refnum) { + if (refnum == Seq.nullRef.refnum) { return; } // Java objects are removed on request of Go. @@ -241,7 +185,7 @@ public class Seq { synchronized Ref createRef(Seq.Object o) { if (o == null) { - return nullRef; + return Seq.nullRef; } if (next == Integer.MAX_VALUE) { throw new RuntimeException("createRef overflow for " + o); @@ -262,10 +206,9 @@ public class Seq { // // When we have real code, examine the tradeoffs. synchronized Ref get(int refnum) { - if (refnum > 0) { - if (refnum == nullRef.refnum) { - return nullRef; - } + if (refnum == NULL_REFNUM) { + return nullRef; + } else if (refnum > 0) { Ref ref = javaObjs.get(refnum); if (ref == null) { throw new RuntimeException("unknown java Ref: "+refnum); diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java index df3a563..c252957 100644 --- a/bind/java/SeqTest.java +++ b/bind/java/SeqTest.java @@ -68,8 +68,6 @@ public class SeqTest extends InstrumentationTestCase { Testpkg.setStructVar(s1); assertEquals("var StructVar", s1.String(), Testpkg.getStructVar().String()); - // TODO(hyangah): handle nil return value (translate to null) - AnI obj = new AnI(); obj.name = "this is an I"; Testpkg.setInterfaceVar(obj); @@ -118,9 +116,14 @@ public class SeqTest extends InstrumentationTestCase { } public void testUnicode() { - String want = "Hello, 世界"; - String got = Testpkg.StrDup(want); - assertEquals("Strings should match", want, got); + String[] tests = new String[]{ + "abcxyz09{}", + "Hello, 世界", + "\uffff\uD800\uDC00\uD800\uDC01\uD808\uDF45\uDBFF\uDFFF"}; + for (String want : tests) { + String got = Testpkg.StrDup(want); + assertEquals("Strings should match", want, got); + } } public void testNilErr() throws Exception { @@ -420,5 +423,37 @@ public class SeqTest extends InstrumentationTestCase { return null; } })); + assertEquals("Go nil interface is null", null, Testpkg.NewNullInterface()); + assertEquals("Go nil struct pointer is null", null, Testpkg.NewNullStruct()); + } + + public void testPassByteArray() { + Testpkg.PassByteArray(new Testpkg.B.Stub() { + @Override public void B(byte[] b) { + byte[] want = new byte[]{1, 2, 3, 4}; + MoreAsserts.assertEquals("bytes should match", want, b); + } + }); + } + + public void testReader() { + byte[] b = new byte[8]; + try { + long n = Testpkg.ReadIntoByteArray(b); + assertEquals("wrote to the entire byte array", b.length, n); + byte[] want = new byte[b.length]; + for (int i = 0; i < want.length; i++) + want[i] = (byte)i; + MoreAsserts.assertEquals("bytes should match", want, b); + } catch (Exception e) { + fail("Failed to write: " + e.toString()); + } + } + + public void testGoroutineCallback() { + Testpkg.GoroutineCallback(new Testpkg.Receiver.Stub() { + @Override public void Hello(String msg) { + } + }); } } diff --git a/bind/java/context_android.c b/bind/java/context_android.c new file mode 100644 index 0000000..d98325c --- /dev/null +++ b/bind/java/context_android.c @@ -0,0 +1,15 @@ +// 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. + +#include +#include "seq.h" + +JNIEXPORT void JNICALL +Java_go_Seq_setContext(JNIEnv* env, jclass clazz, jobject ctx) { + JavaVM* vm; + if ((*env)->GetJavaVM(env, &vm) != 0) { + LOG_FATAL("failed to get JavaVM"); + } + setContext(vm, (*env)->NewGlobalRef(env, ctx)); +} diff --git a/bind/java/context_android.go b/bind/java/context_android.go new file mode 100644 index 0000000..cf41109 --- /dev/null +++ b/bind/java/context_android.go @@ -0,0 +1,21 @@ +// 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 java // import "golang.org/x/mobile/bind/java" + +// #cgo LDFLAGS: -llog +// +//#include +import "C" + +import ( + "unsafe" + + "golang.org/x/mobile/internal/mobileinit" +) + +//export setContext +func setContext(vm *C.JavaVM, ctx C.jobject) { + mobileinit.SetCurrentContext(unsafe.Pointer(vm), unsafe.Pointer(ctx)) +} diff --git a/bind/java/doc.go b/bind/java/doc.go index e7a00a4..3f63ad3 100644 --- a/bind/java/doc.go +++ b/bind/java/doc.go @@ -5,8 +5,6 @@ // Package java implements the Java language bindings. // // See the design document (http://golang.org/s/gobind). -// -// Currently, this works only for android. package java import "C" diff --git a/bind/java/seq.h b/bind/java/seq.h new file mode 100644 index 0000000..3514175 --- /dev/null +++ b/bind/java/seq.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef __GO_SEQ_HDR__ +#define __GO_SEQ_HDR__ + +#include +#include +#include + +#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "go/Seq", __VA_ARGS__) +#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "go/Seq", __VA_ARGS__) + +// Platform specific types +typedef struct nstring { + void *chars; // utf16 encoded + jsize len; // length in bytes +} nstring; +typedef struct nbyteslice { + void *ptr; + jsize len; +} nbyteslice; +typedef jlong nint; + +extern void go_seq_dec_ref(int32_t ref); +extern int32_t go_seq_to_refnum(JNIEnv *env, jobject o); +extern jobject go_seq_from_refnum(JNIEnv *env, int32_t refnum, jclass proxy_class, jmethodID proxy_cons); + +extern void go_seq_maybe_throw_exception(JNIEnv *env, jobject msg); +extern jstring go_seq_get_exception_message(JNIEnv *env); + +extern jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy); +extern nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray s, int copy); + +extern jstring go_seq_to_java_string(JNIEnv *env, nstring str); +extern nstring go_seq_from_java_string(JNIEnv *env, jstring s, int copy); + +// push_local_frame retrieves or creates the JNIEnv* for the current thread +// and pushes a JNI reference frame. Must be matched with call to pop_local_frame. +extern JNIEnv *go_seq_push_local_frame(jint cap); +// Pop the current local frame, releasing all JNI local references in it +extern void go_seq_pop_local_frame(JNIEnv *env); + +#endif // __GO_SEQ_HDR__ diff --git a/bind/java/seq_android.c b/bind/java/seq_android.c deleted file mode 100644 index 30839cb..0000000 --- a/bind/java/seq_android.c +++ /dev/null @@ -1,539 +0,0 @@ -// Copyright 2014 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. - -#include -#include -#include -#include -#include -#include -#include -#include "seq_android.h" -#include "_cgo_export.h" - -#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "go/Seq", __VA_ARGS__) -#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "go/Seq", __VA_ARGS__) - -static jfieldID memptr_id; - -static jclass jbytearray_clazz; - -static jclass seq_clazz; -static jmethodID seq_cons; -static jmethodID seq_recv; - -static JavaVM *jvm; -// jnienvs holds the per-thread JNIEnv* for Go threads where we called AttachCurrentThread. -// A pthread key destructor is supplied to call DetachCurrentThread on exit. This trick is -// documented in http://developer.android.com/training/articles/perf-jni.html under "Threads". -static pthread_key_t jnienvs; - -// pinned represents a pinned array to be released at the end of Send call. -typedef struct pinned { - jobject ref; - void* ptr; - struct pinned* next; -} pinned; - -// mem is a simple C equivalent of seq.Buffer. -// -// Many of the allocations around mem could be avoided to improve -// function call performance, but the goal is to start simple. -typedef struct mem { - uint8_t *buf; - size_t off; - size_t len; - size_t cap; - - // TODO(hyangah): have it as a separate field outside mem? - pinned* pinned; -} mem; - -// mem_ensure ensures that m has at least size bytes free. -// If m is NULL, it is created. -static mem *mem_ensure(mem *m, uint32_t size) { - if (m == NULL) { - m = (mem*)malloc(sizeof(mem)); - if (m == NULL) { - LOG_FATAL("mem_ensure malloc failed"); - } - m->cap = 0; - m->off = 0; - m->len = 0; - m->buf = NULL; - m->pinned = NULL; - } - uint32_t cap = m->cap; - if (m->cap > m->off+size) { - return m; - } - if (cap == 0) { - cap = 64; - } - // TODO(hyangah): consider less aggressive allocation such as - // cap += max(pow2round(size), 64) - while (cap < m->off+size) { - cap *= 2; - } - m->buf = (uint8_t*)realloc((void*)m->buf, cap); - if (m->buf == NULL) { - LOG_FATAL("mem_ensure realloc failed, off=%d, size=%d", m->off, size); - } - m->cap = cap; - return m; -} - -static mem *mem_get(JNIEnv *env, jobject obj) { - if (obj == NULL) { - return NULL; - } - // Storage space for pointer is always 64-bits, even on 32-bit - // machines. Cast to uintptr_t to avoid -Wint-to-pointer-cast. - return (mem*)(uintptr_t)(*env)->GetLongField(env, obj, memptr_id); -} - -static uint32_t align(uint32_t offset, uint32_t alignment) { - uint32_t pad = offset % alignment; - if (pad > 0) { - pad = alignment-pad; - } - return pad+offset; -} - -static uint8_t *mem_read(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) { - if (size == 0) { - return NULL; - } - mem *m = mem_get(env, obj); - if (m == NULL) { - LOG_FATAL("mem_read on NULL mem"); - } - uint32_t offset = align(m->off, alignment); - - if (m->len-offset < size) { - LOG_FATAL("short read"); - } - uint8_t *res = m->buf+offset; - m->off = offset+size; - return res; -} - -uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) { - mem *m = mem_get(env, obj); - if (m == NULL) { - LOG_FATAL("mem_write on NULL mem"); - } - if (m->off != m->len) { - LOG_FATAL("write can only append to seq, size: (off=%d, len=%d, size=%d", m->off, m->len, size); - } - uint32_t offset = align(m->off, alignment); - m = mem_ensure(m, offset - m->off + size); - uint8_t *res = m->buf+offset; - m->off = offset+size; - m->len = offset+size; - return res; -} - -static void *pin_array(JNIEnv *env, jobject obj, jobject arr) { - mem *m = mem_get(env, obj); - if (m == NULL) { - m = mem_ensure(m, 64); - } - pinned *p = (pinned*) malloc(sizeof(pinned)); - if (p == NULL) { - LOG_FATAL("pin_array malloc failed"); - } - p->ref = (*env)->NewGlobalRef(env, arr); - - if ((*env)->IsInstanceOf(env, p->ref, jbytearray_clazz)) { - p->ptr = (*env)->GetByteArrayElements(env, p->ref, NULL); - } else { - LOG_FATAL("unsupported array type"); - } - - p->next = m->pinned; - m->pinned = p; - return p->ptr; -} - -static void unpin_arrays(JNIEnv *env, mem *m) { - pinned* p = m->pinned; - while (p != NULL) { - if ((*env)->IsInstanceOf(env, p->ref, jbytearray_clazz)) { - (*env)->ReleaseByteArrayElements(env, p->ref, (jbyte*)p->ptr, JNI_ABORT); - } else { - LOG_FATAL("invalid array type"); - } - - (*env)->DeleteGlobalRef(env, p->ref); - - pinned* o = p; - p = p->next; - free(o); - } - m->pinned = NULL; -} - -static void describe_exception(JNIEnv* env) { - jthrowable exc = (*env)->ExceptionOccurred(env); - if (exc) { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - } -} - -static jfieldID find_field(JNIEnv *env, const char *class_name, const char *field_name, const char *field_type) { - jclass clazz = (*env)->FindClass(env, class_name); - if (clazz == NULL) { - describe_exception(env); - LOG_FATAL("cannot find %s", class_name); - return NULL; - } - jfieldID id = (*env)->GetFieldID(env, clazz, field_name , field_type); - if(id == NULL) { - describe_exception(env); - LOG_FATAL("no %s/%s field", field_name, field_type); - return NULL; - } - return id; -} - -static jclass find_class(JNIEnv *env, const char *class_name) { - jclass clazz = (*env)->FindClass(env, class_name); - if (clazz == NULL) { - describe_exception(env); - LOG_FATAL("cannot find %s", class_name); - return NULL; - } - return (*env)->NewGlobalRef(env, clazz); -} - -static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name, const char *sig) { - jmethodID m = (*env)->GetMethodID(env, clazz, name, sig); - if (m == NULL) { - describe_exception(env); - LOG_FATAL("cannot find method %s", name); - } - return m; -} - -static jmethodID get_static_method_id(JNIEnv *env, jclass clazz, const char *name, const char *sig) { - jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig); - if (m == NULL) { - describe_exception(env); - LOG_FATAL("cannot find static method %s", name); - } - return m; -} - -void recv(int32_t ref, int code, uint8_t *in_ptr, size_t in_len, uint8_t **out_ptr, size_t *out_len) { - jobject out; - mem *out_mem; - mem *in_mem; - JNIEnv *env; - jobject in; - jint ret; - - ret = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_6); - if (ret != JNI_OK) { - if (ret != JNI_EDETACHED) { - LOG_FATAL("failed to get thread env"); - return; - } - if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) != JNI_OK) { - LOG_FATAL("failed to attach current thread"); - return; - } - pthread_setspecific(jnienvs, env); - } - - in = (*env)->NewObject(env, seq_clazz, seq_cons); - if (in == NULL) { - describe_exception(env); - LOG_FATAL("cannot instantiate Seq"); - return; - } - in_mem = mem_get(env, in); - if (in_mem == NULL) { - LOG_FATAL("recv on NULL in_mem"); - return; - } - memcpy(mem_write(env, in, in_len, 1), in_ptr, in_len); - in_mem->off = 0; - out = (*env)->CallStaticObjectMethod(env, seq_clazz, seq_recv, in, code, ref); - (*env)->DeleteLocalRef(env, in); - if (out == NULL) { - describe_exception(env); - LOG_FATAL("failed to invoke Seq.recv"); - return; - } - out_mem = mem_get(env, out); - (*env)->DeleteLocalRef(env, out); - if (out_mem == NULL) { - LOG_FATAL("recv on NULL out_mem"); - return; - } - *out_ptr = out_mem->buf; - *out_len = out_mem->len; -} - -// env_destructor is registered as a thread data key destructor to -// clean up a Go thread that is attached to the JVM. -static void env_destructor(void *env) { - if ((*jvm)->DetachCurrentThread(jvm) != JNI_OK) { - LOG_INFO("failed to detach current thread"); - } -} - -JNIEXPORT void JNICALL -Java_go_Seq_initSeq(JNIEnv *env, jclass clazz) { - seq_clazz = (*env)->NewGlobalRef(env, clazz); - seq_recv = get_static_method_id(env, seq_clazz, "recv", "(Lgo/Seq;II)Lgo/Seq;"); - seq_cons = get_method_id(env, seq_clazz, "", "()V"); - - memptr_id = find_field(env, "go/Seq", "memptr", "J"); - - jclass bclazz = find_class(env, "[B"); - jbytearray_clazz = (*env)->NewGlobalRef(env, bclazz); - - if ((*env)->GetJavaVM(env, &jvm) != 0) { - LOG_FATAL("failed to get JVM"); - return; - } - if (pthread_key_create(&jnienvs, env_destructor) != 0) { - LOG_FATAL("failed to initialize jnienvs thread local storage"); - return; - } -} - -JNIEXPORT void JNICALL -Java_go_Seq_ensure(JNIEnv *env, jobject obj, jint size) { - mem *m = mem_get(env, obj); - if (m == NULL || m->off+size > m->cap) { - m = mem_ensure(m, size); - (*env)->SetLongField(env, obj, memptr_id, (jlong)(uintptr_t)m); - } -} - -JNIEXPORT void JNICALL -Java_go_Seq_free(JNIEnv *env, jobject obj) { - mem *m = mem_get(env, obj); - if (m != NULL) { - unpin_arrays(env, m); - free((void*)m->buf); - free((void*)m); - } -} - -#define MEM_READ(obj, ty) ((ty*)mem_read(env, obj, sizeof(ty), sizeof(ty))) - -JNIEXPORT jboolean JNICALL -Java_go_Seq_readBool(JNIEnv *env, jobject obj) { - int8_t *v = MEM_READ(obj, int8_t); - if (v == NULL) { - return 0; - } - return *v != 0 ? 1 : 0; -} - -JNIEXPORT jbyte JNICALL -Java_go_Seq_readInt8(JNIEnv *env, jobject obj) { - uint8_t *v = MEM_READ(obj, uint8_t); - if (v == NULL) { - return 0; - } - return *v; -} - -JNIEXPORT jshort JNICALL -Java_go_Seq_readInt16(JNIEnv *env, jobject obj) { - int16_t *v = MEM_READ(obj, int16_t); - return v == NULL ? 0 : *v; -} - -JNIEXPORT jint JNICALL -Java_go_Seq_readInt32(JNIEnv *env, jobject obj) { - int32_t *v = MEM_READ(obj, int32_t); - return v == NULL ? 0 : *v; -} - -JNIEXPORT jlong JNICALL -Java_go_Seq_readInt64(JNIEnv *env, jobject obj) { - int64_t *v = MEM_READ(obj, int64_t); - return v == NULL ? 0 : *v; -} - -JNIEXPORT jfloat JNICALL -Java_go_Seq_readFloat32(JNIEnv *env, jobject obj) { - float *v = MEM_READ(obj, float); - return v == NULL ? 0 : *v; -} - -JNIEXPORT jdouble JNICALL -Java_go_Seq_readFloat64(JNIEnv *env, jobject obj) { - double *v = MEM_READ(obj, double); - return v == NULL ? 0 : *v; -} - -JNIEXPORT jstring JNICALL -Java_go_Seq_readUTF16(JNIEnv *env, jobject obj) { - int32_t size = *MEM_READ(obj, int32_t); - if (size == 0) { - return (*env)->NewString(env, NULL, 0); - } - return (*env)->NewString(env, (jchar*)mem_read(env, obj, 2*size, 1), size); -} - -JNIEXPORT jbyteArray JNICALL -Java_go_Seq_readByteArray(JNIEnv *env, jobject obj) { - // Send the (array length, pointer) pair encoded as two int64. - // The pointer value is omitted if array length is 0. - jlong size = Java_go_Seq_readInt64(env, obj); - if (size == 0) { - return NULL; - } - jbyteArray res = (*env)->NewByteArray(env, size); - jlong ptr = Java_go_Seq_readInt64(env, obj); - (*env)->SetByteArrayRegion(env, res, 0, size, (jbyte*)(intptr_t)(ptr)); - return res; -} - -#define MEM_WRITE(ty) (*(ty*)mem_write(env, obj, sizeof(ty), sizeof(ty))) - -JNIEXPORT void JNICALL -Java_go_Seq_writeBool(JNIEnv *env, jobject obj, jboolean v) { - MEM_WRITE(int8_t) = v ? 1 : 0; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeInt8(JNIEnv *env, jobject obj, jbyte v) { - MEM_WRITE(int8_t) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeInt16(JNIEnv *env, jobject obj, jshort v) { - MEM_WRITE(int16_t) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeInt32(JNIEnv *env, jobject obj, jint v) { - MEM_WRITE(int32_t) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeInt64(JNIEnv *env, jobject obj, jlong v) { - MEM_WRITE(int64_t) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeFloat32(JNIEnv *env, jobject obj, jfloat v) { - MEM_WRITE(float) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeFloat64(JNIEnv *env, jobject obj, jdouble v) { - MEM_WRITE(double) = v; -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeUTF16(JNIEnv *env, jobject obj, jstring v) { - if (v == NULL) { - MEM_WRITE(int32_t) = 0; - return; - } - int32_t size = (*env)->GetStringLength(env, v); - MEM_WRITE(int32_t) = size; - (*env)->GetStringRegion(env, v, 0, size, (jchar*)mem_write(env, obj, 2*size, 1)); -} - -JNIEXPORT void JNICALL -Java_go_Seq_writeByteArray(JNIEnv *env, jobject obj, jbyteArray v) { - // For Byte array, we pass only the (array length, pointer) pair - // encoded as two int64 values. If the array length is 0, - // the pointer value is omitted. - if (v == NULL) { - MEM_WRITE(int64_t) = 0; - return; - } - - jsize len = (*env)->GetArrayLength(env, v); - MEM_WRITE(int64_t) = len; - if (len == 0) { - return; - } - - jbyte* b = pin_array(env, obj, v); - MEM_WRITE(int64_t) = (jlong)(uintptr_t)b; -} - -JNIEXPORT void JNICALL -Java_go_Seq_resetOffset(JNIEnv *env, jobject obj) { - mem *m = mem_get(env, obj); - if (m == NULL) { - LOG_FATAL("resetOffset on NULL mem"); - } - m->off = 0; -} - -JNIEXPORT void JNICALL -Java_go_Seq_log(JNIEnv *env, jobject obj, jstring v) { - mem *m = mem_get(env, obj); - const char *label = (*env)->GetStringUTFChars(env, v, NULL); - if (label == NULL) { - LOG_FATAL("log GetStringUTFChars failed"); - } - if (m == NULL) { - LOG_INFO("%s: mem=NULL", label); - } else { - LOG_INFO("%s: mem{off=%d, len=%d, cap=%d}", label, m->off, m->len, m->cap); - } - (*env)->ReleaseStringUTFChars(env, v, label); -} - -JNIEXPORT void JNICALL -Java_go_Seq_destroyRef(JNIEnv *env, jclass clazz, jint refnum) { - DestroyRef(refnum); -} - -JNIEXPORT void JNICALL -Java_go_Seq_send(JNIEnv *env, jclass clazz, jstring descriptor, jint code, jobject src_obj, jobject dst_obj) { - uint8_t* req = NULL; - size_t reqlen = 0; - mem *src = mem_get(env, src_obj); - if (src != NULL) { - req = src->buf; - reqlen = src->len; - } - - uint8_t** res = NULL; - size_t* reslen = NULL; - mem *dst = mem_get(env, dst_obj); - if (dst != NULL) { - res = &dst->buf; - reslen = &dst->len; - } - - GoString desc; - desc.p = (char*)(*env)->GetStringUTFChars(env, descriptor, NULL); - if (desc.p == NULL) { - LOG_FATAL("send GetStringUTFChars failed"); - } - desc.n = (*env)->GetStringUTFLength(env, descriptor); - - Send(desc, (GoInt)code, req, reqlen, res, reslen); - (*env)->ReleaseStringUTFChars(env, descriptor, desc.p); - - if (src != NULL) { - unpin_arrays(env, src); // assume 'src' is no longer needed. - } -} - -JNIEXPORT void JNICALL -Java_go_Seq_setContext(JNIEnv* env, jclass clazz, jobject ctx) { - JavaVM* vm; - if ((*env)->GetJavaVM(env, &vm) != 0) { - LOG_FATAL("failed to get JavaVM"); - } - setContext(vm, (*env)->NewGlobalRef(env, ctx)); -} diff --git a/bind/java/seq_android.c.support b/bind/java/seq_android.c.support new file mode 100644 index 0000000..42d63dd --- /dev/null +++ b/bind/java/seq_android.c.support @@ -0,0 +1,262 @@ +// 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. + +// C support functions for bindings. This file is copied into the +// generated gomobile_bind package and compiled along with the +// generated binding files. + +#include +#include +#include +#include +#include +#include +#include +#include "seq.h" +#include "_cgo_export.h" + +#define NULL_REFNUM 41 + +static JavaVM *jvm; +// jnienvs holds the per-thread JNIEnv* for Go threads where we called AttachCurrentThread. +// A pthread key destructor is supplied to call DetachCurrentThread on exit. This trick is +// documented in http://developer.android.com/training/articles/perf-jni.html under "Threads". +static pthread_key_t jnienvs; + +static jclass seq_class; +static jmethodID seq_throw_exc; +static jmethodID seq_getRef; +static jmethodID seq_decRef; +static jmethodID seq_incRef; + +static jmethodID throwable_getMessage; + +static jfieldID ref_objField; + +// env_destructor is registered as a thread data key destructor to +// clean up a Go thread that is attached to the JVM. +static void env_destructor(void *env) { + if ((*jvm)->DetachCurrentThread(jvm) != JNI_OK) { + LOG_INFO("failed to detach current thread"); + } +} + +static JNIEnv *go_seq_get_thread_env(void) { + JNIEnv *env; + jint ret = (*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_6); + if (ret != JNI_OK) { + if (ret != JNI_EDETACHED) { + LOG_FATAL("failed to get thread env"); + return; + } + if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) != JNI_OK) { + LOG_FATAL("failed to attach current thread"); + return; + } + pthread_setspecific(jnienvs, env); + } + return env; +} + +void go_seq_maybe_throw_exception(JNIEnv *env, jobject msg) { + if (msg != NULL && (*env)->GetStringLength(env, msg) > 0) { + (*env)->CallStaticVoidMethod(env, seq_class, seq_throw_exc, msg); + } +} + +jstring go_seq_get_exception_message(JNIEnv *env) { + jthrowable exc = (*env)->ExceptionOccurred(env); + if (!exc) { + return NULL; + } + (*env)->ExceptionClear(env); + return (*env)->CallObjectMethod(env, exc, throwable_getMessage); +} + +jbyteArray go_seq_to_java_bytearray(JNIEnv *env, nbyteslice s, int copy) { + if (s.ptr == NULL) { + return NULL; + } + jbyteArray res = (*env)->NewByteArray(env, s.len); + if (res == NULL) { + LOG_FATAL("NewByteArray failed"); + return res; + } + (*env)->SetByteArrayRegion(env, res, 0, s.len, s.ptr); + if (copy) { + free(s.ptr); + } + return res; +} + +nstring go_seq_from_java_string(JNIEnv *env, jstring str, int copy) { + struct nstring res = {NULL, 0}; + if (str == NULL) { + return res; + } + jsize nchars = (*env)->GetStringLength(env, str); + jchar *chars = (jchar *)(*env)->GetStringChars(env, str, NULL); + if (chars == NULL) { + LOG_FATAL("GetStringChars failed"); + return res; + } + if (copy) { + void *arr_copy = malloc(nchars*2); + if (arr_copy == NULL) { + LOG_FATAL("malloc failed"); + return res; + } + memcpy(arr_copy, chars, nchars*2); + (*env)->ReleaseStringChars(env, str, chars); + chars = (jchar *)arr_copy; + } + res.chars = chars; + res.len = nchars; + return res; +} + +nbyteslice go_seq_from_java_bytearray(JNIEnv *env, jbyteArray arr, int copy) { + struct nbyteslice res = {NULL, 0}; + if (arr == NULL) { + return res; + } + + jsize len = (*env)->GetArrayLength(env, arr); + if (len == 0) { + return res; + } + jbyte *ptr = (*env)->GetByteArrayElements(env, arr, NULL); + if (ptr == NULL) { + LOG_FATAL("GetByteArrayElements failed"); + return res; + } + if (copy) { + void *ptr_copy = (void *)malloc(len); + if (ptr_copy == NULL) { + LOG_FATAL("malloc failed"); + return res; + } + memcpy(ptr_copy, ptr, len); + (*env)->ReleaseByteArrayElements(env, arr, ptr, JNI_ABORT); + ptr = (jbyte *)ptr_copy; + } + res.ptr = ptr; + res.len = len; + return res; +} + +int32_t go_seq_to_refnum(JNIEnv *env, jobject o) { + if (o == NULL) { + return NULL_REFNUM; + } + return (int32_t)(*env)->CallStaticIntMethod(env, seq_class, seq_incRef, o); +} + +jobject go_seq_from_refnum(JNIEnv *env, int32_t refnum, jclass proxy_class, jmethodID proxy_cons) { + if (refnum == NULL_REFNUM) { + return NULL; + } + // Seq.Ref ref = Seq.getRef(refnum) + jobject ref = (*env)->CallStaticObjectMethod(env, seq_class, seq_getRef, (jint)refnum); + if (ref == NULL) { + LOG_FATAL("Unknown reference: %d", refnum); + return NULL; + } + if (refnum > 0) { // Java object + // return ref.obj + return (*env)->GetObjectField(env, ref, ref_objField); + } else { + // return new (ref) + return (*env)->NewObject(env, proxy_class, proxy_cons, ref); + } +} + +// go_seq_to_java_string converts a nstring to a jstring. +jstring go_seq_to_java_string(JNIEnv *env, nstring str) { + jstring s = (*env)->NewString(env, str.chars, str.len); + if (str.chars != NULL) { + free(str.chars); + } + return s; +} + +// go_seq_push_local_frame retrieves or creates the JNIEnv* for the current thread +// and pushes a JNI reference frame. Must be matched with call to go_seq_pop_local_frame. +JNIEnv *go_seq_push_local_frame(jint cap) { + JNIEnv *env = go_seq_get_thread_env(); + if ((*env)->PushLocalFrame(env, cap) < 0) { + LOG_FATAL("PushLocalFrame failed"); + } + return env; +} + +// Pop the current local frame, freeing all JNI local references in it +void go_seq_pop_local_frame(JNIEnv *env) { + (*env)->PopLocalFrame(env, NULL); +} + +void go_seq_dec_ref(int32_t ref) { + JNIEnv *env = go_seq_get_thread_env(); + (*env)->CallStaticVoidMethod(env, seq_class, seq_decRef, (jint)ref); +} + +JNIEXPORT void JNICALL +Java_go_Seq_init(JNIEnv *env, jclass clazz) { + if ((*env)->GetJavaVM(env, &jvm) != 0) { + LOG_FATAL("failed to get JVM"); + return; + } + if (pthread_key_create(&jnienvs, env_destructor) != 0) { + LOG_FATAL("failed to initialize jnienvs thread local storage"); + return; + } + + seq_class = (*env)->NewGlobalRef(env, clazz); + seq_throw_exc = (*env)->GetStaticMethodID(env, seq_class, "throwException", "(Ljava/lang/String;)V"); + if (seq_throw_exc == NULL) { + LOG_FATAL("failed to find method Seq.throwException"); + return; + } + + seq_getRef = (*env)->GetStaticMethodID(env, seq_class, "getRef", "(I)Lgo/Seq$Ref;"); + if (seq_getRef == NULL) { + LOG_FATAL("failed to find method Seq.getRef"); + return; + } + seq_decRef = (*env)->GetStaticMethodID(env, seq_class, "decRef", "(I)V"); + if (seq_decRef == NULL) { + LOG_FATAL("failed to find method Seq.decRef"); + return; + } + seq_incRef = (*env)->GetStaticMethodID(env, seq_class, "incRef", "(Lgo/Seq$Object;)I"); + if (seq_incRef == NULL) { + LOG_FATAL("failed to find method Seq.incRef"); + return; + } + jclass throwable_class = (*env)->FindClass(env, "java/lang/Throwable"); + if (throwable_class == NULL) { + LOG_FATAL("failed to find Throwable class"); + return; + } + throwable_getMessage = (*env)->GetMethodID(env, throwable_class, "getMessage", "()Ljava/lang/String;"); + if (throwable_getMessage == NULL) { + LOG_FATAL("failed to find method Throwable.getMessage"); + return; + } + jclass ref_class = (*env)->FindClass(env, "go/Seq$Ref"); + if (ref_class == NULL) { + LOG_FATAL("failed to find the Seq.Ref class"); + return; + } + ref_objField = (*env)->GetFieldID(env, ref_class, "obj", "Lgo/Seq$Object;"); + if (ref_objField == NULL) { + LOG_FATAL("failed to find the Seq.Ref.obj field"); + return; + } +} + +JNIEXPORT void JNICALL +Java_go_Seq_destroyRef(JNIEnv *env, jclass clazz, jint refnum) { + DestroyRef(refnum); +} diff --git a/bind/java/seq_android.go b/bind/java/seq_android.go deleted file mode 100644 index a69362b..0000000 --- a/bind/java/seq_android.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2014 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 java // import "golang.org/x/mobile/bind/java" - -//#cgo LDFLAGS: -llog -//#include -//#include -//#include -//#include -//#include "seq_android.h" -import "C" -import ( - "fmt" - "unsafe" - - "golang.org/x/mobile/bind/seq" - "golang.org/x/mobile/internal/mobileinit" -) - -const maxSliceLen = 1<<31 - 1 - -const debug = false - -// Send is called by Java to send a request to run a Go function. -//export Send -func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) { - fn := seq.Registry[descriptor][code] - if fn == nil { - panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code)) - } - - var in, out *seq.Buffer - if req != nil && reqlen > 0 { - in = &seq.Buffer{ - Data: (*[maxSliceLen]byte)(unsafe.Pointer(req))[:reqlen], - } - } - if res != nil { - out = new(seq.Buffer) - } - - fn(out, in) - - if res != nil { - // BUG(hyangah): the function returning a go byte slice (so fn writes a pointer into 'out') is unsafe. - // After fn is complete here, Go runtime is free to collect or move the pointed byte slice - // contents. (Explicitly calling runtime.GC here will surface the problem?) - // Without pinning support from Go side, it will be hard to fix it without extra copying. - seqToBuf(res, reslen, out) - } -} - -// DestroyRef is called by Java to inform Go it is done with a reference. -//export DestroyRef -func DestroyRef(refnum C.int32_t) { - seq.Delete(int32(refnum)) -} - -func seqToBuf(bufptr **C.uint8_t, lenptr *C.size_t, buf *seq.Buffer) { - if debug { - fmt.Printf("seqToBuf tag 1, len(buf.Data)=%d, *lenptr=%d\n", len(buf.Data), *lenptr) - } - if len(buf.Data) == 0 { - *lenptr = 0 - return - } - if len(buf.Data) > int(*lenptr) { - // TODO(crawshaw): realloc - C.free(unsafe.Pointer(*bufptr)) - m := C.malloc(C.size_t(len(buf.Data))) - if uintptr(m) == 0 { - panic(fmt.Sprintf("malloc failed, size=%d", len(buf.Data))) - } - *bufptr = (*C.uint8_t)(m) - *lenptr = C.size_t(len(buf.Data)) - } - C.memcpy(unsafe.Pointer(*bufptr), unsafe.Pointer(&buf.Data[0]), C.size_t(len(buf.Data))) -} - -// transact calls a method on a Java object instance. -// It blocks until the call is complete. -func transact(ref *seq.Ref, _ string, code int, inBuf *seq.Buffer) *seq.Buffer { - var ( - out *C.uint8_t = nil - outLen C.size_t = 0 - in *C.uint8_t = nil - inLen C.size_t = 0 - ) - - if len(inBuf.Data) > 0 { - in = (*C.uint8_t)(unsafe.Pointer(&inBuf.Data[0])) - inLen = C.size_t(len(inBuf.Data)) - } - - C.recv(C.int32_t(ref.Num), C.int(code), in, inLen, &out, &outLen) - if outLen > 0 { - outBuf := &seq.Buffer{ - Data: make([]byte, outLen), - } - copy(outBuf.Data, (*[maxSliceLen]byte)(unsafe.Pointer(out))[:outLen]) - return outBuf - } - return nil -} - -func encodeString(out *seq.Buffer, v string) { - out.WriteUTF16(v) -} - -func decodeString(in *seq.Buffer) string { - return in.ReadUTF16() -} - -func init() { - seq.FinalizeRef = func(ref *seq.Ref) { - if ref.Num < 0 { - panic(fmt.Sprintf("not a Java ref: %d", ref.Num)) - } - transact(ref, "", -1, new(seq.Buffer)) - } - - seq.Transact = transact - seq.EncString = encodeString - seq.DecString = decodeString -} - -//export setContext -func setContext(vm *C.JavaVM, ctx C.jobject) { - mobileinit.SetCurrentContext(unsafe.Pointer(vm), unsafe.Pointer(ctx)) -} diff --git a/bind/java/seq_android.go.support b/bind/java/seq_android.go.support new file mode 100644 index 0000000..2b6c50b --- /dev/null +++ b/bind/java/seq_android.go.support @@ -0,0 +1,101 @@ +// 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 gomobile_bind + +// Go support functions for bindings. This file is copied into the +// generated gomobile_bind package and compiled along with the +// generated binding files. + +//#cgo LDFLAGS: -llog +//#include +//#include +//#include +//#include "seq.h" +import "C" +import ( + "unicode/utf16" + "unsafe" + + "golang.org/x/mobile/bind/seq" +) + +// DestroyRef is called by Java to inform Go it is done with a reference. +//export DestroyRef +func DestroyRef(refnum C.int32_t) { + seq.Delete(int32(refnum)) +} + +// encodeString encodes a Go string to utf16 and returns a Java string as a nstring +// containing the jstring. +// encodeString uses UTF16 as the intermediate format. Note that UTF8 is an obvious +// alternative, but JNI only supports a C-safe variant of UTF8 (modified UTF8). +// The returned data is always a copy, regardless of cpy, and will be freed in +// go_seq_to_java_string. +func encodeString(s string, cpy bool) C.nstring { + n := C.int(len(s)) + if n == 0 { + return C.nstring{} + } + // Allocate enough for the worst case estimate, every character is a surrogate pair + worstCaseLen := 4 * len(s) + utf16buf := C.malloc(C.size_t(worstCaseLen)) + if utf16buf == nil { + panic("encodeString: malloc failed") + } + chars := (*[1<<30 - 1]uint16)(unsafe.Pointer(utf16buf))[:worstCaseLen/2 : worstCaseLen/2] + nchars := seq.UTF16Encode(s, chars) + return C.nstring{chars: unsafe.Pointer(utf16buf), len: C.jsize(nchars)} +} + +// decodeString decodes a nstring (jstring) to a Go string. +// If cpy is set, the string contains a copy and is freed. +func decodeString(str C.nstring, cpy bool) string { + if str.chars == nil { + return "" + } + chars := (*[1<<30 - 1]uint16)(unsafe.Pointer(str.chars))[:str.len] + s := string(utf16.Decode(chars)) // TODO: avoid the []rune allocation + if cpy { + C.free(str.chars) + } + return s +} + +// fromSlice converts a slice to a jbyteArray cast as a nbyteslice. If cpy +// is set, the returned slice is a copy to be free by go_seq_to_java_bytearray. +func fromSlice(s []byte, cpy bool) C.nbyteslice { + if s == nil || len(s) == 0 { + return C.nbyteslice{} + } + var ptr *C.jbyte + n := C.jsize(len(s)) + if cpy { + ptr = (*C.jbyte)(C.malloc(C.size_t(n))) + if ptr == nil { + panic("fromSlice: malloc failed") + } + copy((*[1<<31 - 1]byte)(unsafe.Pointer(ptr))[:n], s) + } else { + ptr = (*C.jbyte)(unsafe.Pointer(&s[0])) + } + return C.nbyteslice{ptr: unsafe.Pointer(ptr), len: n} +} + +// toSlice takes a nbyteslice (jbyteArray) and returns a byte slice +// with the data. If cpy is set, the slice contains a copy of the data and is +// freed. +func toSlice(s C.nbyteslice, cpy bool) []byte { + if s.ptr == nil || s.len == 0 { + return nil + } + var b []byte + if cpy { + b = C.GoBytes(s.ptr, C.int(s.len)) + C.free(s.ptr) + } else { + b = (*[1<<31 - 1]byte)(unsafe.Pointer(s.ptr))[:s.len:s.len] + } + return b +} diff --git a/bind/java/seq_android.h b/bind/java/seq_android.h deleted file mode 100644 index 5435baa..0000000 --- a/bind/java/seq_android.h +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2014 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. - -void init_seq(void* vm, void* classfinder); -JNIEnv *get_thread_env(void); -void recv(int32_t ref, int code, uint8_t *in_ptr, size_t in_len, uint8_t **out_ptr, size_t *out_len); diff --git a/bind/java/testpkg/testpkg.go b/bind/java/testpkg/testpkg.go index 089ae47..66f6f82 100644 --- a/bind/java/testpkg/testpkg.go +++ b/bind/java/testpkg/testpkg.go @@ -236,6 +236,14 @@ type NullTest interface { Null() NullTest } +func NewNullInterface() I { + return nil +} + +func NewNullStruct() *S { + return nil +} + func CallWithNull(_null NullTest, nuller NullTest) bool { return _null == nil && nuller.Null() == nil } @@ -243,3 +251,35 @@ func CallWithNull(_null NullTest, nuller NullTest) bool { type Issue14168 interface { F(seq int32) } + +func ReadIntoByteArray(s []byte) (int, error) { + if len(s) != cap(s) { + return 0, fmt.Errorf("cap %d != len %d", cap(s), len(s)) + } + for i := 0; i < len(s); i++ { + s[i] = byte(i) + } + return len(s), nil +} + +type B interface { + B(b []byte) +} + +func PassByteArray(b B) { + b.B([]byte{1, 2, 3, 4}) +} + +func GoroutineCallback(r Receiver) { + done := make(chan struct{}) + go func() { + // Run it multiple times to increase the chance that the goroutine + // will use different threads for the call. Use a long argument string to + // make sure the JNI calls take more time. + for i := 0; i < 100000; i++ { + r.Hello("HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello") + } + close(done) + }() + <-done +} diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m index 10b3541..e4feb6a 100644 --- a/bind/objc/SeqTest.m +++ b/bind/objc/SeqTest.m @@ -335,6 +335,89 @@ void testVar() { } } +// Objective-C implementation of testpkg.NullTest. +@interface NullTest : NSObject { +} + +- (GoTestpkgNullTest *)null; +@end + +@implementation NullTest { +} + +- (GoTestpkgNullTest *)null { + return nil; +} +@end + +void testNullReferences() { + NullTest *t = [[NullTest alloc] init]; + BOOL res = GoTestpkgCallWithNull(nil, t); + if (!res) { + ERROR(@"GoTestpkg.CallWithNull failed"); + } + id i = GoTestpkgNewNullInterface(); + if (i != nil) { + ERROR(@"NewNullInterface() returned %p; expected nil", i); + } + GoTestpkgS *s = GoTestpkgNewNullStruct(); + if (s != nil) { + ERROR(@"NewNullStruct() returned %p; expected nil", s); + } +} + +void testByteArrayRead() { + NSData *arr = [NSMutableData dataWithLength:8]; + int n; + BOOL success = GoTestpkgReadIntoByteArray(arr, &n, nil); + if (!success) { + ERROR(@"ReadIntoByteArray failed"); + } + if (n != 8) { + ERROR(@"ReadIntoByteArray wrote %d bytes, expected %d", n, 8); + } + const uint8_t *b = [arr bytes]; + for (int i = 0; i < [arr length]; i++) { + if (b[i] != i) { + ERROR(@"ReadIntoByteArray wrote %d at %d; expected %d", b[i], i, i); + } + } + // Test that immutable data cannot be changed from Go + const uint8_t buf[] = {42}; + arr = [NSData dataWithBytes:buf length:1]; + success = GoTestpkgReadIntoByteArray(arr, &n, nil); + if (!success) { + ERROR(@"ReadIntoByteArray failed"); + } + if (n != 1) { + ERROR(@"ReadIntoByteArray wrote %d bytes, expected %d", n, 8); + } + b = [arr bytes]; + if (b[0] != 42) { + ERROR(@"ReadIntoByteArray wrote to an immutable NSData; expected no change"); + } +} + +void testNilField() { + GoTestpkgNullFieldStruct *s = GoTestpkgNewNullFieldStruct(); + if ([s f] != nil) { + ERROR(@"NullFieldStruct has non-nil field; expected nil"); + } +} + +void testStringDup(NSString *want) { + NSString *got = GoTestpkgStringDup(want); + if (![want isEqualToString:got]) { + ERROR(@"StringDup returned %@; expected %@", got, want) + } +} + +void testUnicodeStrings() { + testStringDup(@"abcxyz09{}"); + testStringDup(@"Hello, 世界"); + testStringDup(@"\uffff\U00010000\U00010001\U00012345\U0010ffff"); +} + // Invokes functions and object methods defined in Testpkg.h. // // TODO(hyangah): apply testing framework (e.g. XCTestCase) @@ -361,7 +444,9 @@ int main(void) { testBytesAppend(@"Foo", @"Bar"); - testStruct(); + @autoreleasepool { + testStruct(); + } int numS = GoTestpkgCollectS( 1, 10); // within 10 seconds, collect the S used in testStruct. if (numS != 1) { @@ -384,6 +469,14 @@ int main(void) { testIssue12307(); testVar(); + + testNullReferences(); + + testByteArrayRead(); + + testNilField(); + + testUnicodeStrings(); } fprintf(stderr, "%s\n", err ? "FAIL" : "PASS"); diff --git a/bind/objc/seq.h b/bind/objc/seq.h index 53d55ae..8d1f23f 100644 --- a/bind/objc/seq.h +++ b/bind/objc/seq.h @@ -7,15 +7,21 @@ #include -// GoSeq is a sequence of machine-dependent encoded values, which -// is a simple C equivalent of seq.Buffer. -// Used by automatically generated language bindings to talk to Go. -typedef struct GoSeq { - uint8_t *buf; - size_t off; - size_t len; - size_t cap; -} GoSeq; +#ifdef DEBUG +#define LOG_DEBUG(...) NSLog(__VA_ARGS__); +#else +#define LOG_DEBUG(...) ; +#endif + +#define LOG_INFO(...) NSLog(__VA_ARGS__); +#define LOG_FATAL(...) \ + { \ + NSLog(__VA_ARGS__); \ + @throw \ + [NSException exceptionWithName:NSInternalInconsistencyException \ + reason:[NSString stringWithFormat:__VA_ARGS__] \ + userInfo:NULL]; \ + } // GoSeqRef is an object tagged with an integer for passing back and // forth across the language boundary. A GoSeqRef may represent either @@ -37,47 +43,35 @@ typedef struct GoSeq { @end -// go_seq_free releases resources of the GoSeq. -extern void go_seq_free(GoSeq *seq); +// Platform specific types +typedef struct nstring { + void *ptr; + int len; +} nstring; +typedef struct nbyteslice { + void *ptr; + int len; +} nbyteslice; +typedef int nint; -extern BOOL go_seq_readBool(GoSeq *seq); -extern int go_seq_readInt(GoSeq *seq); -extern int8_t go_seq_readInt8(GoSeq *seq); -extern int16_t go_seq_readInt16(GoSeq *seq); -extern int32_t go_seq_readInt32(GoSeq *seq); -extern int64_t go_seq_readInt64(GoSeq *seq); -extern float go_seq_readFloat32(GoSeq *seq); -extern double go_seq_readFloat64(GoSeq *seq); -extern GoSeqRef *go_seq_readRef(GoSeq *seq); -extern NSString *go_seq_readUTF8(GoSeq *seq); -extern NSData *go_seq_readByteArray(GoSeq *seq); +extern void init_seq(); +// go_seq_dec_ref decrements the reference count for the +// sepcified refnum. It is called from Go from a finalizer. +extern void go_seq_dec_ref(int32_t refnum); -extern void go_seq_writeBool(GoSeq *seq, BOOL v); -extern void go_seq_writeInt(GoSeq *seq, int v); -extern void go_seq_writeInt8(GoSeq *seq, int8_t v); -extern void go_seq_writeInt16(GoSeq *seq, int16_t v); -extern void go_seq_writeInt32(GoSeq *seq, int32_t v); -extern void go_seq_writeInt64(GoSeq *seq, int64_t v); -extern void go_seq_writeFloat32(GoSeq *seq, float v); -extern void go_seq_writeFloat64(GoSeq *seq, double v); -extern void go_seq_writeRef(GoSeq *seq, GoSeqRef *ref); -extern void go_seq_writeUTF8(GoSeq *seq, NSString *v); +extern int32_t go_seq_to_refnum(id obj); +// go_seq_go_to_refnum is a special case of go_seq_to_refnum +extern int32_t go_seq_go_to_refnum(GoSeqRef *ref); -// go_seq_writeByteArray writes the data bytes to the seq. Note that the -// data should be valid until the the subsequent go_seq_send call completes. -extern void go_seq_writeByteArray(GoSeq *seq, NSData *data); +extern GoSeqRef *go_seq_from_refnum(int32_t refnum); +// go_seq_objc_from_refnum is a special case of go_seq_from_refnum for +// Objective-C objects that implement a Go interface. +extern id go_seq_objc_from_refnum(int32_t refnum); -// go_seq_writeObjcRef is a special case of go_seq_writeRef for -// Objective-C objects that implement Go interface. -extern void go_seq_writeObjcRef(GoSeq *seq, id obj); +extern nbyteslice go_seq_from_objc_bytearray(NSData *data, int copy); +extern nstring go_seq_from_objc_string(NSString *s); -// go_seq_send sends a function invocation request to Go. -// It blocks until the function completes. -// If the request is for a method, the first element in req is -// a Ref to the receiver. -extern void go_seq_send(char *descriptor, int code, GoSeq *req, GoSeq *res); - -extern void go_seq_register_proxy(const char *descriptor, - void(*fn)(id, int, GoSeq *, GoSeq *)); +extern NSData *go_seq_to_objc_bytearray(nbyteslice, int copy); +extern NSString *go_seq_to_objc_string(nstring str); #endif // __GO_SEQ_HDR__ diff --git a/bind/objc/seq_darwin.go b/bind/objc/seq_darwin.go deleted file mode 100644 index bb34850..0000000 --- a/bind/objc/seq_darwin.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2015 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 objc - -/* -#cgo CFLAGS: -x objective-c -fobjc-arc -#cgo LDFLAGS: -framework Foundation - -#include -#include -#include - -void init_seq(); -void go_seq_recv(int32_t, const char*, int, uint8_t*, size_t, uint8_t**, size_t*); -*/ -import "C" - -import ( - "fmt" - "sync" - "unsafe" - - "golang.org/x/mobile/bind/seq" -) - -const debug = false - -const maxSliceLen = 1<<31 - 1 - -// Send is called by Objective-C to send a request to run a Go function. -//export Send -func Send(descriptor string, code int, req *C.uint8_t, reqlen C.size_t, res **C.uint8_t, reslen *C.size_t) { - fn := seq.Registry[descriptor][code] - if fn == nil { - panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code)) - } - var in, out *seq.Buffer - if reqlen > 0 { - in = &seq.Buffer{Data: (*[maxSliceLen]byte)(unsafe.Pointer(req))[:reqlen]} - } - if reslen != nil { - out = new(seq.Buffer) - } - - fn(out, in) - if out != nil { - // sender expects results. - seqToBuf(res, reslen, out) - } -} - -// DestroyRef is called by Objective-C to inform Go it is done with a reference. -//export DestroyRef -func DestroyRef(refnum C.int32_t) { - seq.Delete(int32(refnum)) -} - -type request struct { - ref *seq.Ref - handle int32 - code int - in *seq.Buffer -} - -var recv struct { - sync.Mutex - cond sync.Cond // signals req is not empty - req []request - next int32 // next handle value -} - -var res struct { - sync.Mutex - cond sync.Cond // signals a response is filled in - out map[int32]*seq.Buffer // handle -> output -} - -func init() { - recv.cond.L = &recv.Mutex - recv.next = 411 // arbitrary starting point distrinct from Go and Objective-C object ref nums. - res.cond.L = &res.Mutex - res.out = make(map[int32]*seq.Buffer) -} - -func seqToBuf(bufptr **C.uint8_t, lenptr *C.size_t, buf *seq.Buffer) { - if debug { - fmt.Printf("seqToBuf tag 1, len(buf.Data)=%d, *lenptr=%d\n", len(buf.Data), *lenptr) - } - if len(buf.Data) == 0 { - *lenptr = 0 - return - } - if len(buf.Data) > int(*lenptr) { - // TODO(crawshaw): realloc - C.free(unsafe.Pointer(*bufptr)) - m := C.malloc(C.size_t(len(buf.Data))) - if uintptr(m) == 0 { - panic(fmt.Sprintf("malloc failed, size=%d", len(buf.Data))) - } - *bufptr = (*C.uint8_t)(m) - *lenptr = C.size_t(len(buf.Data)) - } - C.memcpy(unsafe.Pointer(*bufptr), unsafe.Pointer(&buf.Data[0]), C.size_t(len(buf.Data))) -} - -type cStringMap struct { - sync.Mutex - m map[string]*C.char -} - -var cstrings = &cStringMap{ - m: make(map[string]*C.char), -} - -func (s *cStringMap) get(k string) *C.char { - s.Lock() - c, ok := s.m[k] - if !ok { - c = C.CString(k) - s.m[k] = c - } - s.Unlock() - return c -} - -// transact calls a method on an Objective-C object instance. -// It blocks until the call is complete. -// -// Code (>0) is the method id assigned by gobind. -// Code -1 is used to instruct Objective-C to decrement the ref count of -// the Objective-Co object. -func transact(ref *seq.Ref, descriptor string, code int, in *seq.Buffer) *seq.Buffer { - var ( - res *C.uint8_t = nil - resLen C.size_t = 0 - req *C.uint8_t = nil - reqLen C.size_t = 0 - ) - - if len(in.Data) > 0 { - req = (*C.uint8_t)(unsafe.Pointer(&in.Data[0])) - reqLen = C.size_t(len(in.Data)) - } - - if debug { - fmt.Printf("transact: ref.Num = %d code = %d\n", ref.Num, code) - } - - desc := cstrings.get(descriptor) - C.go_seq_recv(C.int32_t(ref.Num), desc, C.int(code), req, reqLen, &res, &resLen) - - if resLen > 0 { - goSlice := (*[maxSliceLen]byte)(unsafe.Pointer(res))[:resLen] - out := new(seq.Buffer) - out.Data = make([]byte, int(resLen)) - copy(out.Data, goSlice) - C.free(unsafe.Pointer(res)) - // TODO: own or copy []bytes whose addresses were passed in. - return out - } - return nil -} - -// finalizeRef notifies Objective-C side of GC of a proxy object from Go side. -func finalizeRef(ref *seq.Ref) { - if ref.Num < 0 { - panic(fmt.Sprintf("not an Objective-C ref: %d", ref.Num)) - } - transact(ref, "", -1, new(seq.Buffer)) -} - -func init() { - seq.EncString = func(out *seq.Buffer, v string) { - out.WriteUTF8(v) - } - seq.DecString = func(in *seq.Buffer) string { - return in.ReadUTF8() - } - seq.Transact = transact - seq.FinalizeRef = finalizeRef - - C.init_seq() -} diff --git a/bind/objc/seq_darwin.go.support b/bind/objc/seq_darwin.go.support new file mode 100644 index 0000000..a494084 --- /dev/null +++ b/bind/objc/seq_darwin.go.support @@ -0,0 +1,94 @@ +// 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 gomobile_bind + +// Go support functions for Objective-C. Note that this +// file is copied into and compiled with the generated +// bindings. + +/* +#cgo CFLAGS: -x objective-c -fobjc-arc +#cgo LDFLAGS: -framework Foundation + +#include +#include +#include "seq.h" +*/ +import "C" + +import ( + "unsafe" + + "golang.org/x/mobile/bind/seq" +) + +// DestroyRef is called by Objective-C to inform Go it is done with a reference. +//export DestroyRef +func DestroyRef(refnum C.int32_t) { + seq.Delete(int32(refnum)) +} + +// encodeString copies a Go string and returns it as a nstring. +// The result is always a copy, because go_seq_to_objc_string +// uses NSString initWithBytesNoCopy to another copy. +func encodeString(s string, cpy bool) C.nstring { + n := C.int(len(s)) + if n == 0 { + return C.nstring{} + } + ptr := C.malloc(C.size_t(n)) + if ptr == nil { + panic("encodeString: malloc failed") + } + copy((*[1<<31 - 1]byte)(ptr)[:n], s) + return C.nstring{ptr: ptr, len: n} +} + +// decodeString converts a nstring to a Go string. +// The data in str is always a copy, so cpy is ignored +// and the data is always freed. +func decodeString(str C.nstring, cpy bool) string { + if str.ptr == nil { + return "" + } + s := C.GoStringN((*C.char)(str.ptr), str.len) + C.free(str.ptr) + return s +} + +// fromSlice converts a slice to a nbyteslice. +// If cpy is set, a malloc'ed copy of the data is returned. +func fromSlice(s []byte, cpy bool) C.nbyteslice { + if s == nil || len(s) == 0 { + return C.nbyteslice{} + } + ptr, n := unsafe.Pointer(&s[0]), C.int(len(s)) + if cpy { + nptr := C.malloc(C.size_t(n)) + if nptr == nil { + panic("fromSlice: malloc failed") + } + copy((*[1<<31 - 1]byte)(nptr)[:n], (*[1<<31 - 1]byte)(ptr)[:n]) + ptr = nptr + } + return C.nbyteslice{ptr: ptr, len: n} +} + +// toSlice takes a nbyteslice and returns a byte slice with the data. If cpy is +// set, the slice contains a copy of the data. If not, the generated Go code +// calls releaseByteSlice after use. +func toSlice(s C.nbyteslice, cpy bool) []byte { + if s.ptr == nil || s.len == 0 { + return nil + } + var b []byte + if cpy { + b = C.GoBytes(s.ptr, C.int(s.len)) + C.free(s.ptr) + } else { + b = (*[1<<31 - 1]byte)(unsafe.Pointer(s.ptr))[:s.len:s.len] + } + return b +} diff --git a/bind/objc/seq_darwin.m b/bind/objc/seq_darwin.m deleted file mode 100644 index a87d7a5..0000000 --- a/bind/objc/seq_darwin.m +++ /dev/null @@ -1,527 +0,0 @@ -// Copyright 2015 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. - -#include -#include -#include -#include -#include "seq.h" -#include "_cgo_export.h" - -#ifdef DEBUG -#define LOG_DEBUG(...) NSLog(__VA_ARGS__); -#else -#define LOG_DEBUG(...) ; -#endif - -#define LOG_INFO(...) NSLog(__VA_ARGS__); -#define LOG_FATAL(...) \ - { \ - NSLog(__VA_ARGS__); \ - @throw \ - [NSException exceptionWithName:NSInternalInconsistencyException \ - reason:[NSString stringWithFormat:__VA_ARGS__] \ - userInfo:NULL]; \ - } - -// * Objective-C implementation of a Go interface type -// -// For an interface testpkg.I, gobind defines a protocol GoSeqTestpkgI. -// Reference tracker (tracker) maintains two maps: -// 1) _refs: objective-C object pointer -> a refnum (starting from 42). -// 2) _objs: refnum -> RefCounter. -// -// Whenever a user's object conforming the protocol is sent to Go (through -// a function or method that takes I), _refs is consulted to find the refnum -// of the object. If not found, the refnum is assigned and stored. -// -// _objs is also updated so that the RefCounter is incremented and the -// user's object is pinned. -// -// When a Go side needs to call a method of the interface, the Go side -// notifies the Objective-C side of the object's refnum, and the method code -// as gobind assigned. Upon receiving the request, Objective-C side looks -// up the object from _objs map, and looks up the proxy global function -// registered in 'proxies'. The global function deserializes/serializes -// the parameters and sends the method to the object. -// -// The RefCount counts the references on objective-C objects from Go side, -// and pins the objective-C objects until there is no more reference from -// Go side. -// -// * Objective-C proxy of a Go object (struct or interface type) -// -// For Go type object, a objective-C proxy instance is created whenever -// the object reference is passed into objective-C. - -// A simple thread-safe mutable dictionary. -@interface goSeqDictionary : NSObject { -} -@property NSMutableDictionary *dict; -@end - -@implementation goSeqDictionary - -- (id)init { - if (self = [super init]) { - _dict = [[NSMutableDictionary alloc] init]; - } - return self; -} - -- (id)get:(id)key { - @synchronized(self) { - return [_dict objectForKey:key]; - } -} - -- (void)put:(id)obj withKey:(id)key { - @synchronized(self) { - [_dict setObject:obj forKey:key]; - } -} -@end - -// The proxies maps Go interface name (e.g. go.testpkg.I) to the proxy function -// gobind generates for interfaces defined in a module. The function is -// registered by calling go_seq_register_proxy from a global contructor funcion. -static goSeqDictionary *proxies = NULL; - -void go_seq_register_proxy(const char *descriptor, - void (*fn)(id, int, GoSeq *, GoSeq *)) { - if (proxies == NULL) { - proxies = [[goSeqDictionary alloc] init]; - } - // Copying moves the block to the heap. - id block = [^(id obj, int code, GoSeq *in, GoSeq *out) { - fn(obj, code, in, out); - } copy]; - - [proxies put:block withKey:[NSString stringWithUTF8String:descriptor]]; -} - -// RefTracker encapsulates a map of objective-C objects passed to Go and -// the reference number counter which is incremented whenever an objective-C -// object that implements a Go interface is created. -@interface RefTracker : NSObject { - int32_t _next; - NSMutableDictionary *_refs; // map: object ptr -> refnum - NSMutableDictionary *_objs; // map: refnum -> RefCounter* -} - -- (id)init; - -// decrements the counter of the objective-C object with the reference number. -// This is called whenever a Go proxy to this object is finalized. -// When the counter reaches 0, the object is removed from the map. -- (void)dec:(int32_t)refnum; - -// returns the object of the reference number. -- (id)get:(int32_t)refnum; - -// returns the reference number of the object and increments the ref count. -// This is called whenever an Objective-C object is sent to Go side. -- (int32_t)assignRefnumAndIncRefcount:(id)obj; -@end - -RefTracker *tracker = NULL; - -// mem_ensure ensures that m has at least size bytes free. -// If m is NULL, it is created. -static void mem_ensure(GoSeq *m, uint32_t size) { - size_t cap = m->cap; - if (cap > m->off + size) { - return; - } - if (cap == 0) { - cap = 64; - } - while (cap < m->off + size) { - cap *= 2; - } - m->buf = (uint8_t *)realloc((void *)m->buf, cap); - if (m->buf == NULL) { - LOG_FATAL(@"mem_ensure realloc failed, off=%zu, size=%u", m->off, size); - } - m->cap = cap; -} - -static uint32_t align(uint32_t offset, uint32_t alignment) { - uint32_t pad = offset % alignment; - if (pad > 0) { - pad = alignment - pad; - } - return pad + offset; -} - -static uint8_t *mem_read(GoSeq *m, uint32_t size, uint32_t alignment) { - if (size == 0) { - return NULL; - } - if (m == NULL) { - LOG_FATAL(@"mem_read on NULL GoSeq"); - } - uint32_t offset = align(m->off, alignment); - - if (m->len - offset < size) { - LOG_FATAL(@"short read"); - } - uint8_t *res = m->buf + offset; - m->off = offset + size; - return res; -} - -static uint8_t *mem_write(GoSeq *m, uint32_t size, uint32_t alignment) { - if (m->off != m->len) { - LOG_FATAL(@"write can only append to seq, size: (off=%zu len=%zu, size=%u)", - m->off, m->len, size); - } - uint32_t offset = align(m->off, alignment); - mem_ensure(m, offset - m->off + size); - uint8_t *res = m->buf + offset; - m->off = offset + size; - m->len = offset + size; - return res; -} - -// extern -void go_seq_free(GoSeq *m) { - if (m != NULL) { - free(m->buf); - } -} - -#define MEM_READ(seq, ty) ((ty *)mem_read(seq, sizeof(ty), sizeof(ty))) -#define MEM_WRITE(seq, ty) (*(ty *)mem_write(seq, sizeof(ty), sizeof(ty))) - -int go_seq_readInt(GoSeq *seq) { - int64_t v = go_seq_readInt64(seq); - return v; // Assume that Go-side used WriteInt to encode 'int' value. -} - -void go_seq_writeInt(GoSeq *seq, int v) { go_seq_writeInt64(seq, v); } - -BOOL go_seq_readBool(GoSeq *seq) { - int8_t v = go_seq_readInt8(seq); - return v ? YES : NO; -} - -void go_seq_writeBool(GoSeq *seq, BOOL v) { go_seq_writeInt8(seq, v ? 1 : 0); } - -int8_t go_seq_readInt8(GoSeq *seq) { - int8_t *v = MEM_READ(seq, int8_t); - return v == NULL ? 0 : *v; -} -void go_seq_writeInt8(GoSeq *seq, int8_t v) { MEM_WRITE(seq, int8_t) = v; } - -int16_t go_seq_readInt16(GoSeq *seq) { - int16_t *v = MEM_READ(seq, int16_t); - return v == NULL ? 0 : *v; -} -void go_seq_writeInt16(GoSeq *seq, int16_t v) { MEM_WRITE(seq, int16_t) = v; } - -int32_t go_seq_readInt32(GoSeq *seq) { - int32_t *v = MEM_READ(seq, int32_t); - return v == NULL ? 0 : *v; -} -void go_seq_writeInt32(GoSeq *seq, int32_t v) { MEM_WRITE(seq, int32_t) = v; } - -int64_t go_seq_readInt64(GoSeq *seq) { - int64_t *v = MEM_READ(seq, int64_t); - return v == NULL ? 0 : *v; -} -void go_seq_writeInt64(GoSeq *seq, int64_t v) { MEM_WRITE(seq, int64_t) = v; } - -float go_seq_readFloat32(GoSeq *seq) { - float *v = MEM_READ(seq, float); - return v == NULL ? 0 : *v; -} -void go_seq_writeFloat32(GoSeq *seq, float v) { MEM_WRITE(seq, float) = v; } - -double go_seq_readFloat64(GoSeq *seq) { - double *v = MEM_READ(seq, double); - return v == NULL ? 0 : *v; -} -void go_seq_writeFloat64(GoSeq *seq, double v) { MEM_WRITE(seq, double) = v; } - -NSString *go_seq_readUTF8(GoSeq *seq) { - int32_t len = *MEM_READ(seq, int32_t); - if (len == 0) { // empty string. - return @""; - } - const void *buf = (const void *)mem_read(seq, len, 1); - return [[NSString alloc] initWithBytes:buf - length:len - encoding:NSUTF8StringEncoding]; -} - -void go_seq_writeUTF8(GoSeq *seq, NSString *s) { - int32_t len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - MEM_WRITE(seq, int32_t) = len; - - if (len == 0 && s.length > 0) { - LOG_INFO(@"unable to incode an NSString into UTF-8"); - return; - } - - char *buf = (char *)mem_write(seq, len, 1); - NSUInteger used; - [s getBytes:buf - maxLength:len - usedLength:&used - encoding:NSUTF8StringEncoding - options:0 - range:NSMakeRange(0, [s length]) - remainingRange:NULL]; - if (used < len) { - buf[used] = '\0'; - } - return; -} - -NSData *go_seq_readByteArray(GoSeq *seq) { - int64_t sz = *MEM_READ(seq, int64_t); - if (sz == 0) { - return [NSData data]; - } - // BUG(hyangah): it is possible that *ptr is already GC'd by Go runtime. - void *ptr = (void *)(*MEM_READ(seq, int64_t)); - return [NSData dataWithBytes:ptr length:sz]; -} - -void go_seq_writeByteArray(GoSeq *seq, NSData *data) { - int64_t sz = data.length; - MEM_WRITE(seq, int64_t) = sz; - if (sz == 0) { - return; - } - - int64_t ptr = (int64_t)data.bytes; - MEM_WRITE(seq, int64_t) = ptr; - return; -} - -typedef void (^proxyFn)(id, int, GoSeq *, GoSeq *); - -// called from Go when Go tries to access an Objective-C object. -void go_seq_recv(int32_t refnum, const char *desc, int code, uint8_t *in_ptr, - size_t in_len, uint8_t **out_ptr, size_t *out_len) { - if (code == -1) { // special signal from seq.FinalizeRef in Go - [tracker dec:refnum]; - return; - } - GoSeq ins = {}; - ins.buf = in_ptr; // Memory allocated from Go - ins.off = 0; - ins.len = in_len; - ins.cap = in_len; - id obj = [tracker get:refnum]; - if (obj == NULL) { - LOG_FATAL(@"invalid object for ref %d", refnum); - return; - } - - NSString *k = [NSString stringWithUTF8String:desc]; - - proxyFn fn = NULL; - if (proxies != NULL) { - fn = [proxies get:k]; - } - if (fn == NULL) { - LOG_FATAL(@"cannot find a proxy function for %s", desc); - return; - } - GoSeq outs = {}; - fn(obj, code, &ins, &outs); - - if (out_ptr == NULL) { - free(outs.buf); - } else { - *out_ptr = outs.buf; // Let Go side free this memory - *out_len = outs.len; - } -} - -void go_seq_send(char *descriptor, int code, GoSeq *req, GoSeq *res) { - if (descriptor == NULL) { - LOG_FATAL(@"invalid NULL descriptor"); - } - uint8_t *req_buf = NULL; - size_t req_len = 0; - if (req != NULL) { - req_buf = req->buf; - req_len = req->len; - } - - uint8_t **res_buf = NULL; - size_t *res_len = NULL; - if (res != NULL) { - res_buf = &res->buf; - res_len = &res->len; - } - - GoString desc; - desc.p = descriptor; - desc.n = strlen(descriptor); - Send(desc, (GoInt)code, req_buf, req_len, res_buf, res_len); -} - -#define IS_FROM_GO(refnum) ((refnum) < 0) - -// init_seq is called when the Go side is initialized. -void init_seq() { tracker = [[RefTracker alloc] init]; } - -GoSeqRef *go_seq_readRef(GoSeq *seq) { - int32_t refnum = go_seq_readInt32(seq); - if (IS_FROM_GO(refnum)) { - return [[GoSeqRef alloc] initWithRefnum:refnum obj:NULL]; - } - return [[GoSeqRef alloc] initWithRefnum:refnum obj:[tracker get:refnum]]; -} - -// TODO(hyangah): make this go_seq_writeRef(GoSeq *seq, int32_t refnum, id obj) -// and get read of GoSeqRef. -void go_seq_writeRef(GoSeq *seq, GoSeqRef *v) { - int32_t refnum = v.refnum; - if (!IS_FROM_GO(refnum)) { - LOG_FATAL(@"go_seq_writeRef on objective-c objects is not permitted"); - } - go_seq_writeInt32(seq, refnum); - return; -} - -void go_seq_writeObjcRef(GoSeq *seq, id obj) { - int32_t refnum = [tracker assignRefnumAndIncRefcount:obj]; - go_seq_writeInt32(seq, refnum); -} - -@implementation GoSeqRef { -} - -- (id)init { - LOG_FATAL(@"GoSeqRef init is disallowed"); - return nil; -} - -// called when an object from Go is passed in. -- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj { - self = [super init]; - if (self) { - _refnum = refnum; - _obj = obj; - } - return self; -} - -- (void)dealloc { - if (IS_FROM_GO(_refnum)) { - DestroyRef(_refnum); - } -} -@end - -// RefCounter is a pair of (GoSeqProxy, count). GoSeqProxy has a strong -// reference to an Objective-C object. The count corresponds to -// the number of Go proxy objects. -// -// RefTracker maintains a map of refnum to RefCounter, for every -// Objective-C objects passed to Go. This map allows the transact -// call to relay the method call to the right Objective-C object, and -// prevents the Objective-C objects from being deallocated -// while they are still referenced from Go side. -@interface RefCounter : NSObject { -} -@property(strong, readonly) id obj; -@property int cnt; - -- (id)initWithObject:(id)obj; -@end - -@implementation RefCounter { -} -- (id)initWithObject:(id)obj { - self = [super init]; - if (self) { - _obj = obj; - _cnt = 0; - } - return self; -} - -@end - -@implementation RefTracker { -} - -- (id)init { - self = [super init]; - if (self) { - _next = 42; - _objs = [[NSMutableDictionary alloc] init]; - } - return self; -} - -- (void)dec:(int32_t)refnum { // called whenever a go proxy object is finalized. - if (IS_FROM_GO(refnum)) { - LOG_FATAL(@"dec:invalid refnum for Objective-C objects"); - return; - } - @synchronized(self) { - id key = @(refnum); - RefCounter *counter = [_objs objectForKey:key]; - if (counter == NULL) { - LOG_FATAL(@"unknown refnum"); - return; - } - int n = counter.cnt; - if (n <= 0) { - LOG_FATAL(@"refcount underflow"); - } else if (n == 1) { - LOG_DEBUG(@"remove the reference %d", refnum); - NSValue *ptr = [NSValue valueWithPointer:(const void *)(counter.obj)]; - [_refs removeObjectForKey:ptr]; - [_objs removeObjectForKey:key]; - } else { - counter.cnt = n - 1; - } - } -} - -- (id)get:(int32_t)refnum { - if (IS_FROM_GO(refnum)) { - LOG_FATAL(@"get:invalid refnum for Objective-C objects"); - return NULL; - } - @synchronized(self) { - RefCounter *counter = _objs[@(refnum)]; - if (counter == NULL) { - LOG_FATAL(@"unidentified object refnum: %d", refnum); - return NULL; - } - return counter.obj; - } -} - -- (int32_t)assignRefnumAndIncRefcount:(id)obj { - @synchronized(self) { - NSValue *ptr = [NSValue valueWithPointer:(const void *)(obj)]; - NSNumber *refnum = [_refs objectForKey:ptr]; - if (refnum == NULL) { - refnum = @(_next++); - _refs[ptr] = refnum; - } - RefCounter *counter = [_objs objectForKey:refnum]; - if (counter == NULL) { - counter = [[RefCounter alloc] initWithObject:obj]; - counter.cnt = 1; - _objs[refnum] = counter; - } else { - counter.cnt++; - } - return (int32_t)([refnum intValue]); - } -} - -@end diff --git a/bind/objc/seq_darwin.m.support b/bind/objc/seq_darwin.m.support new file mode 100644 index 0000000..1e6482c --- /dev/null +++ b/bind/objc/seq_darwin.m.support @@ -0,0 +1,340 @@ +// 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. + +#include +#include +#include +#include +#include "seq.h" +#include "_cgo_export.h" + +// * Objective-C implementation of a Go interface type +// +// For an interface testpkg.I, gobind defines a protocol GoSeqTestpkgI. +// Reference tracker (tracker) maintains two maps: +// 1) _refs: objective-C object pointer -> a refnum (starting from 42). +// 2) _objs: refnum -> RefCounter. +// +// Whenever a user's object conforming the protocol is sent to Go (through +// a function or method that takes I), _refs is consulted to find the refnum +// of the object. If not found, the refnum is assigned and stored. +// +// _objs is also updated so that the RefCounter is incremented and the +// user's object is pinned. +// +// When a Go side needs to call a method of the interface, the Go side +// notifies the Objective-C side of the object's refnum. Upon receiving the +// request, Objective-C side looks up the object from _objs map, and sends +// the method to the object. +// +// The RefCount counts the references on objective-C objects from Go side, +// and pins the objective-C objects until there is no more references from +// Go side. +// +// * Objective-C proxy of a Go object (struct or interface type) +// +// For Go type object, a objective-C proxy instance is created whenever +// the object reference is passed into objective-C. + +// Note that this file is copied into and compiled with the generated +// bindings. + +// A simple thread-safe mutable dictionary. +@interface goSeqDictionary : NSObject { +} +@property NSMutableDictionary *dict; +@end + +@implementation goSeqDictionary + +- (id)init { + if (self = [super init]) { + _dict = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (id)get:(id)key { + @synchronized(self) { + return [_dict objectForKey:key]; + } +} + +- (void)put:(id)obj withKey:(id)key { + @synchronized(self) { + [_dict setObject:obj forKey:key]; + } +} +@end + +// NULL_REFNUM is also known to bind/seq/ref.go and bind/java/Seq.java +#define NULL_REFNUM 41 + +// RefTracker encapsulates a map of objective-C objects passed to Go and +// the reference number counter which is incremented whenever an objective-C +// object that implements a Go interface is created. +@interface RefTracker : NSObject { + int32_t _next; + NSMutableDictionary *_refs; // map: object ptr -> refnum + NSMutableDictionary *_objs; // map: refnum -> RefCounter* +} + +- (id)init; + +// decrements the counter of the objective-C object with the reference number. +// This is called whenever a Go proxy to this object is finalized. +// When the counter reaches 0, the object is removed from the map. +- (void)dec:(int32_t)refnum; + +// returns the object of the reference number. +- (id)get:(int32_t)refnum; + +// returns the reference number of the object and increments the ref count. +// This is called whenever an Objective-C object is sent to Go side. +- (int32_t)assignRefnumAndIncRefcount:(id)obj; +@end + +static RefTracker *tracker = NULL; + +#define IS_FROM_GO(refnum) ((refnum) < 0) + +// init_seq is called when the Go side is initialized. +void init_seq() { tracker = [[RefTracker alloc] init]; } + +void go_seq_dec_ref(int32_t refnum) { + [tracker dec:refnum]; +} + +NSData *go_seq_to_objc_bytearray(nbyteslice s, int copy) { + if (s.ptr == NULL) { + return NULL; + } + BOOL freeWhenDone = copy ? YES : NO; + return [NSData dataWithBytesNoCopy:s.ptr length:s.len freeWhenDone:freeWhenDone]; +} + +NSString *go_seq_to_objc_string(nstring str) { + if (str.len == 0) { // empty string. + return @""; + } + NSString * res = [[NSString alloc] initWithBytesNoCopy:str.ptr + length:str.len + encoding:NSUTF8StringEncoding + freeWhenDone:YES]; + return res; +} + +id go_seq_objc_from_refnum(int32_t refnum) { + return [tracker get:refnum]; +} + +GoSeqRef *go_seq_from_refnum(int32_t refnum) { + if (refnum == NULL_REFNUM) { + return nil; + } + if (IS_FROM_GO(refnum)) { + return [[GoSeqRef alloc] initWithRefnum:refnum obj:NULL]; + } + return [[GoSeqRef alloc] initWithRefnum:refnum obj:go_seq_objc_from_refnum(refnum)]; +} + +int32_t go_seq_to_refnum(id obj) { + if (obj == nil) { + return NULL_REFNUM; + } + return [tracker assignRefnumAndIncRefcount:obj]; +} + +int32_t go_seq_go_to_refnum(GoSeqRef *ref) { + int32_t refnum = ref.refnum; + if (!IS_FROM_GO(refnum)) { + LOG_FATAL(@"go_seq_go_to_refnum on objective-c objects is not permitted"); + } + return refnum; +} + +nbyteslice go_seq_from_objc_bytearray(NSData *data, int copy) { + struct nbyteslice res = {NULL, 0, NO}; + int sz = data.length; + if (sz == 0) { + return res; + } + void *ptr; + // If the argument was not a NSMutableData, copy the data so that + // the NSData is not changed from Go. The corresponding free is called + // by releaseByteSlice. + if (copy || ![data isKindOfClass:[NSMutableData class]]) { + void *arr_copy = malloc(sz); + if (arr_copy == NULL) { + LOG_FATAL(@"malloc failed"); + return res; + } + memcpy(arr_copy, [data bytes], sz); + ptr = arr_copy; + } else { + ptr = (void *)[data bytes]; + } + res.ptr = ptr; + res.len = sz; + return res; +} + +nstring go_seq_from_objc_string(NSString *s) { + nstring res = {NULL, 0}; + int len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + if (len == 0) { + if (s.length > 0) { + LOG_INFO(@"unable to encode an NSString into UTF-8"); + } + return res; + } + + char *buf = (char *)malloc(len); + if (buf == NULL) { + LOG_FATAL(@"malloc failed"); + return res; + } + NSUInteger used; + [s getBytes:buf + maxLength:len + usedLength:&used + encoding:NSUTF8StringEncoding + options:0 + range:NSMakeRange(0, [s length]) + remainingRange:NULL]; + res.ptr = buf; + res.len = used; + return res; +} + +@implementation GoSeqRef { +} + +- (id)init { + LOG_FATAL(@"GoSeqRef init is disallowed"); + return nil; +} + +// called when an object from Go is passed in. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj { + self = [super init]; + if (self) { + _refnum = refnum; + _obj = obj; + } + return self; +} + +- (void)dealloc { + if (IS_FROM_GO(_refnum)) { + DestroyRef(_refnum); + } +} +@end + +// RefCounter is a pair of (GoSeqProxy, count). GoSeqProxy has a strong +// reference to an Objective-C object. The count corresponds to +// the number of Go proxy objects. +// +// RefTracker maintains a map of refnum to RefCounter, for every +// Objective-C objects passed to Go. This map allows the transact +// call to relay the method call to the right Objective-C object, and +// prevents the Objective-C objects from being deallocated +// while they are still referenced from Go side. +@interface RefCounter : NSObject { +} +@property(strong, readonly) id obj; +@property int cnt; + +- (id)initWithObject:(id)obj; +@end + +@implementation RefCounter { +} +- (id)initWithObject:(id)obj { + self = [super init]; + if (self) { + _obj = obj; + _cnt = 0; + } + return self; +} + +@end + +@implementation RefTracker { +} + +- (id)init { + self = [super init]; + if (self) { + _next = 42; + _objs = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)dec:(int32_t)refnum { // called whenever a go proxy object is finalized. + if (IS_FROM_GO(refnum)) { + LOG_FATAL(@"dec:invalid refnum for Objective-C objects"); + return; + } + @synchronized(self) { + id key = @(refnum); + RefCounter *counter = [_objs objectForKey:key]; + if (counter == NULL) { + LOG_FATAL(@"unknown refnum"); + return; + } + int n = counter.cnt; + if (n <= 0) { + LOG_FATAL(@"refcount underflow"); + } else if (n == 1) { + LOG_DEBUG(@"remove the reference %d", refnum); + NSValue *ptr = [NSValue valueWithPointer:(const void *)(counter.obj)]; + [_refs removeObjectForKey:ptr]; + [_objs removeObjectForKey:key]; + } else { + counter.cnt = n - 1; + } + } +} + +- (id)get:(int32_t)refnum { + if (IS_FROM_GO(refnum)) { + LOG_FATAL(@"get:invalid refnum for Objective-C objects"); + return NULL; + } + @synchronized(self) { + RefCounter *counter = _objs[@(refnum)]; + if (counter == NULL) { + LOG_FATAL(@"unidentified object refnum: %d", refnum); + return NULL; + } + return counter.obj; + } +} + +- (int32_t)assignRefnumAndIncRefcount:(id)obj { + @synchronized(self) { + NSValue *ptr = [NSValue valueWithPointer:(const void *)(obj)]; + NSNumber *refnum = [_refs objectForKey:ptr]; + if (refnum == NULL) { + refnum = @(_next++); + _refs[ptr] = refnum; + } + RefCounter *counter = [_objs objectForKey:refnum]; + if (counter == NULL) { + counter = [[RefCounter alloc] initWithObject:obj]; + counter.cnt = 1; + _objs[refnum] = counter; + } else { + counter.cnt++; + } + return (int32_t)([refnum intValue]); + } +} + +@end diff --git a/bind/objc/test.bash b/bind/objc/test.bash index 2f114f9..dc27637 100755 --- a/bind/objc/test.bash +++ b/bind/objc/test.bash @@ -20,12 +20,15 @@ trap cleanup EXIT (cd testpkg; go generate) -go build -x -v -buildmode=c-archive -o=${WORK}/libgo.a test_main.go -cp ./seq.h ${WORK}/ -cp testpkg/objc_testpkg/GoTestpkg.* ${WORK}/ +cp ./seq.h ./testpkg/go_testpkg +cp ./seq_darwin.m.support ./testpkg/go_testpkg/seq_darwin.m +cp ./seq_darwin.go.support ./testpkg/go_testpkg/seq_darwin.go +cp ../seq.go.support ./testpkg/go_testpkg/seq.go +go build -x -v -buildmode=c-archive -ldflags="$ccargs" -o=${WORK}/libgo.a test_main.go +cp testpkg/go_testpkg/GoTestpkg.h ${WORK}/ cp ./SeqTest.m ${WORK}/ ccargs="-Wl,-no_pie -framework Foundation -fobjc-arc" -$(go env CC) $(go env GOGCCFLAGS) $ccargs -o ${WORK}/a.out ${WORK}/libgo.a ${WORK}/GoTestpkg.m ${WORK}/SeqTest.m +$(go env CC) $(go env GOGCCFLAGS) $ccargs -o ${WORK}/a.out ${WORK}/libgo.a ${WORK}/SeqTest.m ${WORK}/a.out diff --git a/bind/objc/test_main.go b/bind/objc/test_main.go index ccf4e98..b4bed18 100644 --- a/bind/objc/test_main.go +++ b/bind/objc/test_main.go @@ -10,7 +10,6 @@ package main import "C" import ( - _ "golang.org/x/mobile/bind/objc" _ "golang.org/x/mobile/bind/objc/testpkg/go_testpkg" ) diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h b/bind/objc/testpkg/go_testpkg/GoTestpkg.h similarity index 80% rename from bind/objc/testpkg/objc_testpkg/GoTestpkg.h rename to bind/objc/testpkg/go_testpkg/GoTestpkg.h index 1164f53..2712fb4 100644 --- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h +++ b/bind/objc/testpkg/go_testpkg/GoTestpkg.h @@ -9,10 +9,13 @@ #include @class GoTestpkgNode; +@class GoTestpkgNullFieldStruct; @class GoTestpkgS; @class GoTestpkgStructThatStartsWithLetterBeforeZ; @protocol GoTestpkgI; @class GoTestpkgI; +@protocol GoTestpkgNullTest; +@class GoTestpkgNullTest; @protocol GoTestpkgZ; @class GoTestpkgZ; @@ -27,6 +30,15 @@ - (void)setErr:(NSString*)v; @end +@interface GoTestpkgNullFieldStruct : NSObject { +} +@property(strong, readonly) id _ref; + +- (id)initWithRef:(id)ref; +- (GoTestpkgS*)f; +- (void)setF:(GoTestpkgS*)v; +@end + @interface GoTestpkgS : NSObject { } @property(strong, readonly) id _ref; @@ -55,11 +67,16 @@ - (int64_t)times:(int32_t)v; @end +@protocol GoTestpkgNullTest +- (id)null; +@end + @protocol GoTestpkgZ @end FOUNDATION_EXPORT const BOOL GoTestpkgABool; FOUNDATION_EXPORT const double GoTestpkgAFloat; +FOUNDATION_EXPORT NSString* const GoTestpkgALongString; FOUNDATION_EXPORT NSString* const GoTestpkgAString; FOUNDATION_EXPORT const int64_t GoTestpkgAnInt; FOUNDATION_EXPORT const double GoTestpkgLog2E; @@ -72,7 +89,7 @@ FOUNDATION_EXPORT const int64_t GoTestpkgMinInt64; FOUNDATION_EXPORT const float GoTestpkgSmallestNonzeroFloat32; FOUNDATION_EXPORT const double GoTestpkgSmallestNonzeroFloat64; -@interface GoTestpkg : NSObject +@interface GoTestpkg : NSObject + (int) intVar; + (void) setIntVar:(int)v; @@ -95,6 +112,8 @@ FOUNDATION_EXPORT BOOL GoTestpkgCallIStringError(id i, NSString* s, FOUNDATION_EXPORT double GoTestpkgCallSSum(GoTestpkgS* s); +FOUNDATION_EXPORT BOOL GoTestpkgCallWithNull(id p0, id nuller); + FOUNDATION_EXPORT int GoTestpkgCollectS(int want, int timeoutSec); FOUNDATION_EXPORT NSString* GoTestpkgEcho(NSString* s); @@ -113,12 +132,22 @@ FOUNDATION_EXPORT id GoTestpkgNewI(); FOUNDATION_EXPORT GoTestpkgNode* GoTestpkgNewNode(NSString* name); +FOUNDATION_EXPORT GoTestpkgNullFieldStruct* GoTestpkgNewNullFieldStruct(); + +FOUNDATION_EXPORT id GoTestpkgNewNullInterface(); + +FOUNDATION_EXPORT GoTestpkgS* GoTestpkgNewNullStruct(); + FOUNDATION_EXPORT GoTestpkgS* GoTestpkgNewS(double x, double y); +FOUNDATION_EXPORT BOOL GoTestpkgReadIntoByteArray(NSData* s, int* ret0_, NSError** error); + FOUNDATION_EXPORT void GoTestpkgRegisterI(int32_t idx, id i); FOUNDATION_EXPORT BOOL GoTestpkgReturnsError(BOOL b, NSString** ret0_, NSError** error); +FOUNDATION_EXPORT NSString* GoTestpkgStringDup(NSString* s); + FOUNDATION_EXPORT int64_t GoTestpkgSum(int64_t x, int64_t y); FOUNDATION_EXPORT void GoTestpkgUnregisterI(int32_t idx); diff --git a/bind/objc/testpkg/go_testpkg/GoTestpkg.m b/bind/objc/testpkg/go_testpkg/GoTestpkg.m new file mode 100644 index 0000000..0a97aa9 --- /dev/null +++ b/bind/objc/testpkg/go_testpkg/GoTestpkg.m @@ -0,0 +1,725 @@ +// Objective-C API for talking to golang.org/x/mobile/bind/objc/testpkg Go package. +// gobind -lang=objc golang.org/x/mobile/bind/objc/testpkg +// +// File is generated by gobind. Do not edit. + +#include "GoTestpkg.h" +#include +#include "seq.h" +#include "_cgo_export.h" + +static NSString* errDomain = @"go.golang.org/x/mobile/bind/objc/testpkg"; + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +@class GoTestpkgI; + +@class GoTestpkgNullTest; + +@class GoTestpkgZ; + +@interface GoTestpkgI : NSObject { +} +@property(strong, readonly) id _ref; + +- (id)initWithRef:(id)ref; +- (BOOL)error:(BOOL)triggerError error:(NSError**)error; +- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error; +- (int64_t)times:(int32_t)v; +@end + +@interface GoTestpkgNullTest : NSObject { +} +@property(strong, readonly) id _ref; + +- (id)initWithRef:(id)ref; +- (id)null; +@end + +@interface GoTestpkgZ : NSObject { +} +@property(strong, readonly) id _ref; + +- (id)initWithRef:(id)ref; +@end + + +@implementation GoTestpkgNode { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (NSString*)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxytestpkg_Node_V_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setV:(NSString*)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxytestpkg_Node_V_Set(refnum, _v); +} + +- (NSString*)err { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxytestpkg_Node_Err_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + +- (void)setErr:(NSString*)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxytestpkg_Node_Err_Set(refnum, _v); +} + +@end + + +@implementation GoTestpkgNullFieldStruct { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (GoTestpkgS*)f { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxytestpkg_NullFieldStruct_F_Get(refnum); + GoTestpkgS* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoTestpkgS alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +- (void)setF:(GoTestpkgS*)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _v; + if ([(id)(v) isKindOfClass:[GoTestpkgS class]]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + proxytestpkg_NullFieldStruct_F_Set(refnum, _v); +} + +@end + + +@implementation GoTestpkgS { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (double)x { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxytestpkg_S_X_Get(refnum); + double _r0 = (double)r0; + return _r0; +} + +- (void)setX:(double)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxytestpkg_S_X_Set(refnum, _v); +} + +- (double)y { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxytestpkg_S_Y_Get(refnum); + double _r0 = (double)r0; + return _r0; +} + +- (void)setY:(double)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxytestpkg_S_Y_Set(refnum, _v); +} + +- (double)sum { + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxytestpkg_S_Sum(refnum); + double _ret0_ = (double)r0; + return _ret0_; +} + +- (NSString*)tryTwoStrings:(NSString*)first second:(NSString*)second { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _first = go_seq_from_objc_string(first); + nstring _second = go_seq_from_objc_string(second); + nstring r0 = proxytestpkg_S_TryTwoStrings(refnum, _first, _second); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +@end + + +@implementation GoTestpkgStructThatStartsWithLetterBeforeZ { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (id)value { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Get(refnum); + id _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoTestpkgZ alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +- (void)setValue:(id)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _v; + if ([(id)(v) isKindOfClass:[GoTestpkgZ class]]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Set(refnum, _v); +} + +@end + +@implementation GoTestpkgI { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (BOOL)error:(BOOL)triggerError error:(NSError**)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + char _triggerError = (char)triggerError; + nstring r0 = proxytestpkg_I_Error(refnum, _triggerError); + NSString *_error = go_seq_to_objc_string(r0); + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error { + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _s = go_seq_from_objc_string(s); + struct proxytestpkg_I_StringError_return res = proxytestpkg_I_StringError(refnum, _s); + NSString *_ret0_ = go_seq_to_objc_string(res.r0); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +- (int64_t)times:(int32_t)v { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _v = (int32_t)v; + int64_t r0 = proxytestpkg_I_Times(refnum, _v); + int64_t _ret0_ = (int64_t)r0; + return _ret0_; +} + +@end + + +@implementation GoTestpkgNullTest { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +- (id)null { + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxytestpkg_NullTest_Null(refnum); + id _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgNullTest alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +@end + + +@implementation GoTestpkgZ { +} + +- (id)initWithRef:(id)ref { + self = [super init]; + if (self) { __ref = ref; } + return self; +} + +@end + + +const BOOL GoTestpkgABool = YES; +const double GoTestpkgAFloat = 0.12345; +NSString* const GoTestpkgALongString = @"LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString,LongString"; +NSString* const GoTestpkgAString = @"a string"; +const int64_t GoTestpkgAnInt = 7LL; +const double GoTestpkgLog2E = 1.4426950408889634; +const float GoTestpkgMaxFloat32 = 3.4028234663852886e+38; +const double GoTestpkgMaxFloat64 = 1.7976931348623157e+308; +const int32_t GoTestpkgMaxInt32 = 2147483647; +const int64_t GoTestpkgMaxInt64 = 9223372036854775807LL; +const int32_t GoTestpkgMinInt32 = -2147483648; +const int64_t GoTestpkgMinInt64 = -9223372036854775807LL-1; +const float GoTestpkgSmallestNonzeroFloat32 = 0; +const double GoTestpkgSmallestNonzeroFloat64 = 5e-324; + +@implementation GoTestpkg ++ (void) setIntVar:(int)v { + nint _v = (nint)v; + var_settestpkg_IntVar(_v); +} + ++ (int) intVar { + nint r0 = var_gettestpkg_IntVar(); + int _r0 = (int)r0; + return _r0; +} + ++ (void) setInterfaceVar:(id)v { + int32_t _v; + if ([(id)(v) isKindOfClass:[GoTestpkgI class]]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + var_settestpkg_InterfaceVar(_v); +} + ++ (id) interfaceVar { + int32_t r0 = var_gettestpkg_InterfaceVar(); + id _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoTestpkgI alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + ++ (void) setStringVar:(NSString*)v { + nstring _v = go_seq_from_objc_string(v); + var_settestpkg_StringVar(_v); +} + ++ (NSString*) stringVar { + nstring r0 = var_gettestpkg_StringVar(); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; +} + ++ (void) setStructVar:(GoTestpkgNode*)v { + int32_t _v; + if ([(id)(v) isKindOfClass:[GoTestpkgNode class]]) { + id v_proxy = (id)(v); + _v = go_seq_go_to_refnum(v_proxy._ref); + } else { + _v = go_seq_to_refnum(v); + } + var_settestpkg_StructVar(_v); +} + ++ (GoTestpkgNode*) structVar { + int32_t r0 = var_gettestpkg_StructVar(); + GoTestpkgNode* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoTestpkgNode alloc] initWithRef:_r0_ref]; + } + } + return _r0; +} + +@end + + +NSData* GoTestpkgBytesAppend(NSData* a, NSData* b) { + nbyteslice _a = go_seq_from_objc_bytearray(a, 0); + nbyteslice _b = go_seq_from_objc_bytearray(b, 0); + nbyteslice r0 = proxytestpkg__BytesAppend(_a, _b); + if (![a isKindOfClass:[NSMutableData class]]) { + free(_a.ptr); + } + if (![b isKindOfClass:[NSMutableData class]]) { + free(_b.ptr); + } + NSData *_ret0_ = go_seq_to_objc_bytearray(r0, 1); + return _ret0_; +} + +BOOL GoTestpkgCallIError(id i, BOOL triggerError, NSError** error) { + int32_t _i; + if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { + id i_proxy = (id)(i); + _i = go_seq_go_to_refnum(i_proxy._ref); + } else { + _i = go_seq_to_refnum(i); + } + char _triggerError = (char)triggerError; + nstring r0 = proxytestpkg__CallIError(_i, _triggerError); + NSString *_error = go_seq_to_objc_string(r0); + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +BOOL GoTestpkgCallIStringError(id i, NSString* s, NSString** ret0_, NSError** error) { + int32_t _i; + if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { + id i_proxy = (id)(i); + _i = go_seq_go_to_refnum(i_proxy._ref); + } else { + _i = go_seq_to_refnum(i); + } + nstring _s = go_seq_from_objc_string(s); + struct proxytestpkg__CallIStringError_return res = proxytestpkg__CallIStringError(_i, _s); + NSString *_ret0_ = go_seq_to_objc_string(res.r0); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +double GoTestpkgCallSSum(GoTestpkgS* s) { + int32_t _s; + if ([(id)(s) isKindOfClass:[GoTestpkgS class]]) { + id s_proxy = (id)(s); + _s = go_seq_go_to_refnum(s_proxy._ref); + } else { + _s = go_seq_to_refnum(s); + } + double r0 = proxytestpkg__CallSSum(_s); + double _ret0_ = (double)r0; + return _ret0_; +} + +BOOL GoTestpkgCallWithNull(id p0, id nuller) { + int32_t _p0; + if ([(id)(p0) isKindOfClass:[GoTestpkgNullTest class]]) { + id p0_proxy = (id)(p0); + _p0 = go_seq_go_to_refnum(p0_proxy._ref); + } else { + _p0 = go_seq_to_refnum(p0); + } + int32_t _nuller; + if ([(id)(nuller) isKindOfClass:[GoTestpkgNullTest class]]) { + id nuller_proxy = (id)(nuller); + _nuller = go_seq_go_to_refnum(nuller_proxy._ref); + } else { + _nuller = go_seq_to_refnum(nuller); + } + char r0 = proxytestpkg__CallWithNull(_p0, _nuller); + BOOL _ret0_ = r0 ? YES : NO; + return _ret0_; +} + +int GoTestpkgCollectS(int want, int timeoutSec) { + nint _want = (nint)want; + nint _timeoutSec = (nint)timeoutSec; + nint r0 = proxytestpkg__CollectS(_want, _timeoutSec); + int _ret0_ = (int)r0; + return _ret0_; +} + +NSString* GoTestpkgEcho(NSString* s) { + nstring _s = go_seq_from_objc_string(s); + nstring r0 = proxytestpkg__Echo(_s); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +void GoTestpkgGC() { + proxytestpkg__GC(); +} + +NSString* GoTestpkgHello(NSString* s) { + nstring _s = go_seq_from_objc_string(s); + nstring r0 = proxytestpkg__Hello(_s); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +void GoTestpkgHi() { + proxytestpkg__Hi(); +} + +void GoTestpkgInt(int32_t x) { + int32_t _x = (int32_t)x; + proxytestpkg__Int(_x); +} + +int64_t GoTestpkgMultiply(int32_t idx, int32_t val) { + int32_t _idx = (int32_t)idx; + int32_t _val = (int32_t)val; + int64_t r0 = proxytestpkg__Multiply(_idx, _val); + int64_t _ret0_ = (int64_t)r0; + return _ret0_; +} + +id GoTestpkgNewI() { + int32_t r0 = proxytestpkg__NewI(); + id _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgI alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +GoTestpkgNode* GoTestpkgNewNode(NSString* name) { + nstring _name = go_seq_from_objc_string(name); + int32_t r0 = proxytestpkg__NewNode(_name); + GoTestpkgNode* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgNode alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +GoTestpkgNullFieldStruct* GoTestpkgNewNullFieldStruct() { + int32_t r0 = proxytestpkg__NewNullFieldStruct(); + GoTestpkgNullFieldStruct* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgNullFieldStruct alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +id GoTestpkgNewNullInterface() { + int32_t r0 = proxytestpkg__NewNullInterface(); + id _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgI alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +GoTestpkgS* GoTestpkgNewNullStruct() { + int32_t r0 = proxytestpkg__NewNullStruct(); + GoTestpkgS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgS alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +GoTestpkgS* GoTestpkgNewS(double x, double y) { + double _x = (double)x; + double _y = (double)y; + int32_t r0 = proxytestpkg__NewS(_x, _y); + GoTestpkgS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoTestpkgS alloc] initWithRef:_ret0__ref]; + } + } + return _ret0_; +} + +BOOL GoTestpkgReadIntoByteArray(NSData* s, int* ret0_, NSError** error) { + nbyteslice _s = go_seq_from_objc_bytearray(s, 0); + struct proxytestpkg__ReadIntoByteArray_return res = proxytestpkg__ReadIntoByteArray(_s); + if (![s isKindOfClass:[NSMutableData class]]) { + free(_s.ptr); + } + int _ret0_ = (int)res.r0; + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +void GoTestpkgRegisterI(int32_t idx, id i) { + int32_t _idx = (int32_t)idx; + int32_t _i; + if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { + id i_proxy = (id)(i); + _i = go_seq_go_to_refnum(i_proxy._ref); + } else { + _i = go_seq_to_refnum(i); + } + proxytestpkg__RegisterI(_idx, _i); +} + +BOOL GoTestpkgReturnsError(BOOL b, NSString** ret0_, NSError** error) { + char _b = (char)b; + struct proxytestpkg__ReturnsError_return res = proxytestpkg__ReturnsError(_b); + NSString *_ret0_ = go_seq_to_objc_string(res.r0); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; + if ([_error length] != 0 && error != nil) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:_error forKey:NSLocalizedDescriptionKey]; + *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; + } + return ([_error length] == 0); +} + +NSString* GoTestpkgStringDup(NSString* s) { + nstring _s = go_seq_from_objc_string(s); + nstring r0 = proxytestpkg__StringDup(_s); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; +} + +int64_t GoTestpkgSum(int64_t x, int64_t y) { + int64_t _x = (int64_t)x; + int64_t _y = (int64_t)y; + int64_t r0 = proxytestpkg__Sum(_x, _y); + int64_t _ret0_ = (int64_t)r0; + return _ret0_; +} + +void GoTestpkgUnregisterI(int32_t idx) { + int32_t _idx = (int32_t)idx; + proxytestpkg__UnregisterI(_idx); +} + +nstring cproxytestpkg_I_Error(int32_t refnum, char triggerError) { + id o = go_seq_objc_from_refnum(refnum); + BOOL _triggerError = triggerError ? YES : NO; + NSError* error = nil; + BOOL returnVal = [o error:_triggerError error:&error]; + NSString *error_str = nil; + if (!returnVal) { + error_str = [error localizedDescription]; + if (error_str == nil || error_str.length == 0) { + error_str = @"gobind: unknown error"; + } + } + nstring _error_str = go_seq_from_objc_string(error_str); + return _error_str; +} + +struct cproxytestpkg_I_StringError_return cproxytestpkg_I_StringError(int32_t refnum, nstring s) { + id o = go_seq_objc_from_refnum(refnum); + NSString *_s = go_seq_to_objc_string(s); + NSString* ret0_; + NSError* error = nil; + BOOL returnVal = [o stringError:_s ret0_:&ret0_ error:&error]; + nstring _ret0_ = go_seq_from_objc_string(ret0_); + NSString *error_str = nil; + if (!returnVal) { + error_str = [error localizedDescription]; + if (error_str == nil || error_str.length == 0) { + error_str = @"gobind: unknown error"; + } + } + nstring _error_str = go_seq_from_objc_string(error_str); + cproxytestpkg_I_StringError_return _sres = { + _ret0_, _error_str + }; + return _sres; +} + +int64_t cproxytestpkg_I_Times(int32_t refnum, int32_t v) { + id o = go_seq_objc_from_refnum(refnum); + int32_t _v = (int32_t)v; + int64_t returnVal = [o times:_v]; + int64_t _returnVal = (int64_t)returnVal; + return _returnVal; +} + +int32_t cproxytestpkg_NullTest_Null(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + id returnVal = [o null]; + int32_t _returnVal; + if ([(id)(returnVal) isKindOfClass:[GoTestpkgNullTest class]]) { + id returnVal_proxy = (id)(returnVal); + _returnVal = go_seq_go_to_refnum(returnVal_proxy._ref); + } else { + _returnVal = go_seq_to_refnum(returnVal); + } + return _returnVal; +} + +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/objc/testpkg/go_testpkg/go_testpkg.go b/bind/objc/testpkg/go_testpkg/go_testpkg.go index cf3760b..45a2b4a 100644 --- a/bind/objc/testpkg/go_testpkg/go_testpkg.go +++ b/bind/objc/testpkg/go_testpkg/go_testpkg.go @@ -1,436 +1,608 @@ -// Package go_testpkg is an autogenerated binder stub for package testpkg. +// Package gomobile_bind is an autogenerated binder stub for package testpkg. // gobind -lang=go golang.org/x/mobile/bind/objc/testpkg // // File is generated by gobind. Do not edit. -package go_testpkg +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "testpkg.h" + +*/ +import "C" import ( "golang.org/x/mobile/bind/objc/testpkg" - "golang.org/x/mobile/bind/seq" + _seq "golang.org/x/mobile/bind/seq" ) -func proxy_BytesAppend(out, in *seq.Buffer) { - param_a := in.ReadByteArray() - param_b := in.ReadByteArray() - res := testpkg.BytesAppend(param_a, param_b) - out.WriteByteArray(res) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum + +type proxyNode _seq.Ref + +//export proxytestpkg_Node_V_Set +func proxytestpkg_Node_V_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v, false) + ref.Get().(*testpkg.Node).V = _v } -func proxy_CallIError(out, in *seq.Buffer) { - var param_i testpkg.I - param_i_ref := in.ReadRef() - if param_i_ref.Num < 0 { // go object - param_i = param_i_ref.Get().(testpkg.I) - } else { // foreign object - param_i = (*proxyI)(param_i_ref) - } - param_triggerError := in.ReadBool() - err := testpkg.CallIError(param_i, param_triggerError) - if err == nil { - out.WriteString("") +//export proxytestpkg_Node_V_Get +func proxytestpkg_Node_V_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.Node).V + _v := encodeString(v, true) + return _v +} + +//export proxytestpkg_Node_Err_Set +func proxytestpkg_Node_Err_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v_str := decodeString(v, false) + _v := toError(_v_str) + ref.Get().(*testpkg.Node).Err = _v +} + +//export proxytestpkg_Node_Err_Get +func proxytestpkg_Node_Err_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.Node).Err + var _v_str string + if v == nil { + _v_str = "" } else { - out.WriteString(err.Error()) + _v_str = v.Error() } + _v := encodeString(_v_str, true) + return _v } -func proxy_CallIStringError(out, in *seq.Buffer) { - var param_i testpkg.I - param_i_ref := in.ReadRef() - if param_i_ref.Num < 0 { // go object - param_i = param_i_ref.Get().(testpkg.I) - } else { // foreign object - param_i = (*proxyI)(param_i_ref) - } - param_s := in.ReadString() - res, err := testpkg.CallIStringError(param_i, param_s) - out.WriteString(res) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) - } -} +type proxyNullFieldStruct _seq.Ref -func proxy_CallSSum(out, in *seq.Buffer) { +//export proxytestpkg_NullFieldStruct_F_Set +func proxytestpkg_NullFieldStruct_F_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) // Must be a Go object - param_s_ref := in.ReadRef() - param_s := param_s_ref.Get().(*testpkg.S) - res := testpkg.CallSSum(param_s) - out.WriteFloat64(res) + _v_ref := _seq.FromRefNum(int32(v)) + _v := _v_ref.Get().(*testpkg.S) + ref.Get().(*testpkg.NullFieldStruct).F = _v } -func proxy_CollectS(out, in *seq.Buffer) { - param_want := in.ReadInt() - param_timeoutSec := in.ReadInt() - res := testpkg.CollectS(param_want, param_timeoutSec) - out.WriteInt(res) -} - -func proxy_Echo(out, in *seq.Buffer) { - param_s := in.ReadString() - res := testpkg.Echo(param_s) - out.WriteString(res) -} - -func proxy_GC(out, in *seq.Buffer) { - testpkg.GC() -} - -func proxy_Hello(out, in *seq.Buffer) { - param_s := in.ReadString() - res := testpkg.Hello(param_s) - out.WriteString(res) -} - -func proxy_Hi(out, in *seq.Buffer) { - testpkg.Hi() -} - -const ( - proxyI_Descriptor = "go.testpkg.I" - proxyI_Error_Code = 0x10a - proxyI_StringError_Code = 0x20a - proxyI_Times_Code = 0x30a -) - -func proxyI_Error(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(testpkg.I) - param_triggerError := in.ReadBool() - err := v.Error(param_triggerError) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) +//export proxytestpkg_NullFieldStruct_F_Get +func proxytestpkg_NullFieldStruct_F_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.NullFieldStruct).F + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) } + return _v } -func proxyI_StringError(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(testpkg.I) - param_s := in.ReadString() - res, err := v.StringError(param_s) - out.WriteString(res) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) +type proxyS _seq.Ref + +//export proxytestpkg_S_X_Set +func proxytestpkg_S_X_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*testpkg.S).X = _v +} + +//export proxytestpkg_S_X_Get +func proxytestpkg_S_X_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.S).X + _v := C.double(v) + return _v +} + +//export proxytestpkg_S_Y_Set +func proxytestpkg_S_Y_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*testpkg.S).Y = _v +} + +//export proxytestpkg_S_Y_Get +func proxytestpkg_S_Y_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.S).Y + _v := C.double(v) + return _v +} + +//export proxytestpkg_S_Sum +func proxytestpkg_S_Sum(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.S) + res_0 := v.Sum() + _res_0 := C.double(res_0) + return _res_0 +} + +//export proxytestpkg_S_TryTwoStrings +func proxytestpkg_S_TryTwoStrings(refnum C.int32_t, param_first C.nstring, param_second C.nstring) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.S) + _param_first := decodeString(param_first, false) + _param_second := decodeString(param_second, false) + res_0 := v.TryTwoStrings(_param_first, _param_second) + _res_0 := encodeString(res_0, true) + return _res_0 +} + +type proxyStructThatStartsWithLetterBeforeZ _seq.Ref + +//export proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Set +func proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Set(refnum C.int32_t, v C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + var _v testpkg.Z + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if _v_ref.Num < 0 { // go object + _v = _v_ref.Get().(testpkg.Z) + } else { // foreign object + _v = (*proxytestpkg_Z)(_v_ref) + } } + ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value = _v } -func proxyI_Times(out, in *seq.Buffer) { - ref := in.ReadRef() +//export proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Get +func proxytestpkg_StructThatStartsWithLetterBeforeZ_Value_Get(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export proxytestpkg_I_Error +func proxytestpkg_I_Error(refnum C.int32_t, param_triggerError C.char) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(testpkg.I) - param_v := in.ReadInt32() - res := v.Times(param_v) - out.WriteInt64(res) + _param_triggerError := param_triggerError != 0 + res_0 := v.Error(_param_triggerError) + var _res_0_str string + if res_0 == nil { + _res_0_str = "" + } else { + _res_0_str = res_0.Error() + } + _res_0 := encodeString(_res_0_str, true) + return _res_0 } -func init() { - seq.Register(proxyI_Descriptor, proxyI_Error_Code, proxyI_Error) - seq.Register(proxyI_Descriptor, proxyI_StringError_Code, proxyI_StringError) - seq.Register(proxyI_Descriptor, proxyI_Times_Code, proxyI_Times) +//export proxytestpkg_I_StringError +func proxytestpkg_I_StringError(refnum C.int32_t, param_s C.nstring) (C.nstring, C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(testpkg.I) + _param_s := decodeString(param_s, false) + res_0, res_1 := v.StringError(_param_s) + _res_0 := encodeString(res_0, true) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 } -type proxyI seq.Ref - -func (p *proxyI) Error(triggerError bool) error { - in := new(seq.Buffer) - in.WriteBool(triggerError) - out := seq.Transact((*seq.Ref)(p), "go.testpkg.I", proxyI_Error_Code, in) - res_0 := out.ReadError() - return res_0 +//export proxytestpkg_I_Times +func proxytestpkg_I_Times(refnum C.int32_t, param_v C.int32_t) C.int64_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(testpkg.I) + _param_v := int32(param_v) + res_0 := v.Times(_param_v) + _res_0 := C.int64_t(res_0) + return _res_0 } -func (p *proxyI) StringError(s string) (string, error) { - in := new(seq.Buffer) - in.WriteString(s) - out := seq.Transact((*seq.Ref)(p), "go.testpkg.I", proxyI_StringError_Code, in) - res_0 := out.ReadString() - res_1 := out.ReadError() +type proxytestpkg_I _seq.Ref + +func (p *proxytestpkg_I) Error(param_triggerError bool) error { + var _param_triggerError C.char = 0 + if param_triggerError { + _param_triggerError = 1 + } + res := C.cproxytestpkg_I_Error(C.int32_t(p.Num), _param_triggerError) + _res_str := decodeString(res, true) + _res := toError(_res_str) + return _res +} + +func (p *proxytestpkg_I) StringError(param_s string) (string, error) { + _param_s := encodeString(param_s, false) + res := C.cproxytestpkg_I_StringError(C.int32_t(p.Num), _param_s) + res_0 := decodeString(res.r0, true) + res_1_str := decodeString(res.r1, true) + res_1 := toError(res_1_str) return res_0, res_1 } -func (p *proxyI) Times(v int32) int64 { - in := new(seq.Buffer) - in.WriteInt32(v) - out := seq.Transact((*seq.Ref)(p), "go.testpkg.I", proxyI_Times_Code, in) - res_0 := out.ReadInt64() - return res_0 +func (p *proxytestpkg_I) Times(param_v int32) int64 { + _param_v := C.int32_t(param_v) + res := C.cproxytestpkg_I_Times(C.int32_t(p.Num), _param_v) + _res := int64(res) + return _res } -func proxy_Int(out, in *seq.Buffer) { - param_x := in.ReadInt32() - testpkg.Int(param_x) -} - -func var_setIntVar(out, in *seq.Buffer) { - v := in.ReadInt() - testpkg.IntVar = v -} -func var_getIntVar(out, in *seq.Buffer) { - out.WriteInt(testpkg.IntVar) -} -func var_setInterfaceVar(out, in *seq.Buffer) { - var v testpkg.I - v_ref := in.ReadRef() - if v_ref.Num < 0 { // go object - v = v_ref.Get().(testpkg.I) - } else { // foreign object - v = (*proxyI)(v_ref) +//export proxytestpkg_NullTest_Null +func proxytestpkg_NullTest_Null(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(testpkg.NullTest) + res_0 := v.Null() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) } - testpkg.InterfaceVar = v -} -func var_getInterfaceVar(out, in *seq.Buffer) { - out.WriteGoRef(testpkg.InterfaceVar) -} -func proxy_Multiply(out, in *seq.Buffer) { - param_idx := in.ReadInt32() - param_val := in.ReadInt32() - res := testpkg.Multiply(param_idx, param_val) - out.WriteInt64(res) + return _res_0 } -func proxy_NewI(out, in *seq.Buffer) { - res := testpkg.NewI() - out.WriteGoRef(res) -} +type proxytestpkg_NullTest _seq.Ref -func proxy_NewNode(out, in *seq.Buffer) { - param_name := in.ReadString() - res := testpkg.NewNode(param_name) - out.WriteGoRef(res) -} - -func proxy_NewS(out, in *seq.Buffer) { - param_x := in.ReadFloat64() - param_y := in.ReadFloat64() - res := testpkg.NewS(param_x, param_y) - out.WriteGoRef(res) -} - -const ( - proxyNode_Descriptor = "go.testpkg.Node" - proxyNode_V_Get_Code = 0x00f - proxyNode_V_Set_Code = 0x01f - proxyNode_Err_Get_Code = 0x10f - proxyNode_Err_Set_Code = 0x11f -) - -type proxyNode seq.Ref - -func proxyNode_V_Set(out, in *seq.Buffer) { - ref := in.ReadRef() - v := in.ReadString() - ref.Get().(*testpkg.Node).V = v -} - -func proxyNode_V_Get(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.Node).V - out.WriteString(v) -} - -func proxyNode_Err_Set(out, in *seq.Buffer) { - ref := in.ReadRef() - v := in.ReadError() - ref.Get().(*testpkg.Node).Err = v -} - -func proxyNode_Err_Get(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.Node).Err - if v == nil { - out.WriteString("") - } else { - out.WriteString(v.Error()) +func (p *proxytestpkg_NullTest) Null() testpkg.NullTest { + res := C.cproxytestpkg_NullTest_Null(C.int32_t(p.Num)) + var _res testpkg.NullTest + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if _res_ref.Num < 0 { // go object + _res = _res_ref.Get().(testpkg.NullTest) + } else { // foreign object + _res = (*proxytestpkg_NullTest)(_res_ref) + } } + return _res } -func init() { - seq.Register(proxyNode_Descriptor, proxyNode_V_Set_Code, proxyNode_V_Set) - seq.Register(proxyNode_Descriptor, proxyNode_V_Get_Code, proxyNode_V_Get) - seq.Register(proxyNode_Descriptor, proxyNode_Err_Set_Code, proxyNode_Err_Set) - seq.Register(proxyNode_Descriptor, proxyNode_Err_Get_Code, proxyNode_Err_Get) +type proxytestpkg_Z _seq.Ref + +//export var_settestpkg_IntVar +func var_settestpkg_IntVar(v C.nint) { + _v := int(v) + testpkg.IntVar = _v } -func proxy_RegisterI(out, in *seq.Buffer) { - param_idx := in.ReadInt32() - var param_i testpkg.I - param_i_ref := in.ReadRef() - if param_i_ref.Num < 0 { // go object - param_i = param_i_ref.Get().(testpkg.I) - } else { // foreign object - param_i = (*proxyI)(param_i_ref) +//export var_gettestpkg_IntVar +func var_gettestpkg_IntVar() C.nint { + v := testpkg.IntVar + _v := C.nint(v) + return _v +} + +//export var_settestpkg_InterfaceVar +func var_settestpkg_InterfaceVar(v C.int32_t) { + var _v testpkg.I + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if _v_ref.Num < 0 { // go object + _v = _v_ref.Get().(testpkg.I) + } else { // foreign object + _v = (*proxytestpkg_I)(_v_ref) + } } - testpkg.RegisterI(param_idx, param_i) + testpkg.InterfaceVar = _v } -func proxy_ReturnsError(out, in *seq.Buffer) { - param_b := in.ReadBool() - res, err := testpkg.ReturnsError(param_b) - out.WriteString(res) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) +//export var_gettestpkg_InterfaceVar +func var_gettestpkg_InterfaceVar() C.int32_t { + v := testpkg.InterfaceVar + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) } + return _v } -const ( - proxyS_Descriptor = "go.testpkg.S" - proxyS_X_Get_Code = 0x00f - proxyS_X_Set_Code = 0x01f - proxyS_Y_Get_Code = 0x10f - proxyS_Y_Set_Code = 0x11f - proxyS_Sum_Code = 0x00c - proxyS_TryTwoStrings_Code = 0x10c -) - -type proxyS seq.Ref - -func proxyS_X_Set(out, in *seq.Buffer) { - ref := in.ReadRef() - v := in.ReadFloat64() - ref.Get().(*testpkg.S).X = v +//export var_settestpkg_StringVar +func var_settestpkg_StringVar(v C.nstring) { + _v := decodeString(v, false) + testpkg.StringVar = _v } -func proxyS_X_Get(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.S).X - out.WriteFloat64(v) +//export var_gettestpkg_StringVar +func var_gettestpkg_StringVar() C.nstring { + v := testpkg.StringVar + _v := encodeString(v, true) + return _v } -func proxyS_Y_Set(out, in *seq.Buffer) { - ref := in.ReadRef() - v := in.ReadFloat64() - ref.Get().(*testpkg.S).Y = v -} - -func proxyS_Y_Get(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.S).Y - out.WriteFloat64(v) -} - -func proxyS_Sum(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.S) - res := v.Sum() - out.WriteFloat64(res) -} - -func proxyS_TryTwoStrings(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.S) - param_first := in.ReadString() - param_second := in.ReadString() - res := v.TryTwoStrings(param_first, param_second) - out.WriteString(res) -} - -func init() { - seq.Register(proxyS_Descriptor, proxyS_X_Set_Code, proxyS_X_Set) - seq.Register(proxyS_Descriptor, proxyS_X_Get_Code, proxyS_X_Get) - seq.Register(proxyS_Descriptor, proxyS_Y_Set_Code, proxyS_Y_Set) - seq.Register(proxyS_Descriptor, proxyS_Y_Get_Code, proxyS_Y_Get) - seq.Register(proxyS_Descriptor, proxyS_Sum_Code, proxyS_Sum) - seq.Register(proxyS_Descriptor, proxyS_TryTwoStrings_Code, proxyS_TryTwoStrings) -} - -func var_setStringVar(out, in *seq.Buffer) { - v := in.ReadString() - testpkg.StringVar = v -} -func var_getStringVar(out, in *seq.Buffer) { - out.WriteString(testpkg.StringVar) -} - -const ( - proxyStructThatStartsWithLetterBeforeZ_Descriptor = "go.testpkg.StructThatStartsWithLetterBeforeZ" - proxyStructThatStartsWithLetterBeforeZ_Value_Get_Code = 0x00f - proxyStructThatStartsWithLetterBeforeZ_Value_Set_Code = 0x01f -) - -type proxyStructThatStartsWithLetterBeforeZ seq.Ref - -func proxyStructThatStartsWithLetterBeforeZ_Value_Set(out, in *seq.Buffer) { - ref := in.ReadRef() - var v testpkg.Z - v_ref := in.ReadRef() - if v_ref.Num < 0 { // go object - v = v_ref.Get().(testpkg.Z) - } else { // foreign object - v = (*proxyZ)(v_ref) - } - ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value = v -} - -func proxyStructThatStartsWithLetterBeforeZ_Value_Get(out, in *seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value - out.WriteGoRef(v) -} - -func init() { - seq.Register(proxyStructThatStartsWithLetterBeforeZ_Descriptor, proxyStructThatStartsWithLetterBeforeZ_Value_Set_Code, proxyStructThatStartsWithLetterBeforeZ_Value_Set) - seq.Register(proxyStructThatStartsWithLetterBeforeZ_Descriptor, proxyStructThatStartsWithLetterBeforeZ_Value_Get_Code, proxyStructThatStartsWithLetterBeforeZ_Value_Get) -} - -func var_setStructVar(out, in *seq.Buffer) { +//export var_settestpkg_StructVar +func var_settestpkg_StructVar(v C.int32_t) { // Must be a Go object - v_ref := in.ReadRef() - v := v_ref.Get().(*testpkg.Node) - testpkg.StructVar = v -} -func var_getStructVar(out, in *seq.Buffer) { - out.WriteGoRef(testpkg.StructVar) -} -func proxy_Sum(out, in *seq.Buffer) { - param_x := in.ReadInt64() - param_y := in.ReadInt64() - res := testpkg.Sum(param_x, param_y) - out.WriteInt64(res) + _v_ref := _seq.FromRefNum(int32(v)) + _v := _v_ref.Get().(*testpkg.Node) + testpkg.StructVar = _v } -func proxy_UnregisterI(out, in *seq.Buffer) { - param_idx := in.ReadInt32() - testpkg.UnregisterI(param_idx) +//export var_gettestpkg_StructVar +func var_gettestpkg_StructVar() C.int32_t { + v := testpkg.StructVar + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v } -const ( - proxyZ_Descriptor = "go.testpkg.Z" -) - -type proxyZ seq.Ref - -func init() { - seq.Register("testpkg", 1, proxy_BytesAppend) - seq.Register("testpkg", 2, proxy_CallIError) - seq.Register("testpkg", 3, proxy_CallIStringError) - seq.Register("testpkg", 4, proxy_CallSSum) - seq.Register("testpkg", 5, proxy_CollectS) - seq.Register("testpkg", 6, proxy_Echo) - seq.Register("testpkg", 7, proxy_GC) - seq.Register("testpkg", 8, proxy_Hello) - seq.Register("testpkg", 9, proxy_Hi) - seq.Register("testpkg", 10, proxy_Int) - seq.Register("testpkg", 11, proxy_Multiply) - seq.Register("testpkg", 12, proxy_NewI) - seq.Register("testpkg", 13, proxy_NewNode) - seq.Register("testpkg", 14, proxy_NewS) - seq.Register("testpkg", 15, proxy_RegisterI) - seq.Register("testpkg", 16, proxy_ReturnsError) - seq.Register("testpkg", 17, proxy_Sum) - seq.Register("testpkg", 18, proxy_UnregisterI) +//export proxytestpkg__BytesAppend +func proxytestpkg__BytesAppend(param_a C.nbyteslice, param_b C.nbyteslice) C.nbyteslice { + _param_a := toSlice(param_a, false) + _param_b := toSlice(param_b, false) + res_0 := testpkg.BytesAppend(_param_a, _param_b) + _res_0 := fromSlice(res_0, true) + return _res_0 } -func init() { - seq.Register("testpkg.IntVar", 1, var_setIntVar) - seq.Register("testpkg.IntVar", 2, var_getIntVar) - seq.Register("testpkg.InterfaceVar", 1, var_setInterfaceVar) - seq.Register("testpkg.InterfaceVar", 2, var_getInterfaceVar) - seq.Register("testpkg.StringVar", 1, var_setStringVar) - seq.Register("testpkg.StringVar", 2, var_getStringVar) - seq.Register("testpkg.StructVar", 1, var_setStructVar) - seq.Register("testpkg.StructVar", 2, var_getStructVar) + +//export proxytestpkg__CallIError +func proxytestpkg__CallIError(param_i C.int32_t, param_triggerError C.char) C.nstring { + var _param_i testpkg.I + _param_i_ref := _seq.FromRefNum(int32(param_i)) + if _param_i_ref != nil { + if _param_i_ref.Num < 0 { // go object + _param_i = _param_i_ref.Get().(testpkg.I) + } else { // foreign object + _param_i = (*proxytestpkg_I)(_param_i_ref) + } + } + _param_triggerError := param_triggerError != 0 + res_0 := testpkg.CallIError(_param_i, _param_triggerError) + var _res_0_str string + if res_0 == nil { + _res_0_str = "" + } else { + _res_0_str = res_0.Error() + } + _res_0 := encodeString(_res_0_str, true) + return _res_0 +} + +//export proxytestpkg__CallIStringError +func proxytestpkg__CallIStringError(param_i C.int32_t, param_s C.nstring) (C.nstring, C.nstring) { + var _param_i testpkg.I + _param_i_ref := _seq.FromRefNum(int32(param_i)) + if _param_i_ref != nil { + if _param_i_ref.Num < 0 { // go object + _param_i = _param_i_ref.Get().(testpkg.I) + } else { // foreign object + _param_i = (*proxytestpkg_I)(_param_i_ref) + } + } + _param_s := decodeString(param_s, false) + res_0, res_1 := testpkg.CallIStringError(_param_i, _param_s) + _res_0 := encodeString(res_0, true) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 +} + +//export proxytestpkg__CallSSum +func proxytestpkg__CallSSum(param_s C.int32_t) C.double { + // Must be a Go object + _param_s_ref := _seq.FromRefNum(int32(param_s)) + _param_s := _param_s_ref.Get().(*testpkg.S) + res_0 := testpkg.CallSSum(_param_s) + _res_0 := C.double(res_0) + return _res_0 +} + +//export proxytestpkg__CallWithNull +func proxytestpkg__CallWithNull(param_p0 C.int32_t, param_nuller C.int32_t) C.char { + var _param_p0 testpkg.NullTest + _param_p0_ref := _seq.FromRefNum(int32(param_p0)) + if _param_p0_ref != nil { + if _param_p0_ref.Num < 0 { // go object + _param_p0 = _param_p0_ref.Get().(testpkg.NullTest) + } else { // foreign object + _param_p0 = (*proxytestpkg_NullTest)(_param_p0_ref) + } + } + var _param_nuller testpkg.NullTest + _param_nuller_ref := _seq.FromRefNum(int32(param_nuller)) + if _param_nuller_ref != nil { + if _param_nuller_ref.Num < 0 { // go object + _param_nuller = _param_nuller_ref.Get().(testpkg.NullTest) + } else { // foreign object + _param_nuller = (*proxytestpkg_NullTest)(_param_nuller_ref) + } + } + res_0 := testpkg.CallWithNull(_param_p0, _param_nuller) + var _res_0 C.char = 0 + if res_0 { + _res_0 = 1 + } + return _res_0 +} + +//export proxytestpkg__CollectS +func proxytestpkg__CollectS(param_want C.nint, param_timeoutSec C.nint) C.nint { + _param_want := int(param_want) + _param_timeoutSec := int(param_timeoutSec) + res_0 := testpkg.CollectS(_param_want, _param_timeoutSec) + _res_0 := C.nint(res_0) + return _res_0 +} + +//export proxytestpkg__Echo +func proxytestpkg__Echo(param_s C.nstring) C.nstring { + _param_s := decodeString(param_s, false) + res_0 := testpkg.Echo(_param_s) + _res_0 := encodeString(res_0, true) + return _res_0 +} + +//export proxytestpkg__GC +func proxytestpkg__GC() { + testpkg.GC() +} + +//export proxytestpkg__Hello +func proxytestpkg__Hello(param_s C.nstring) C.nstring { + _param_s := decodeString(param_s, false) + res_0 := testpkg.Hello(_param_s) + _res_0 := encodeString(res_0, true) + return _res_0 +} + +//export proxytestpkg__Hi +func proxytestpkg__Hi() { + testpkg.Hi() +} + +//export proxytestpkg__Int +func proxytestpkg__Int(param_x C.int32_t) { + _param_x := int32(param_x) + testpkg.Int(_param_x) +} + +//export proxytestpkg__Multiply +func proxytestpkg__Multiply(param_idx C.int32_t, param_val C.int32_t) C.int64_t { + _param_idx := int32(param_idx) + _param_val := int32(param_val) + res_0 := testpkg.Multiply(_param_idx, _param_val) + _res_0 := C.int64_t(res_0) + return _res_0 +} + +//export proxytestpkg__NewI +func proxytestpkg__NewI() C.int32_t { + res_0 := testpkg.NewI() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__NewNode +func proxytestpkg__NewNode(param_name C.nstring) C.int32_t { + _param_name := decodeString(param_name, false) + res_0 := testpkg.NewNode(_param_name) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__NewNullFieldStruct +func proxytestpkg__NewNullFieldStruct() C.int32_t { + res_0 := testpkg.NewNullFieldStruct() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__NewNullInterface +func proxytestpkg__NewNullInterface() C.int32_t { + res_0 := testpkg.NewNullInterface() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__NewNullStruct +func proxytestpkg__NewNullStruct() C.int32_t { + res_0 := testpkg.NewNullStruct() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__NewS +func proxytestpkg__NewS(param_x C.double, param_y C.double) C.int32_t { + _param_x := float64(param_x) + _param_y := float64(param_y) + res_0 := testpkg.NewS(_param_x, _param_y) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxytestpkg__ReadIntoByteArray +func proxytestpkg__ReadIntoByteArray(param_s C.nbyteslice) (C.nint, C.nstring) { + _param_s := toSlice(param_s, false) + res_0, res_1 := testpkg.ReadIntoByteArray(_param_s) + _res_0 := C.nint(res_0) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 +} + +//export proxytestpkg__RegisterI +func proxytestpkg__RegisterI(param_idx C.int32_t, param_i C.int32_t) { + _param_idx := int32(param_idx) + var _param_i testpkg.I + _param_i_ref := _seq.FromRefNum(int32(param_i)) + if _param_i_ref != nil { + if _param_i_ref.Num < 0 { // go object + _param_i = _param_i_ref.Get().(testpkg.I) + } else { // foreign object + _param_i = (*proxytestpkg_I)(_param_i_ref) + } + } + testpkg.RegisterI(_param_idx, _param_i) +} + +//export proxytestpkg__ReturnsError +func proxytestpkg__ReturnsError(param_b C.char) (C.nstring, C.nstring) { + _param_b := param_b != 0 + res_0, res_1 := testpkg.ReturnsError(_param_b) + _res_0 := encodeString(res_0, true) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 +} + +//export proxytestpkg__StringDup +func proxytestpkg__StringDup(param_s C.nstring) C.nstring { + _param_s := decodeString(param_s, false) + res_0 := testpkg.StringDup(_param_s) + _res_0 := encodeString(res_0, true) + return _res_0 +} + +//export proxytestpkg__Sum +func proxytestpkg__Sum(param_x C.int64_t, param_y C.int64_t) C.int64_t { + _param_x := int64(param_x) + _param_y := int64(param_y) + res_0 := testpkg.Sum(_param_x, _param_y) + _res_0 := C.int64_t(res_0) + return _res_0 +} + +//export proxytestpkg__UnregisterI +func proxytestpkg__UnregisterI(param_idx C.int32_t) { + _param_idx := int32(param_idx) + testpkg.UnregisterI(_param_idx) } diff --git a/bind/objc/testpkg/go_testpkg/testpkg.h b/bind/objc/testpkg/go_testpkg/testpkg.h new file mode 100644 index 0000000..d284cd1 --- /dev/null +++ b/bind/objc/testpkg/go_testpkg/testpkg.h @@ -0,0 +1,23 @@ +// Objective-C API for talking to golang.org/x/mobile/bind/objc/testpkg Go package. +// gobind -lang=objc golang.org/x/mobile/bind/objc/testpkg +// +// File is generated by gobind. Do not edit. + +#ifndef __testpkg_H__ +#define __testpkg_H__ + +#include +#include +nstring cproxytestpkg_I_Error(int32_t refnum, char triggerError); + +typedef struct cproxytestpkg_I_StringError_return { + nstring r0; + nstring r1; +} cproxytestpkg_I_StringError_return; +struct cproxytestpkg_I_StringError_return cproxytestpkg_I_StringError(int32_t refnum, nstring s); + +int64_t cproxytestpkg_I_Times(int32_t refnum, int32_t v); + +int32_t cproxytestpkg_NullTest_Null(int32_t refnum); + +#endif diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m b/bind/objc/testpkg/objc_testpkg/GoTestpkg.m deleted file mode 100644 index 362c891..0000000 --- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m +++ /dev/null @@ -1,740 +0,0 @@ -// Objective-C API for talking to golang.org/x/mobile/bind/objc/testpkg Go package. -// gobind -lang=objc golang.org/x/mobile/bind/objc/testpkg -// -// File is generated by gobind. Do not edit. - -#include "GoTestpkg.h" -#include -#include "seq.h" - -static NSString* errDomain = @"go.golang.org/x/mobile/bind/objc/testpkg"; - -@protocol goSeqRefInterface --(GoSeqRef*) _ref; -@end - -#define _DESCRIPTOR_ "testpkg" - -@class GoTestpkgI; - -@class GoTestpkgZ; - -@interface GoTestpkgI : NSObject { -} -@property(strong, readonly) id _ref; - -- (id)initWithRef:(id)ref; -- (BOOL)error:(BOOL)triggerError error:(NSError**)error; -- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error; -- (int64_t)times:(int32_t)v; -@end - -@interface GoTestpkgZ : NSObject { -} -@property(strong, readonly) id _ref; - -- (id)initWithRef:(id)ref; -@end - -#define _GO_testpkg_Node_DESCRIPTOR_ "go.testpkg.Node" -#define _GO_testpkg_Node_FIELD_V_GET_ (0x00f) -#define _GO_testpkg_Node_FIELD_V_SET_ (0x01f) -#define _GO_testpkg_Node_FIELD_Err_GET_ (0x10f) -#define _GO_testpkg_Node_FIELD_Err_SET_ (0x11f) - -@implementation GoTestpkgNode { -} - -- (id)initWithRef:(id)ref { - self = [super init]; - if (self) { __ref = ref; } - return self; -} - -- (NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_V_GET_, &in_, &out_); - NSString* ret_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; -} - -- (void)setV:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, v); - go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_V_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -- (NSString*)err { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_Err_GET_, &in_, &out_); - NSString* ret_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; -} - -- (void)setErr:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, v); - go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_Err_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -@end - -#define _GO_testpkg_S_DESCRIPTOR_ "go.testpkg.S" -#define _GO_testpkg_S_FIELD_X_GET_ (0x00f) -#define _GO_testpkg_S_FIELD_X_SET_ (0x01f) -#define _GO_testpkg_S_FIELD_Y_GET_ (0x10f) -#define _GO_testpkg_S_FIELD_Y_SET_ (0x11f) -#define _GO_testpkg_S_Sum_ (0x00c) -#define _GO_testpkg_S_TryTwoStrings_ (0x10c) - -@implementation GoTestpkgS { -} - -- (id)initWithRef:(id)ref { - self = [super init]; - if (self) { __ref = ref; } - return self; -} - -- (double)x { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_X_GET_, &in_, &out_); - double ret_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; -} - -- (void)setX:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeFloat64(&in_, v); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_X_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -- (double)y { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_Y_GET_, &in_, &out_); - double ret_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; -} - -- (void)setY:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeFloat64(&in_, v); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_Y_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -- (double)sum { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_Sum_, &in_, &out_); - double ret0_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -- (NSString*)tryTwoStrings:(NSString*)first second:(NSString*)second { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, first); - go_seq_writeUTF8(&in_, second); - go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_TryTwoStrings_, &in_, &out_); - NSString* ret0_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -@end - -#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_ "go.testpkg.StructThatStartsWithLetterBeforeZ" -#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_GET_ (0x00f) -#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_SET_ (0x01f) - -@implementation GoTestpkgStructThatStartsWithLetterBeforeZ { -} - -- (id)initWithRef:(id)ref { - self = [super init]; - if (self) { __ref = ref; } - return self; -} - -- (id)value { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_, _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_GET_, &in_, &out_); - GoSeqRef* ret__ref = go_seq_readRef(&out_); - id ret_ = ret__ref.obj; - if (ret_ == NULL) { - ret_ = [[GoTestpkgZ alloc] initWithRef:ret__ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; -} - -- (void)setValue:(id)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - if ([(id)(v) isKindOfClass:[GoTestpkgZ class]]) { - id v_proxy = (id)(v); - go_seq_writeRef(&in_, v_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, v); - } - go_seq_send(_GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_, _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -@end - -#define _GO_testpkg_I_DESCRIPTOR_ "go.testpkg.I" -#define _GO_testpkg_I_Error_ (0x10a) -#define _GO_testpkg_I_StringError_ (0x20a) -#define _GO_testpkg_I_Times_ (0x30a) - -@implementation GoTestpkgI { -} - -- (id)initWithRef:(id)ref { - self = [super init]; - if (self) { __ref = ref; } - return self; -} - -- (BOOL)error:(BOOL)triggerError error:(NSError**)error { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeBool(&in_, triggerError); - go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Error_, &in_, &out_); - NSString* _error = go_seq_readUTF8(&out_); - if ([_error length] != 0 && error != nil) { - NSMutableDictionary* details = [NSMutableDictionary dictionary]; - [details setValue:_error forKey:NSLocalizedDescriptionKey]; - *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ([_error length] == 0); -} - -- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, s); - go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_StringError_, &in_, &out_); - NSString* ret0__val = go_seq_readUTF8(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__val; - } - NSString* _error = go_seq_readUTF8(&out_); - if ([_error length] != 0 && error != nil) { - NSMutableDictionary* details = [NSMutableDictionary dictionary]; - [details setValue:_error forKey:NSLocalizedDescriptionKey]; - *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ([_error length] == 0); -} - -- (int64_t)times:(int32_t)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeInt32(&in_, v); - go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Times_, &in_, &out_); - int64_t ret0_ = go_seq_readInt64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -@end - -static void proxyGoTestpkgI(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_testpkg_I_Error_: { - id o = (id)(obj); - BOOL triggerError = go_seq_readBool(in); - NSError* error = NULL; - BOOL returnVal = [o error:triggerError error:&error]; - if (returnVal) { - go_seq_writeUTF8(out, NULL); - } else { - NSString* errorDesc = [error localizedDescription]; - if (errorDesc == NULL || errorDesc.length == 0) { - errorDesc = @"gobind: unknown error"; - } - go_seq_writeUTF8(out, errorDesc); - } - } break; - case _GO_testpkg_I_StringError_: { - id o = (id)(obj); - NSString* s = go_seq_readUTF8(in); - NSString* ret0_; - NSError* error = NULL; - BOOL returnVal = [o stringError:s ret0_:&ret0_ error:&error]; - go_seq_writeUTF8(out, ret0_); - if (returnVal) { - go_seq_writeUTF8(out, NULL); - } else { - NSString* errorDesc = [error localizedDescription]; - if (errorDesc == NULL || errorDesc.length == 0) { - errorDesc = @"gobind: unknown error"; - } - go_seq_writeUTF8(out, errorDesc); - } - } break; - case _GO_testpkg_I_Times_: { - id o = (id)(obj); - int32_t v = go_seq_readInt32(in); - int64_t returnVal = [o times:v]; - go_seq_writeInt64(out, returnVal); - } break; - default: - NSLog(@"unknown code %x for _GO_testpkg_I_DESCRIPTOR_", code); - } -} - -#define _GO_testpkg_Z_DESCRIPTOR_ "go.testpkg.Z" - -@implementation GoTestpkgZ { -} - -- (id)initWithRef:(id)ref { - self = [super init]; - if (self) { __ref = ref; } - return self; -} - -@end - -static void proxyGoTestpkgZ(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - default: - NSLog(@"unknown code %x for _GO_testpkg_Z_DESCRIPTOR_", code); - } -} - -const BOOL GoTestpkgABool = YES; -const double GoTestpkgAFloat = 0.12345; -NSString* const GoTestpkgAString = @"a string"; -const int64_t GoTestpkgAnInt = 7LL; -const double GoTestpkgLog2E = 1.4426950408889634; -const float GoTestpkgMaxFloat32 = 3.4028234663852886e+38; -const double GoTestpkgMaxFloat64 = 1.7976931348623157e+308; -const int32_t GoTestpkgMaxInt32 = 2147483647; -const int64_t GoTestpkgMaxInt64 = 9223372036854775807LL; -const int32_t GoTestpkgMinInt32 = -2147483648; -const int64_t GoTestpkgMinInt64 = -9223372036854775807LL-1; -const float GoTestpkgSmallestNonzeroFloat32 = 0; -const double GoTestpkgSmallestNonzeroFloat64 = 5e-324; - -@implementation GoTestpkg -+ (void) setIntVar:(int)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt(&in_, v); - go_seq_send("testpkg.IntVar", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -+ (int) intVar { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("testpkg.IntVar", 2, &in_, &out_); - int ret = go_seq_readInt(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; -} - -+ (void) setInterfaceVar:(id)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - if ([(id)(v) isKindOfClass:[GoTestpkgI class]]) { - id v_proxy = (id)(v); - go_seq_writeRef(&in_, v_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, v); - } - go_seq_send("testpkg.InterfaceVar", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -+ (id) interfaceVar { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("testpkg.InterfaceVar", 2, &in_, &out_); - GoSeqRef* ret_ref = go_seq_readRef(&out_); - id ret = ret_ref.obj; - if (ret == NULL) { - ret = [[GoTestpkgI alloc] initWithRef:ret_ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret; -} - -+ (void) setStringVar:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeUTF8(&in_, v); - go_seq_send("testpkg.StringVar", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -+ (NSString*) stringVar { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("testpkg.StringVar", 2, &in_, &out_); - NSString* ret = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; -} - -+ (void) setStructVar:(GoTestpkgNode*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - if ([(id)(v) isKindOfClass:[GoTestpkgNode class]]) { - id v_proxy = (id)(v); - go_seq_writeRef(&in_, v_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, v); - } - go_seq_send("testpkg.StructVar", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -+ (GoTestpkgNode*) structVar { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("testpkg.StructVar", 2, &in_, &out_); - GoSeqRef* ret_ref = go_seq_readRef(&out_); - GoTestpkgNode* ret = ret_ref.obj; - if (ret == NULL) { - ret = [[GoTestpkgNode alloc] initWithRef:ret_ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret; -} - -@end - -#define _CALL_BytesAppend_ 1 -#define _CALL_CallIError_ 2 -#define _CALL_CallIStringError_ 3 -#define _CALL_CallSSum_ 4 -#define _CALL_CollectS_ 5 -#define _CALL_Echo_ 6 -#define _CALL_GC_ 7 -#define _CALL_Hello_ 8 -#define _CALL_Hi_ 9 -#define _CALL_Int_ 10 -#define _CALL_Multiply_ 11 -#define _CALL_NewI_ 12 -#define _CALL_NewNode_ 13 -#define _CALL_NewS_ 14 -#define _CALL_RegisterI_ 15 -#define _CALL_ReturnsError_ 16 -#define _CALL_Sum_ 17 -#define _CALL_UnregisterI_ 18 - -NSData* GoTestpkgBytesAppend(NSData* a, NSData* b) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeByteArray(&in_, a); - go_seq_writeByteArray(&in_, b); - go_seq_send(_DESCRIPTOR_, _CALL_BytesAppend_, &in_, &out_); - NSData* ret0_ = go_seq_readByteArray(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -BOOL GoTestpkgCallIError(id i, BOOL triggerError, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; - if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { - id i_proxy = (id)(i); - go_seq_writeRef(&in_, i_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, i); - } - go_seq_writeBool(&in_, triggerError); - go_seq_send(_DESCRIPTOR_, _CALL_CallIError_, &in_, &out_); - NSString* _error = go_seq_readUTF8(&out_); - if ([_error length] != 0 && error != nil) { - NSMutableDictionary* details = [NSMutableDictionary dictionary]; - [details setValue:_error forKey:NSLocalizedDescriptionKey]; - *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ([_error length] == 0); -} - -BOOL GoTestpkgCallIStringError(id i, NSString* s, NSString** ret0_, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; - if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { - id i_proxy = (id)(i); - go_seq_writeRef(&in_, i_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, i); - } - go_seq_writeUTF8(&in_, s); - go_seq_send(_DESCRIPTOR_, _CALL_CallIStringError_, &in_, &out_); - NSString* ret0__val = go_seq_readUTF8(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__val; - } - NSString* _error = go_seq_readUTF8(&out_); - if ([_error length] != 0 && error != nil) { - NSMutableDictionary* details = [NSMutableDictionary dictionary]; - [details setValue:_error forKey:NSLocalizedDescriptionKey]; - *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ([_error length] == 0); -} - -double GoTestpkgCallSSum(GoTestpkgS* s) { - GoSeq in_ = {}; - GoSeq out_ = {}; - if ([(id)(s) isKindOfClass:[GoTestpkgS class]]) { - id s_proxy = (id)(s); - go_seq_writeRef(&in_, s_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, s); - } - go_seq_send(_DESCRIPTOR_, _CALL_CallSSum_, &in_, &out_); - double ret0_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -int GoTestpkgCollectS(int want, int timeoutSec) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt(&in_, want); - go_seq_writeInt(&in_, timeoutSec); - go_seq_send(_DESCRIPTOR_, _CALL_CollectS_, &in_, &out_); - int ret0_ = go_seq_readInt(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -NSString* GoTestpkgEcho(NSString* s) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeUTF8(&in_, s); - go_seq_send(_DESCRIPTOR_, _CALL_Echo_, &in_, &out_); - NSString* ret0_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -void GoTestpkgGC() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_GC_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -NSString* GoTestpkgHello(NSString* s) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeUTF8(&in_, s); - go_seq_send(_DESCRIPTOR_, _CALL_Hello_, &in_, &out_); - NSString* ret0_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -void GoTestpkgHi() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_Hi_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -void GoTestpkgInt(int32_t x) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt32(&in_, x); - go_seq_send(_DESCRIPTOR_, _CALL_Int_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -int64_t GoTestpkgMultiply(int32_t idx, int32_t val) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt32(&in_, idx); - go_seq_writeInt32(&in_, val); - go_seq_send(_DESCRIPTOR_, _CALL_Multiply_, &in_, &out_); - int64_t ret0_ = go_seq_readInt64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -id GoTestpkgNewI() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_NewI_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - id ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoTestpkgI alloc] initWithRef:ret0__ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -GoTestpkgNode* GoTestpkgNewNode(NSString* name) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeUTF8(&in_, name); - go_seq_send(_DESCRIPTOR_, _CALL_NewNode_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - GoTestpkgNode* ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoTestpkgNode alloc] initWithRef:ret0__ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -GoTestpkgS* GoTestpkgNewS(double x, double y) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeFloat64(&in_, x); - go_seq_writeFloat64(&in_, y); - go_seq_send(_DESCRIPTOR_, _CALL_NewS_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - GoTestpkgS* ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoTestpkgS alloc] initWithRef:ret0__ref]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -void GoTestpkgRegisterI(int32_t idx, id i) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt32(&in_, idx); - if ([(id)(i) isKindOfClass:[GoTestpkgI class]]) { - id i_proxy = (id)(i); - go_seq_writeRef(&in_, i_proxy._ref); - } else { - go_seq_writeObjcRef(&in_, i); - } - go_seq_send(_DESCRIPTOR_, _CALL_RegisterI_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -BOOL GoTestpkgReturnsError(BOOL b, NSString** ret0_, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeBool(&in_, b); - go_seq_send(_DESCRIPTOR_, _CALL_ReturnsError_, &in_, &out_); - NSString* ret0__val = go_seq_readUTF8(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__val; - } - NSString* _error = go_seq_readUTF8(&out_); - if ([_error length] != 0 && error != nil) { - NSMutableDictionary* details = [NSMutableDictionary dictionary]; - [details setValue:_error forKey:NSLocalizedDescriptionKey]; - *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; - } - go_seq_free(&in_); - go_seq_free(&out_); - return ([_error length] == 0); -} - -int64_t GoTestpkgSum(int64_t x, int64_t y) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt64(&in_, x); - go_seq_writeInt64(&in_, y); - go_seq_send(_DESCRIPTOR_, _CALL_Sum_, &in_, &out_); - int64_t ret0_ = go_seq_readInt64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; -} - -void GoTestpkgUnregisterI(int32_t idx) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt32(&in_, idx); - go_seq_send(_DESCRIPTOR_, _CALL_UnregisterI_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); -} - -__attribute__((constructor)) static void init() { - go_seq_register_proxy("go.testpkg.I", proxyGoTestpkgI); - go_seq_register_proxy("go.testpkg.Z", proxyGoTestpkgZ); -} diff --git a/bind/objc/testpkg/testpkg.go b/bind/objc/testpkg/testpkg.go index 92c9594..776a953 100644 --- a/bind/objc/testpkg/testpkg.go +++ b/bind/objc/testpkg/testpkg.go @@ -4,8 +4,8 @@ package testpkg -//go:generate gobind -lang=go -outdir=go_testpkg . -//go:generate gobind -lang=objc -outdir=objc_testpkg . +//go:generate gobind -lang=go -outdir=go_testpkg golang.org/x/mobile/bind/objc/testpkg +//go:generate gobind -lang=objc -outdir=go_testpkg golang.org/x/mobile/bind/objc/testpkg import ( "errors" @@ -97,6 +97,8 @@ func Multiply(idx int32, val int32) int64 { func GC() { runtime.GC() + // Allow for finalizers to run and release any foreign references + time.Sleep(100 * time.Millisecond) } func Hi() { @@ -192,3 +194,42 @@ type Z interface { func Echo(s string) string { return s } + +type NullTest interface { + Null() NullTest +} + +func NewNullInterface() I { + return nil +} + +func NewNullStruct() *S { + return nil +} + +func CallWithNull(_null NullTest, nuller NullTest) bool { + return _null == nil && nuller.Null() == nil +} + +func ReadIntoByteArray(s []byte) (int, error) { + if len(s) != cap(s) { + return 0, fmt.Errorf("cap %d != len %d", cap(s), len(s)) + } + for i := 0; i < len(s); i++ { + s[i] = byte(i) + } + return len(s), nil +} + +// Issue #13033 +type NullFieldStruct struct { + F *S +} + +func NewNullFieldStruct() *NullFieldStruct { + return &NullFieldStruct{} +} + +func StringDup(s string) string { + return s +} diff --git a/bind/seq.go b/bind/seq.go deleted file mode 100644 index 5ba0274..0000000 --- a/bind/seq.go +++ /dev/null @@ -1,87 +0,0 @@ -package bind - -import ( - "fmt" - "go/types" -) - -// seqType returns a string that can be used for reading and writing a -// type using the seq library. -// TODO(hyangah): avoid panic; gobind needs to output the problematic code location. -func seqType(t types.Type) string { - if isErrorType(t) { - return "String" - } - switch t := t.(type) { - case *types.Basic: - switch t.Kind() { - case types.Bool: - return "Bool" - case types.Int: - return "Int" - case types.Int8: - return "Int8" - case types.Int16: - return "Int16" - case types.Int32: - return "Int32" - case types.Int64: - return "Int64" - case types.Uint8: // Byte. - // TODO(crawshaw): questionable, but vital? - return "Byte" - // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: - case types.Float32: - return "Float32" - case types.Float64: - return "Float64" - case types.String: - return "String" - default: - // Should be caught earlier in processing. - panic(fmt.Sprintf("unsupported basic seqType: %s", t)) - } - case *types.Named: - switch u := t.Underlying().(type) { - case *types.Interface: - return "Ref" - default: - panic(fmt.Sprintf("unsupported named seqType: %s / %T", u, u)) - } - case *types.Slice: - switch e := t.Elem().(type) { - case *types.Basic: - switch e.Kind() { - case types.Uint8: // Byte. - return "ByteArray" - default: - panic(fmt.Sprintf("unsupported seqType: %s(%s) / %T(%T)", t, e, t, e)) - } - default: - panic(fmt.Sprintf("unsupported seqType: %s(%s) / %T(%T)", t, e, t, e)) - } - // TODO: let the types.Array case handled like types.Slice? - case *types.Pointer: - if _, ok := t.Elem().(*types.Named); ok { - return "Ref" - } - panic(fmt.Sprintf("not supported yet, pointer type: %s / %T", t, t)) - - default: - panic(fmt.Sprintf("unsupported seqType: %s / %T", t, t)) - } -} - -func seqRead(o types.Type) string { - t := seqType(o) - return t + "()" -} - -func seqWrite(o types.Type, name string) string { - t := seqType(o) - if t == "Ref" { - // TODO(crawshaw): do something cleaner, i.e. genWrite. - return t + "(" + name + " != null ? " + name + ".ref() : null)" - } - return t + "(" + name + ")" -} diff --git a/bind/seq.go.support b/bind/seq.go.support new file mode 100644 index 0000000..a8169ee --- /dev/null +++ b/bind/seq.go.support @@ -0,0 +1,36 @@ +// 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 gomobile_bind + +// Go support functions for generated Go bindings. This file is +// copied into the generated package, gomobile_bind, and compiled +// along with the bindings. + +// #include +// #include "seq.h" +import "C" + +import ( + "errors" + "fmt" + + _seq "golang.org/x/mobile/bind/seq" +) + +func toError(s string) error { + if s == "" { + return nil + } + return errors.New(s) +} + +func init() { + _seq.FinalizeRef = func(ref *_seq.Ref) { + if ref.Num < 0 { + panic(fmt.Sprintf("not a foreign ref: %d", ref.Num)) + } + C.go_seq_dec_ref(C.int32_t(ref.Num)) + } +} diff --git a/bind/seq/buffer.go b/bind/seq/buffer.go deleted file mode 100644 index 45f40ca..0000000 --- a/bind/seq/buffer.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2014 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 seq - -import ( - "bytes" - "fmt" - "runtime" - "unsafe" -) - -// Buffer is a set of arguments or return values from a function call -// across the language boundary. Encoding is machine-dependent. -type Buffer struct { - Data []byte - Offset int // position of next read/write from Data -} - -func (b *Buffer) String() string { - // Debugging. - var buf bytes.Buffer - fmt.Fprintf(&buf, "seq{Off=%d, Len=%d Data=", b.Offset, len(b.Data)) - const hextable = "0123456789abcdef" - for i, v := range b.Data { - if i > 0 { - buf.WriteByte(':') - } - buf.WriteByte(hextable[v>>4]) - buf.WriteByte(hextable[v&0x0f]) - } - buf.WriteByte('}') - return buf.String() -} - -func (b *Buffer) panic(need int) { - panic(fmt.Sprintf("need %d bytes: %s", need, b)) -} - -func (b *Buffer) grow(need int) { - size := len(b.Data) - if size == 0 { - size = 2 - } - for size < need { - size *= 2 - } - data := make([]byte, size+len(b.Data)) - copy(data, b.Data[:b.Offset]) - b.Data = data -} - -// align returns the aligned offset. -func align(offset, alignment int) int { - pad := offset % alignment - if pad > 0 { - pad = alignment - pad - } - return pad + offset -} - -func (b *Buffer) ReadInt8() int8 { - offset := b.Offset - if len(b.Data)-offset < 1 { - b.panic(1) - } - v := *(*int8)(unsafe.Pointer(&b.Data[offset])) - b.Offset++ - return v -} - -func (b *Buffer) ReadInt16() int16 { - offset := align(b.Offset, 2) - if len(b.Data)-offset < 2 { - b.panic(2) - } - v := *(*int16)(unsafe.Pointer(&b.Data[offset])) - b.Offset = offset + 2 - return v -} - -func (b *Buffer) ReadInt32() int32 { - offset := align(b.Offset, 4) - if len(b.Data)-offset < 4 { - b.panic(4) - } - v := *(*int32)(unsafe.Pointer(&b.Data[offset])) - b.Offset = offset + 4 - return v -} - -func (b *Buffer) ReadInt64() int64 { - offset := align(b.Offset, 8) - if len(b.Data)-offset < 8 { - b.panic(8) - } - v := *(*int64)(unsafe.Pointer(&b.Data[offset])) - b.Offset = offset + 8 - return v -} - -func (b *Buffer) ReadBool() bool { - return b.ReadInt8() != 0 -} - -func (b *Buffer) ReadInt() int { - return int(b.ReadInt64()) -} - -func (b *Buffer) ReadFloat32() float32 { - offset := align(b.Offset, 4) - if len(b.Data)-offset < 4 { - b.panic(4) - } - v := *(*float32)(unsafe.Pointer(&b.Data[offset])) - b.Offset = offset + 4 - return v -} - -func (b *Buffer) ReadFloat64() float64 { - offset := align(b.Offset, 8) - if len(b.Data)-offset < 8 { - b.panic(8) - } - v := *(*float64)(unsafe.Pointer(&b.Data[offset])) - b.Offset = offset + 8 - return v -} - -func (b *Buffer) ReadByteArray() []byte { - sz := b.ReadInt64() - if sz == 0 { - return nil - } - - ptr := b.ReadInt64() - org := (*[1 << 30]byte)(unsafe.Pointer(uintptr(ptr)))[:sz] - - // Make a copy managed by Go, so the returned byte array can be - // used safely in Go. - slice := make([]byte, sz) - copy(slice, org) - return slice -} - -func (b *Buffer) ReadRef() *Ref { - ref := &Ref{b.ReadInt32()} - if ref.Num > 0 { - // This is a foreign object reference. - // Track its lifetime with a finalizer. - runtime.SetFinalizer(ref, FinalizeRef) - } - return ref -} - -func (b *Buffer) ReadString() string { - return DecString(b) -} - -func (b *Buffer) WriteInt8(v int8) { - offset := b.Offset - if len(b.Data)-offset < 1 { - b.grow(offset + 1 - len(b.Data)) - } - *(*int8)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset++ -} - -func (b *Buffer) WriteInt16(v int16) { - offset := align(b.Offset, 2) - if len(b.Data)-offset < 2 { - b.grow(offset + 2 - len(b.Data)) - } - *(*int16)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset = offset + 2 -} - -func (b *Buffer) WriteInt32(v int32) { - offset := align(b.Offset, 4) - if len(b.Data)-offset < 4 { - b.grow(offset + 4 - len(b.Data)) - } - *(*int32)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset = offset + 4 -} - -func (b *Buffer) WriteInt64(v int64) { - offset := align(b.Offset, 8) - if len(b.Data)-offset < 8 { - b.grow(offset + 8 - len(b.Data)) - } - *(*int64)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset = offset + 8 -} - -func (b *Buffer) WriteBool(v bool) { - if v { - b.WriteInt8(1) - } else { - b.WriteInt8(0) - } -} - -func (b *Buffer) WriteInt(v int) { - b.WriteInt64(int64(v)) -} - -func (b *Buffer) WriteFloat32(v float32) { - offset := align(b.Offset, 4) - if len(b.Data)-offset < 4 { - b.grow(offset + 4 - len(b.Data)) - } - *(*float32)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset = offset + 4 -} - -func (b *Buffer) WriteFloat64(v float64) { - offset := align(b.Offset, 8) - if len(b.Data)-offset < 8 { - b.grow(offset + 8 - len(b.Data)) - } - *(*float64)(unsafe.Pointer(&b.Data[offset])) = v - b.Offset = offset + 8 -} - -func (b *Buffer) WriteByteArray(byt []byte) { - sz := len(byt) - if sz == 0 { - b.WriteInt64(int64(sz)) - return - } - - ptr := uintptr(unsafe.Pointer(&byt[0])) - b.WriteInt64(int64(sz)) - b.WriteInt64(int64(ptr)) - return -} - -func (b *Buffer) WriteString(v string) { - EncString(b, v) -} - -func (b *Buffer) WriteGoRef(obj interface{}) { - refs.Lock() - num := refs.refs[obj] - if num != 0 { - s := refs.objs[num] - refs.objs[num] = countedObj{s.obj, s.cnt + 1} - } else { - num = refs.next - refs.next-- - if refs.next > 0 { - panic("refs.next underflow") - } - refs.refs[obj] = num - refs.objs[num] = countedObj{obj, 1} - } - refs.Unlock() - - b.WriteInt32(int32(num)) -} - -/* TODO: Will we need it? -func (b *Buffer) WriteRef(ref *Ref) { - b.WriteInt32(ref.Num) -} -*/ diff --git a/bind/seq/ref.go b/bind/seq/ref.go index c4811f7..39519e9 100644 --- a/bind/seq/ref.go +++ b/bind/seq/ref.go @@ -11,6 +11,7 @@ package seq import ( "fmt" + "runtime" "sync" ) @@ -19,7 +20,8 @@ type countedObj struct { cnt int32 } -const NullRefNum = 41 // also known to bind/java/Seq.java +// also known to bind/java/Seq.java and bind/objc/seq_darwin.m +const NullRefNum = 41 // refs stores Go objects that have been passed to another language. var refs struct { @@ -43,6 +45,44 @@ type Ref struct { Num int32 } +// ToRefNum increments the reference count for a Go object and +// return its refnum. +func ToRefNum(obj interface{}) int32 { + refs.Lock() + num := refs.refs[obj] + if num != 0 { + s := refs.objs[num] + refs.objs[num] = countedObj{s.obj, s.cnt + 1} + } else { + num = refs.next + refs.next-- + if refs.next > 0 { + panic("refs.next underflow") + } + refs.refs[obj] = num + refs.objs[num] = countedObj{obj, 1} + } + refs.Unlock() + + return int32(num) +} + +// FromRefNum returns the Ref for a refnum. If the refnum specifies a +// foreign object, a finalizer is set to track its lifetime. +func FromRefNum(num int32) *Ref { + if num == NullRefNum { + return nil + } + ref := &Ref{num} + if ref.Num > 0 { + // This is a foreign object reference. + // Track its lifetime with a finalizer. + runtime.SetFinalizer(ref, FinalizeRef) + } + + return ref +} + // Get returns the underlying object. func (r *Ref) Get() interface{} { refs.Lock() diff --git a/bind/seq/seq.go b/bind/seq/seq.go index 21f3093..4807604 100644 --- a/bind/seq/seq.go +++ b/bind/seq/seq.go @@ -11,46 +11,7 @@ // use this directly. package seq // import "golang.org/x/mobile/bind/seq" -// TODO(crawshaw): -// There is opportunity for optimizing these language -// bindings which requires deconstructing seq into something -// gnarly. So don't get too attached to the design. - -import ( - "fmt" - - _ "golang.org/x/mobile/internal/mobileinit" -) - -// Transact calls a method on a foreign object instance. -// It blocks until the call is complete. -var Transact func(ref *Ref, desc string, code int, in *Buffer) (out *Buffer) +import _ "golang.org/x/mobile/internal/mobileinit" // FinalizeRef is the finalizer used on foreign objects. var FinalizeRef func(ref *Ref) - -// A Func can be registered and called by a foreign language. -type Func func(out, in *Buffer) - -// Registry holds functions callable from gobind generated bindings. -// Functions are keyed by descriptor and function code. -var Registry = make(map[string]map[int]Func) - -// Register registers a function in the Registry. -func Register(descriptor string, code int, fn Func) { - m := Registry[descriptor] - if m == nil { - m = make(map[int]Func) - Registry[descriptor] = m - } - if m[code] != nil { - panic(fmt.Sprintf("registry.Register: %q/%d already registered", descriptor, code)) - } - m[code] = fn -} - -// DecString decodes a string encoded in the Buffer. -var DecString func(in *Buffer) string - -// EncString encodes a Go string into the Buffer. -var EncString func(out *Buffer, v string) diff --git a/bind/seq/seq_test.go b/bind/seq/seq_test.go deleted file mode 100644 index cc24292..0000000 --- a/bind/seq/seq_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 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 seq - -import "testing" - -func TestBuffer(t *testing.T) { - buf := new(Buffer) - buf.WriteInt64(1 << 42) - buf.WriteInt32(1 << 13) - buf.WriteUTF16("Hello, world") - buf.WriteFloat64(4.02) - buf.WriteFloat32(1.2) - buf.WriteGoRef(new(int)) - buf.WriteGoRef(new(int)) - - buf.Offset = 0 - - if got, want := buf.ReadInt64(), int64(1<<42); got != want { - t.Errorf("buf.ReadInt64()=%d, want %d", got, want) - } - if got, want := buf.ReadInt32(), int32(1<<13); got != want { - t.Errorf("buf.ReadInt32()=%d, want %d", got, want) - } - if got, want := buf.ReadUTF16(), "Hello, world"; got != want { - t.Errorf("buf.ReadUTF16()=%q, want %q", got, want) - } - if got, want := buf.ReadFloat64(), 4.02; got != want { - t.Errorf("buf.ReadFloat64()=%f, want %f", got, want) - } - if got, want := buf.ReadFloat32(), float32(1.2); got != want { - t.Errorf("buf.ReadFloat32()=%f, want %f", got, want) - } -} diff --git a/bind/seq/string.go b/bind/seq/string.go index 2035008..a39b115 100644 --- a/bind/seq/string.go +++ b/bind/seq/string.go @@ -5,8 +5,6 @@ package seq import ( - "errors" - "fmt" "unicode/utf16" "unsafe" ) @@ -33,18 +31,10 @@ func writeUint16(b []byte, v rune) { *(*uint16)(unsafe.Pointer(&b[0])) = uint16(v) } -func (b *Buffer) WriteUTF16(s string) { - // The first 4 bytes is the length, as int32 (4-byte aligned). - // written last. - // The next n bytes is utf-16 string (1-byte aligned). - offset0 := align(b.Offset, 4) // length. - offset1 := align(offset0+4, 1) // contents. - - if len(b.Data)-offset1 < 4*len(s) { - // worst case estimate, everything is surrogate pair - b.grow(offset1 + 4*len(s) - len(b.Data)) - } - data := b.Data[offset1:] +// UTF16Encode utf16 encodes s into chars. It returns the resulting +// length in units of uint16. It is assumed that the chars slice +// has enough room for the encoded string. +func UTF16Encode(s string, chars []uint16) int { n := 0 for _, v := range s { switch { @@ -52,72 +42,15 @@ func (b *Buffer) WriteUTF16(s string) { v = replacementChar fallthrough case v < surrSelf: - writeUint16(data[n:], v) - n += 2 + chars[n] = uint16(v) + n += 1 default: // surrogate pair, two uint16 values r1, r2 := utf16.EncodeRune(v) - writeUint16(data[n:], r1) - writeUint16(data[n+2:], r2) - n += 4 + chars[n] = uint16(r1) + chars[n+1] = uint16(r2) + n += 2 } } - - // write length at b.Data[b.Offset:], before contents. - // length is number of uint16 values, not number of bytes. - b.WriteInt32(int32(n / 2)) - - b.Offset = offset1 + n -} - -func (b *Buffer) WriteUTF8(s string) { - n := len(s) - b.WriteInt32(int32(n)) - if len(s) == 0 { - return - } - offset := align(b.Offset, 1) - if len(b.Data)-offset < n { - b.grow(offset + n - len(b.Data)) - } - copy(b.Data[offset:], s) - b.Offset = offset + n -} - -const maxSliceLen = (1<<31 - 1) / 2 - -func (b *Buffer) ReadError() error { - if s := b.ReadString(); s != "" { - return errors.New(s) - } - return nil -} - -func (b *Buffer) ReadUTF16() string { - size := int(b.ReadInt32()) - if size == 0 { - return "" - } - if size < 0 { - panic(fmt.Sprintf("string size negative: %d", size)) - } - offset := align(b.Offset, 1) - u := (*[maxSliceLen]uint16)(unsafe.Pointer(&b.Data[offset]))[:size] - s := string(utf16.Decode(u)) // TODO: save the []rune alloc - b.Offset = offset + 2*size - - return s -} - -func (b *Buffer) ReadUTF8() string { - size := int(b.ReadInt32()) - if size == 0 { - return "" - } - if size < 0 { - panic(fmt.Sprintf("string size negative: %d", size)) - } - offset := align(b.Offset, 1) - b.Offset = offset + size - return string(b.Data[offset : offset+size]) + return n } diff --git a/bind/seq/string_test.go b/bind/seq/string_test.go index 42e144e..21a54f6 100644 --- a/bind/seq/string_test.go +++ b/bind/seq/string_test.go @@ -4,7 +4,10 @@ package seq -import "testing" +import ( + "testing" + "unicode/utf16" +) var strData = []string{ "abcxyz09{}", @@ -12,40 +15,14 @@ var strData = []string{ string([]rune{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}), } -var stringEncoder = map[string]struct { - write func(*Buffer, string) - read func(*Buffer) string -}{ - "UTF16": {write: (*Buffer).WriteUTF16, read: (*Buffer).ReadUTF16}, - "UTF8": {write: (*Buffer).WriteUTF8, read: (*Buffer).ReadUTF8}, -} - func TestString(t *testing.T) { - for encoding, f := range stringEncoder { - for _, test := range strData { - buf := new(Buffer) - f.write(buf, test) - buf.Offset = 0 - got := f.read(buf) - if got != test { - t.Errorf("%s: got %q, want %q", encoding, got, test) - } - } - } -} - -func TestSequential(t *testing.T) { - for encoding, f := range stringEncoder { - buf := new(Buffer) - for _, test := range strData { - f.write(buf, test) - } - buf.Offset = 0 - for i, test := range strData { - got := f.read(buf) - if got != test { - t.Errorf("%s: %d: got %q, want %q", encoding, i, got, test) - } + for _, test := range strData { + chars := make([]uint16, 4*len(test)) + nchars := UTF16Encode(test, chars) + chars = chars[:nchars] + got := string(utf16.Decode(chars)) + if got != test { + t.Errorf("UTF16: got %q, want %q", got, test) } } } diff --git a/bind/testdata/basictypes.go.golden b/bind/testdata/basictypes.go.golden index de48b1f..89e6be7 100644 --- a/bind/testdata/basictypes.go.golden +++ b/bind/testdata/basictypes.go.golden @@ -1,58 +1,78 @@ -// Package go_basictypes is an autogenerated binder stub for package basictypes. +// Package gomobile_bind is an autogenerated binder stub for package basictypes. // gobind -lang=go basictypes // // File is generated by gobind. Do not edit. -package go_basictypes +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "basictypes.h" + +*/ +import "C" import ( "basictypes" _seq "golang.org/x/mobile/bind/seq" ) -func proxy_Bool(out, in *_seq.Buffer) { - param_p0 := in.ReadBool() - res := basictypes.Bool(param_p0) - out.WriteBool(res) -} +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum -func proxy_ByteArrays(out, in *_seq.Buffer) { - param_x := in.ReadByteArray() - res := basictypes.ByteArrays(param_x) - out.WriteByteArray(res) -} - -func proxy_Error(out, in *_seq.Buffer) { - err := basictypes.Error() - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) +//export proxybasictypes__Bool +func proxybasictypes__Bool(param_p0 C.char) C.char { + _param_p0 := param_p0 != 0 + res_0 := basictypes.Bool(_param_p0) + var _res_0 C.char = 0 + if res_0 { + _res_0 = 1 } + return _res_0 } -func proxy_ErrorPair(out, in *_seq.Buffer) { - res, err := basictypes.ErrorPair() - out.WriteInt(res) - if err == nil { - out.WriteString("") +//export proxybasictypes__ByteArrays +func proxybasictypes__ByteArrays(param_x C.nbyteslice) C.nbyteslice { + _param_x := toSlice(param_x, false) + res_0 := basictypes.ByteArrays(_param_x) + _res_0 := fromSlice(res_0, true) + return _res_0 +} + +//export proxybasictypes__Error +func proxybasictypes__Error() C.nstring { + res_0 := basictypes.Error() + var _res_0_str string + if res_0 == nil { + _res_0_str = "" } else { - out.WriteString(err.Error()) + _res_0_str = res_0.Error() } + _res_0 := encodeString(_res_0_str, true) + return _res_0 } -func proxy_Ints(out, in *_seq.Buffer) { - param_x := in.ReadInt8() - param_y := in.ReadInt16() - param_z := in.ReadInt32() - param_t := in.ReadInt64() - param_u := in.ReadInt() - basictypes.Ints(param_x, param_y, param_z, param_t, param_u) +//export proxybasictypes__ErrorPair +func proxybasictypes__ErrorPair() (C.nint, C.nstring) { + res_0, res_1 := basictypes.ErrorPair() + _res_0 := C.nint(res_0) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 } -func init() { - _seq.Register("basictypes", 1, proxy_Bool) - _seq.Register("basictypes", 2, proxy_ByteArrays) - _seq.Register("basictypes", 3, proxy_Error) - _seq.Register("basictypes", 4, proxy_ErrorPair) - _seq.Register("basictypes", 5, proxy_Ints) +//export proxybasictypes__Ints +func proxybasictypes__Ints(param_x C.int8_t, param_y C.int16_t, param_z C.int32_t, param_t C.int64_t, param_u C.nint) { + _param_x := int8(param_x) + _param_y := int16(param_y) + _param_z := int32(param_z) + _param_t := int64(param_t) + _param_u := int(param_u) + basictypes.Ints(_param_x, _param_y, _param_z, _param_t, _param_u) } diff --git a/bind/testdata/basictypes.java.c.golden b/bind/testdata/basictypes.java.c.golden new file mode 100644 index 0000000..5690011 --- /dev/null +++ b/bind/testdata/basictypes.java.c.golden @@ -0,0 +1,63 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java basictypes +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "basictypes.h" +#include "_cgo_export.h" + + + +JNIEXPORT void JNICALL +Java_go_basictypes_Basictypes_init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT jboolean JNICALL +Java_go_basictypes_Basictypes_Bool(JNIEnv* env, jclass clazz, jboolean p0) { + char _p0 = (char)p0; + char r0 = proxybasictypes__Bool(_p0); + jboolean _r0 = r0 ? JNI_TRUE : JNI_FALSE; + return _r0; +} + +JNIEXPORT jbyteArray JNICALL +Java_go_basictypes_Basictypes_ByteArrays(JNIEnv* env, jclass clazz, jbyteArray x) { + nbyteslice _x = go_seq_from_java_bytearray(env, x, 0); + nbyteslice r0 = proxybasictypes__ByteArrays(_x); + if (_x.ptr != NULL) { + (*env)->ReleaseByteArrayElements(env, x, _x.ptr, 0); + } + jbyteArray _r0 = go_seq_to_java_bytearray(env, r0, 1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_basictypes_Basictypes_Error(JNIEnv* env, jclass clazz) { + nstring r0 = proxybasictypes__Error(); + jstring _r0 = go_seq_to_java_string(env, r0); + go_seq_maybe_throw_exception(env, _r0); +} + +JNIEXPORT jlong JNICALL +Java_go_basictypes_Basictypes_ErrorPair(JNIEnv* env, jclass clazz) { + struct proxybasictypes__ErrorPair_return res = proxybasictypes__ErrorPair(); + jlong _r0 = (jlong)res.r0; + jstring _r1 = go_seq_to_java_string(env, res.r1); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_basictypes_Basictypes_Ints(JNIEnv* env, jclass clazz, jbyte x, jshort y, jint z, jlong t, jlong u) { + int8_t _x = (int8_t)x; + int16_t _y = (int16_t)y; + int32_t _z = (int32_t)z; + int64_t _t = (int64_t)t; + nint _u = (nint)u; + proxybasictypes__Ints(_x, _y, _z, _t, _u); +} + diff --git a/bind/testdata/basictypes.java.golden b/bind/testdata/basictypes.java.golden index 054735f..f3fecc9 100644 --- a/bind/testdata/basictypes.java.golden +++ b/bind/testdata/basictypes.java.golden @@ -7,79 +7,25 @@ package go.basictypes; import go.Seq; public abstract class Basictypes { + static { + Seq.touch(); // for loading the native library + init(); + } + private Basictypes() {} // uninstantiable + private static native void init(); + public static final boolean ABool = true; public static final double AFloat = 0.2015; public static final int ARune = 32; public static final String AString = "a string"; public static final long AnInt = 7L; public static final long AnInt2 = 9223372036854775807L; - public static boolean Bool(boolean p0) { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - boolean _result; - _in = new go.Seq(); - _in.writeBool(p0); - Seq.send(DESCRIPTOR, CALL_Bool, _in, _out); - _result = _out.readBool(); - return _result; - } - public static byte[] ByteArrays(byte[] x) { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - byte[] _result; - _in = new go.Seq(); - _in.writeByteArray(x); - Seq.send(DESCRIPTOR, CALL_ByteArrays, _in, _out); - _result = _out.readByteArray(); - return _result; - } - - public static void Error() throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - Seq.send(DESCRIPTOR, CALL_Error, _in, _out); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - } - - public static long ErrorPair() throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - long _result; - Seq.send(DESCRIPTOR, CALL_ErrorPair, _in, _out); - _result = _out.readInt(); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - return _result; - } - - public static void Ints(byte x, short y, int z, long t, long u) { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeInt8(x); - _in.writeInt16(y); - _in.writeInt32(z); - _in.writeInt64(t); - _in.writeInt(u); - Seq.send(DESCRIPTOR, CALL_Ints, _in, _out); - } - - private static final int CALL_Bool = 1; - private static final int CALL_ByteArrays = 2; - private static final int CALL_Error = 3; - private static final int CALL_ErrorPair = 4; - private static final int CALL_Ints = 5; - private static final String DESCRIPTOR = "basictypes"; + public static native boolean Bool(boolean p0); + public static native byte[] ByteArrays(byte[] x); + public static native void Error() throws Exception; + public static native long ErrorPair() throws Exception; + public static native void Ints(byte x, short y, int z, long t, long u); } diff --git a/bind/testdata/basictypes.java.h.golden b/bind/testdata/basictypes.java.h.golden new file mode 100644 index 0000000..89cc2fb --- /dev/null +++ b/bind/testdata/basictypes.java.h.golden @@ -0,0 +1,11 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java basictypes +// +// File is generated by gobind. Do not edit. + +#ifndef __Basictypes_H__ +#define __Basictypes_H__ + +#include + +#endif diff --git a/bind/testdata/basictypes.objc.go.h.golden b/bind/testdata/basictypes.objc.go.h.golden new file mode 100644 index 0000000..77c00b7 --- /dev/null +++ b/bind/testdata/basictypes.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to basictypes Go package. +// gobind -lang=objc basictypes +// +// File is generated by gobind. Do not edit. + +#ifndef __basictypes_H__ +#define __basictypes_H__ + +#include +#include +#endif diff --git a/bind/testdata/basictypes.objc.m.golden b/bind/testdata/basictypes.objc.m.golden index 959e5c9..8ee9e62 100644 --- a/bind/testdata/basictypes.objc.m.golden +++ b/bind/testdata/basictypes.objc.m.golden @@ -6,6 +6,7 @@ #include "GoBasictypes.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.basictypes"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.basictypes"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "basictypes" - const BOOL GoBasictypesABool = YES; const double GoBasictypesAFloat = 0.2015; const int32_t GoBasictypesARune = 32; @@ -22,78 +21,57 @@ NSString* const GoBasictypesAString = @"a string"; const int64_t GoBasictypesAnInt = 7LL; const int64_t GoBasictypesAnInt2 = 9223372036854775807LL; -#define _CALL_Bool_ 1 -#define _CALL_ByteArrays_ 2 -#define _CALL_Error_ 3 -#define _CALL_ErrorPair_ 4 -#define _CALL_Ints_ 5 BOOL GoBasictypesBool(BOOL p0) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeBool(&in_, p0); - go_seq_send(_DESCRIPTOR_, _CALL_Bool_, &in_, &out_); - BOOL ret0_ = go_seq_readBool(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + char _p0 = (char)p0; + char r0 = proxybasictypes__Bool(_p0); + BOOL _ret0_ = r0 ? YES : NO; + return _ret0_; } NSData* GoBasictypesByteArrays(NSData* x) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeByteArray(&in_, x); - go_seq_send(_DESCRIPTOR_, _CALL_ByteArrays_, &in_, &out_); - NSData* ret0_ = go_seq_readByteArray(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + nbyteslice _x = go_seq_from_objc_bytearray(x, 0); + nbyteslice r0 = proxybasictypes__ByteArrays(_x); + if (![x isKindOfClass:[NSMutableData class]]) { + free(_x.ptr); + } + NSData *_ret0_ = go_seq_to_objc_bytearray(r0, 1); + return _ret0_; } BOOL GoBasictypesError(NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_Error_, &in_, &out_); - NSString* _error = go_seq_readUTF8(&out_); + nstring r0 = proxybasictypes__Error(); + NSString *_error = go_seq_to_objc_string(r0); if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } BOOL GoBasictypesErrorPair(int* ret0_, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_ErrorPair_, &in_, &out_); - int ret0__val = go_seq_readInt(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__val; - } - NSString* _error = go_seq_readUTF8(&out_); + struct proxybasictypes__ErrorPair_return res = proxybasictypes__ErrorPair(); + int _ret0_ = (int)res.r0; + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } void GoBasictypesInts(int8_t x, int16_t y, int32_t z, int64_t t, int u) { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt8(&in_, x); - go_seq_writeInt16(&in_, y); - go_seq_writeInt32(&in_, z); - go_seq_writeInt64(&in_, t); - go_seq_writeInt(&in_, u); - go_seq_send(_DESCRIPTOR_, _CALL_Ints_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int8_t _x = (int8_t)x; + int16_t _y = (int16_t)y; + int32_t _z = (int32_t)z; + int64_t _t = (int64_t)t; + nint _u = (nint)u; + proxybasictypes__Ints(_x, _y, _z, _t, _u); } +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/customprefix.java.c.golden b/bind/testdata/customprefix.java.c.golden new file mode 100644 index 0000000..a8ba32b --- /dev/null +++ b/bind/testdata/customprefix.java.c.golden @@ -0,0 +1,23 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java -javapkg=com.example customprefix +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "customprefix.h" +#include "_cgo_export.h" + + + +JNIEXPORT void JNICALL +Java_com_example_Customprefix_init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT void JNICALL +Java_com_example_Customprefix_F(JNIEnv* env, jclass clazz) { + proxycustomprefix__F(); +} + diff --git a/bind/testdata/customprefix.java.golden b/bind/testdata/customprefix.java.golden index 0c3e033..7a770b3 100644 --- a/bind/testdata/customprefix.java.golden +++ b/bind/testdata/customprefix.java.golden @@ -7,14 +7,15 @@ package com.example; import go.Seq; public abstract class Customprefix { - private Customprefix() {} // uninstantiable - - public static void F() { - go.Seq _in = null; - go.Seq _out = null; - Seq.send(DESCRIPTOR, CALL_F, _in, _out); + static { + Seq.touch(); // for loading the native library + init(); } - private static final int CALL_F = 1; - private static final String DESCRIPTOR = "customprefix"; + private Customprefix() {} // uninstantiable + + private static native void init(); + + + public static native void F(); } diff --git a/bind/testdata/customprefix.java.h.golden b/bind/testdata/customprefix.java.h.golden new file mode 100644 index 0000000..302ba2d --- /dev/null +++ b/bind/testdata/customprefix.java.h.golden @@ -0,0 +1,11 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java -javapkg=com.example customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __Customprefix_H__ +#define __Customprefix_H__ + +#include + +#endif diff --git a/bind/testdata/customprefix.objc.go.h.golden b/bind/testdata/customprefix.objc.go.h.golden new file mode 100644 index 0000000..5fee907 --- /dev/null +++ b/bind/testdata/customprefix.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to customprefix Go package. +// gobind -lang=objc -prefix=EX customprefix +// +// File is generated by gobind. Do not edit. + +#ifndef __customprefix_H__ +#define __customprefix_H__ + +#include +#include +#endif diff --git a/bind/testdata/customprefix.objc.m.golden b/bind/testdata/customprefix.objc.m.golden index 3ca30b9..59f8583 100644 --- a/bind/testdata/customprefix.objc.m.golden +++ b/bind/testdata/customprefix.objc.m.golden @@ -6,6 +6,7 @@ #include "EXCustomprefix.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.customprefix"; @@ -13,15 +14,11 @@ static NSString* errDomain = @"go.customprefix"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "customprefix" - -#define _CALL_F_ 1 void EXCustomprefixF() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_F_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + proxycustomprefix__F(); } +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/interfaces.go.golden b/bind/testdata/interfaces.go.golden index de04b31..f55a960 100644 --- a/bind/testdata/interfaces.go.golden +++ b/bind/testdata/interfaces.go.golden @@ -1,186 +1,169 @@ -// Package go_interfaces is an autogenerated binder stub for package interfaces. +// Package gomobile_bind is an autogenerated binder stub for package interfaces. // gobind -lang=go interfaces // // File is generated by gobind. Do not edit. -package go_interfaces +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "interfaces.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "interfaces" ) -func proxy_Add3(out, in *_seq.Buffer) { - var param_r interfaces.I - param_r_ref := in.ReadRef() - if param_r_ref.Num < 0 { // go object - param_r = param_r_ref.Get().(interfaces.I) - } else if param_r_ref.Num != _seq.NullRefNum { // foreign object - param_r = (*proxyI)(param_r_ref) - } - res := interfaces.Add3(param_r) - out.WriteInt32(res) -} +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum -func proxy_CallErr(out, in *_seq.Buffer) { - var param_e interfaces.Error - param_e_ref := in.ReadRef() - if param_e_ref.Num < 0 { // go object - param_e = param_e_ref.Get().(interfaces.Error) - } else if param_e_ref.Num != _seq.NullRefNum { // foreign object - param_e = (*proxyError)(param_e_ref) - } - err := interfaces.CallErr(param_e) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) - } -} - -const ( - proxyError_Descriptor = "go.interfaces.Error" - proxyError_Err_Code = 0x10a -) - -func proxyError_Err(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_Error_Err +func proxyinterfaces_Error_Err(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.Error) - err := v.Err() - if err == nil { - out.WriteString("") + res_0 := v.Err() + var _res_0_str string + if res_0 == nil { + _res_0_str = "" } else { - out.WriteString(err.Error()) + _res_0_str = res_0.Error() } + _res_0 := encodeString(_res_0_str, true) + return _res_0 } -func init() { - _seq.Register(proxyError_Descriptor, proxyError_Err_Code, proxyError_Err) +type proxyinterfaces_Error _seq.Ref + +func (p *proxyinterfaces_Error) Err() error { + res := C.cproxyinterfaces_Error_Err(C.int32_t(p.Num)) + _res_str := decodeString(res, true) + _res := toError(_res_str) + return _res } -type proxyError _seq.Ref - -func (p *proxyError) Err() error { - in := new(_seq.Buffer) - out := _seq.Transact((*_seq.Ref)(p), "go.interfaces.Error", proxyError_Err_Code, in) - res_0 := out.ReadError() - return res_0 -} - -const ( - proxyI_Descriptor = "go.interfaces.I" - proxyI_Rand_Code = 0x10a -) - -func proxyI_Rand(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_I_Rand +func proxyinterfaces_I_Rand(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.I) - res := v.Rand() - out.WriteInt32(res) + res_0 := v.Rand() + _res_0 := C.int32_t(res_0) + return _res_0 } -func init() { - _seq.Register(proxyI_Descriptor, proxyI_Rand_Code, proxyI_Rand) +type proxyinterfaces_I _seq.Ref + +func (p *proxyinterfaces_I) Rand() int32 { + res := C.cproxyinterfaces_I_Rand(C.int32_t(p.Num)) + _res := int32(res) + return _res } -type proxyI _seq.Ref - -func (p *proxyI) Rand() int32 { - in := new(_seq.Buffer) - out := _seq.Transact((*_seq.Ref)(p), "go.interfaces.I", proxyI_Rand_Code, in) - res_0 := out.ReadInt32() - return res_0 -} - -const ( - proxyI1_Descriptor = "go.interfaces.I1" - proxyI1_J_Code = 0x10a -) - -func proxyI1_J(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_I1_J +func proxyinterfaces_I1_J(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.I1) v.J() } -func init() { - _seq.Register(proxyI1_Descriptor, proxyI1_J_Code, proxyI1_J) -} - -const ( - proxyI2_Descriptor = "go.interfaces.I2" - proxyI2_G_Code = 0x10a -) - -func proxyI2_G(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_I2_G +func proxyinterfaces_I2_G(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.I2) v.G() } -func init() { - _seq.Register(proxyI2_Descriptor, proxyI2_G_Code, proxyI2_G) -} - -const ( - proxyI3_Descriptor = "go.interfaces.I3" - proxyI3_F_Code = 0x10a -) - -func proxyI3_F(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_I3_F +func proxyinterfaces_I3_F(refnum C.int32_t) C.int32_t { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.I3) - res := v.F() - out.WriteGoRef(res) -} - -func init() { - _seq.Register(proxyI3_Descriptor, proxyI3_F_Code, proxyI3_F) -} - -type proxyI3 _seq.Ref - -func (p *proxyI3) F() interfaces.I1 { - in := new(_seq.Buffer) - out := _seq.Transact((*_seq.Ref)(p), "go.interfaces.I3", proxyI3_F_Code, in) - var res_0 interfaces.I1 - res_0_ref := out.ReadRef() - if res_0_ref.Num < 0 { // go object - res_0 = res_0_ref.Get().(interfaces.I1) + res_0 := v.F() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) } - return res_0 + return _res_0 } -func proxy_Seven(out, in *_seq.Buffer) { - res := interfaces.Seven() - out.WriteGoRef(res) +type proxyinterfaces_I3 _seq.Ref + +func (p *proxyinterfaces_I3) F() interfaces.I1 { + res := C.cproxyinterfaces_I3_F(C.int32_t(p.Num)) + var _res interfaces.I1 + _res_ref := _seq.FromRefNum(int32(res)) + if _res_ref != nil { + if _res_ref.Num < 0 { // go object + _res = _res_ref.Get().(interfaces.I1) + } + } + return _res } -const ( - proxyWithParam_Descriptor = "go.interfaces.WithParam" - proxyWithParam_HasParam_Code = 0x10a -) - -func proxyWithParam_HasParam(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyinterfaces_WithParam_HasParam +func proxyinterfaces_WithParam_HasParam(refnum C.int32_t, param_p0 C.char) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(interfaces.WithParam) - param_p0 := in.ReadBool() - v.HasParam(param_p0) + _param_p0 := param_p0 != 0 + v.HasParam(_param_p0) } -func init() { - _seq.Register(proxyWithParam_Descriptor, proxyWithParam_HasParam_Code, proxyWithParam_HasParam) +type proxyinterfaces_WithParam _seq.Ref + +func (p *proxyinterfaces_WithParam) HasParam(param_p0 bool) { + var _param_p0 C.char = 0 + if param_p0 { + _param_p0 = 1 + } + C.cproxyinterfaces_WithParam_HasParam(C.int32_t(p.Num), _param_p0) } -type proxyWithParam _seq.Ref - -func (p *proxyWithParam) HasParam(p0 bool) { - in := new(_seq.Buffer) - in.WriteBool(p0) - _seq.Transact((*_seq.Ref)(p), "go.interfaces.WithParam", proxyWithParam_HasParam_Code, in) +//export proxyinterfaces__Add3 +func proxyinterfaces__Add3(param_r C.int32_t) C.int32_t { + var _param_r interfaces.I + _param_r_ref := _seq.FromRefNum(int32(param_r)) + if _param_r_ref != nil { + if _param_r_ref.Num < 0 { // go object + _param_r = _param_r_ref.Get().(interfaces.I) + } else { // foreign object + _param_r = (*proxyinterfaces_I)(_param_r_ref) + } + } + res_0 := interfaces.Add3(_param_r) + _res_0 := C.int32_t(res_0) + return _res_0 } -func init() { - _seq.Register("interfaces", 1, proxy_Add3) - _seq.Register("interfaces", 2, proxy_CallErr) - _seq.Register("interfaces", 3, proxy_Seven) +//export proxyinterfaces__CallErr +func proxyinterfaces__CallErr(param_e C.int32_t) C.nstring { + var _param_e interfaces.Error + _param_e_ref := _seq.FromRefNum(int32(param_e)) + if _param_e_ref != nil { + if _param_e_ref.Num < 0 { // go object + _param_e = _param_e_ref.Get().(interfaces.Error) + } else { // foreign object + _param_e = (*proxyinterfaces_Error)(_param_e_ref) + } + } + res_0 := interfaces.CallErr(_param_e) + var _res_0_str string + if res_0 == nil { + _res_0_str = "" + } else { + _res_0_str = res_0.Error() + } + _res_0 := encodeString(_res_0_str, true) + return _res_0 +} + +//export proxyinterfaces__Seven +func proxyinterfaces__Seven() C.int32_t { + res_0 := interfaces.Seven() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 } diff --git a/bind/testdata/interfaces.java.c.golden b/bind/testdata/interfaces.java.c.golden new file mode 100644 index 0000000..ba36f77 --- /dev/null +++ b/bind/testdata/interfaces.java.c.golden @@ -0,0 +1,190 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java interfaces +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "interfaces.h" +#include "_cgo_export.h" + + +static jclass proxy_class_interfaces_Error; +static jmethodID proxy_class_interfaces_Error_cons; +static jmethodID mid_Error_Err; +static jclass proxy_class_interfaces_I; +static jmethodID proxy_class_interfaces_I_cons; +static jmethodID mid_I_Rand; +static jclass proxy_class_interfaces_I1; +static jmethodID proxy_class_interfaces_I1_cons; +static jmethodID mid_I1_H; +static jmethodID mid_I1_J; +static jclass proxy_class_interfaces_I2; +static jmethodID proxy_class_interfaces_I2_cons; +static jmethodID mid_I2_G; +static jmethodID mid_I2_f; +static jclass proxy_class_interfaces_I3; +static jmethodID proxy_class_interfaces_I3_cons; +static jmethodID mid_I3_F; +static jclass proxy_class_interfaces_WithParam; +static jmethodID proxy_class_interfaces_WithParam_cons; +static jmethodID mid_WithParam_HasParam; + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$Error$Proxy"); + proxy_class_interfaces_Error = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_Error_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$Error"); + mid_Error_Err = (*env)->GetMethodID(env, clazz, "Err", "()V"); + + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I$Proxy"); + proxy_class_interfaces_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I"); + mid_I_Rand = (*env)->GetMethodID(env, clazz, "Rand", "()I"); + + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I1$Proxy"); + proxy_class_interfaces_I1 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I1_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I1"); + mid_I1_J = (*env)->GetMethodID(env, clazz, "J", "()V"); + + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I2$Proxy"); + proxy_class_interfaces_I2 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I2_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I2"); + mid_I2_G = (*env)->GetMethodID(env, clazz, "G", "()V"); + + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I3$Proxy"); + proxy_class_interfaces_I3 = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_I3_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$I3"); + mid_I3_F = (*env)->GetMethodID(env, clazz, "F", "()Lgo/interfaces/Interfaces$I1;"); + + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$WithParam$Proxy"); + proxy_class_interfaces_WithParam = (*env)->NewGlobalRef(env, clazz); + proxy_class_interfaces_WithParam_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/interfaces/Interfaces$WithParam"); + mid_WithParam_HasParam = (*env)->GetMethodID(env, clazz, "HasParam", "(Z)V"); + +} + +JNIEXPORT jint JNICALL +Java_go_interfaces_Interfaces_Add3(JNIEnv* env, jclass clazz, jobject r) { + int32_t _r = go_seq_to_refnum(env, r); + int32_t r0 = proxyinterfaces__Add3(_r); + jint _r0 = (jint)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_CallErr(JNIEnv* env, jclass clazz, jobject e) { + int32_t _e = go_seq_to_refnum(env, e); + nstring r0 = proxyinterfaces__CallErr(_e); + jstring _r0 = go_seq_to_java_string(env, r0); + go_seq_maybe_throw_exception(env, _r0); +} + +JNIEXPORT jobject JNICALL +Java_go_interfaces_Interfaces_Seven(JNIEnv* env, jclass clazz) { + int32_t r0 = proxyinterfaces__Seven(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_interfaces_I, proxy_class_interfaces_I_cons); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_00024Error_00024Proxy_Err(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + nstring r0 = proxyinterfaces_Error_Err(o); + jstring _r0 = go_seq_to_java_string(env, r0); + go_seq_maybe_throw_exception(env, _r0); +} + +nstring cproxyinterfaces_Error_Err(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_Error, proxy_class_interfaces_Error_cons); + (*env)->CallVoidMethod(env, o, mid_Error_Err); + jstring exc = go_seq_get_exception_message(env); + nstring _exc = go_seq_from_java_string(env, exc, 1); + go_seq_pop_local_frame(env); + return _exc; +} + +JNIEXPORT jint JNICALL +Java_go_interfaces_Interfaces_00024I_00024Proxy_Rand(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + int32_t r0 = proxyinterfaces_I_Rand(o); + jint _r0 = (jint)r0; + return _r0; +} + +int32_t cproxyinterfaces_I_Rand(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I, proxy_class_interfaces_I_cons); + jint res = (*env)->CallIntMethod(env, o, mid_I_Rand); + int32_t _res = (int32_t)res; + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_00024I1_00024Proxy_J(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + proxyinterfaces_I1_J(o); +} + +void cproxyinterfaces_I1_J(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I1, proxy_class_interfaces_I1_cons); + (*env)->CallVoidMethod(env, o, mid_I1_J); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_00024I2_00024Proxy_G(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + proxyinterfaces_I2_G(o); +} + +void cproxyinterfaces_I2_G(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I2, proxy_class_interfaces_I2_cons); + (*env)->CallVoidMethod(env, o, mid_I2_G); + go_seq_pop_local_frame(env); +} + +JNIEXPORT jobject JNICALL +Java_go_interfaces_Interfaces_00024I3_00024Proxy_F(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + int32_t r0 = proxyinterfaces_I3_F(o); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_interfaces_I1, proxy_class_interfaces_I1_cons); + return _r0; +} + +int32_t cproxyinterfaces_I3_F(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_I3, proxy_class_interfaces_I3_cons); + jobject res = (*env)->CallObjectMethod(env, o, mid_I3_F); + int32_t _res = go_seq_to_refnum(env, res); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT void JNICALL +Java_go_interfaces_Interfaces_00024WithParam_00024Proxy_HasParam(JNIEnv* env, jobject this, jboolean p0) { + int32_t o = go_seq_to_refnum(env, this); + char _p0 = (char)p0; + proxyinterfaces_WithParam_HasParam(o, _p0); +} + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0) { + JNIEnv *env = go_seq_push_local_frame(12); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_WithParam, proxy_class_interfaces_WithParam_cons); + jboolean _p0 = p0 ? JNI_TRUE : JNI_FALSE; + (*env)->CallVoidMethod(env, o, mid_WithParam_HasParam, _p0); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/interfaces.java.golden b/bind/testdata/interfaces.java.golden index 82d2d51..982ebaf 100644 --- a/bind/testdata/interfaces.java.golden +++ b/bind/testdata/interfaces.java.golden @@ -7,324 +7,135 @@ package go.interfaces; import go.Seq; public abstract class Interfaces { + static { + Seq.touch(); // for loading the native library + init(); + } + private Interfaces() {} // uninstantiable - public static int Add3(I r) { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - int _result; - _in = new go.Seq(); - _in.writeRef(r != null ? r.ref() : null); - Seq.send(DESCRIPTOR, CALL_Add3, _in, _out); - _result = _out.readInt32(); - return _result; - } - - public static void CallErr(Error e) throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - _in = new go.Seq(); - _in.writeRef(e != null ? e.ref() : null); - Seq.send(DESCRIPTOR, CALL_CallErr, _in, _out); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - } + private static native void init(); public interface Error extends go.Seq.Object { public void Err() throws Exception; - public static abstract class Stub implements Error { - static final String DESCRIPTOR = "go.interfaces.Error"; - private final go.Seq.Ref ref; public Stub() { ref = go.Seq.createRef(this); } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_Err: { - try { - this.Err(); - out.writeString(null); - } catch (Exception e) { - out.writeString(e.getMessage()); - } - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } } static final class Proxy implements Error { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void Err() throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_Err, _in, _out); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - } - - static final int CALL_Err = 0x10a; + public native void Err() throws Exception; } } public interface I extends go.Seq.Object { public int Rand(); - public static abstract class Stub implements I { - static final String DESCRIPTOR = "go.interfaces.I"; - private final go.Seq.Ref ref; public Stub() { ref = go.Seq.createRef(this); } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_Rand: { - int result = this.Rand(); - out.writeInt32(result); - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } } static final class Proxy implements I { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public int Rand() { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - int _result; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_Rand, _in, _out); - _result = _out.readInt32(); - return _result; - } - - static final int CALL_Rand = 0x10a; + public native int Rand(); } } public interface I1 extends go.Seq.Object { public void J(); - static final class Proxy implements I1 { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void J() { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_J, _in, _out); - } - - static final int CALL_J = 0x10a; + public native void J(); } } public interface I2 extends go.Seq.Object { public void G(); - static final class Proxy implements I2 { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void G() { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_G, _in, _out); - } - - static final int CALL_G = 0x10a; + public native void G(); } } public interface I3 extends go.Seq.Object { public I1 F(); - public static abstract class Stub implements I3 { - static final String DESCRIPTOR = "go.interfaces.I3"; - private final go.Seq.Ref ref; public Stub() { ref = go.Seq.createRef(this); } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_F: { - I1 result = this.F(); - out.writeRef(result != null ? result.ref() : null); - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } } static final class Proxy implements I3 { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public I1 F() { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - I1 _result; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_F, _in, _out); - _result = new I1.Proxy(_out.readRef()); - return _result; - } - - static final int CALL_F = 0x10a; + public native I1 F(); } } - public static I Seven() { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - I _result; - Seq.send(DESCRIPTOR, CALL_Seven, _in, _out); - _result = new I.Proxy(_out.readRef()); - return _result; - } - public interface WithParam extends go.Seq.Object { public void HasParam(boolean p0); - public static abstract class Stub implements WithParam { - static final String DESCRIPTOR = "go.interfaces.WithParam"; - private final go.Seq.Ref ref; public Stub() { ref = go.Seq.createRef(this); } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_HasParam: { - boolean param_p0; - param_p0 = in.readBool(); - this.HasParam(param_p0); - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } } static final class Proxy implements WithParam { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void HasParam(boolean p0) { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - _in.writeBool(p0); - Seq.send(DESCRIPTOR, CALL_HasParam, _in, _out); - } - - static final int CALL_HasParam = 0x10a; + public native void HasParam(boolean p0); } } - private static final int CALL_Add3 = 1; - private static final int CALL_CallErr = 2; - private static final int CALL_Seven = 3; - private static final String DESCRIPTOR = "interfaces"; + + public static native int Add3(I r); + public static native void CallErr(Error e) throws Exception; + public static native I Seven(); } diff --git a/bind/testdata/interfaces.java.h.golden b/bind/testdata/interfaces.java.h.golden new file mode 100644 index 0000000..6e05bd7 --- /dev/null +++ b/bind/testdata/interfaces.java.h.golden @@ -0,0 +1,23 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java interfaces +// +// File is generated by gobind. Do not edit. + +#ifndef __Interfaces_H__ +#define __Interfaces_H__ + +#include + +nstring cproxyinterfaces_Error_Err(int32_t refnum); + +int32_t cproxyinterfaces_I_Rand(int32_t refnum); + +void cproxyinterfaces_I1_J(int32_t refnum); + +void cproxyinterfaces_I2_G(int32_t refnum); + +int32_t cproxyinterfaces_I3_F(int32_t refnum); + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0); + +#endif diff --git a/bind/testdata/interfaces.objc.go.h.golden b/bind/testdata/interfaces.objc.go.h.golden new file mode 100644 index 0000000..ddef052 --- /dev/null +++ b/bind/testdata/interfaces.objc.go.h.golden @@ -0,0 +1,19 @@ +// Objective-C API for talking to interfaces Go package. +// gobind -lang=objc interfaces +// +// File is generated by gobind. Do not edit. + +#ifndef __interfaces_H__ +#define __interfaces_H__ + +#include +#include +nstring cproxyinterfaces_Error_Err(int32_t refnum); + +int32_t cproxyinterfaces_I_Rand(int32_t refnum); + +int32_t cproxyinterfaces_I3_F(int32_t refnum); + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0); + +#endif diff --git a/bind/testdata/interfaces.objc.m.golden b/bind/testdata/interfaces.objc.m.golden index 7719a88..c7c1dc0 100644 --- a/bind/testdata/interfaces.objc.m.golden +++ b/bind/testdata/interfaces.objc.m.golden @@ -6,6 +6,7 @@ #include "GoInterfaces.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.interfaces"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.interfaces"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "interfaces" - @class GoInterfacesError; @class GoInterfacesI; @@ -55,9 +54,6 @@ static NSString* errDomain = @"go.interfaces"; - (void)hasParam:(BOOL)p0; @end -#define _GO_interfaces_Error_DESCRIPTOR_ "go.interfaces.Error" -#define _GO_interfaces_Error_Err_ (0x10a) - @implementation GoInterfacesError { } @@ -68,46 +64,19 @@ static NSString* errDomain = @"go.interfaces"; } - (BOOL)err:(NSError**)error { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_interfaces_Error_DESCRIPTOR_, _GO_interfaces_Error_Err_, &in_, &out_); - NSString* _error = go_seq_readUTF8(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxyinterfaces_Error_Err(refnum); + NSString *_error = go_seq_to_objc_string(r0); if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } @end -static void proxyGoInterfacesError(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_interfaces_Error_Err_: { - id o = (id)(obj); - NSError* error = NULL; - BOOL returnVal = [o err:&error]; - if (returnVal) { - go_seq_writeUTF8(out, NULL); - } else { - NSString* errorDesc = [error localizedDescription]; - if (errorDesc == NULL || errorDesc.length == 0) { - errorDesc = @"gobind: unknown error"; - } - go_seq_writeUTF8(out, errorDesc); - } - } break; - default: - NSLog(@"unknown code %x for _GO_interfaces_Error_DESCRIPTOR_", code); - } -} - -#define _GO_interfaces_I_DESCRIPTOR_ "go.interfaces.I" -#define _GO_interfaces_I_Rand_ (0x10a) @implementation GoInterfacesI { } @@ -119,32 +88,14 @@ static void proxyGoInterfacesError(id obj, int code, GoSeq* in, GoSeq* out) { } - (int32_t)rand { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_interfaces_I_DESCRIPTOR_, _GO_interfaces_I_Rand_, &in_, &out_); - int32_t ret0_ = go_seq_readInt32(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_I_Rand(refnum); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; } @end -static void proxyGoInterfacesI(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_interfaces_I_Rand_: { - id o = (id)(obj); - int32_t returnVal = [o rand]; - go_seq_writeInt32(out, returnVal); - } break; - default: - NSLog(@"unknown code %x for _GO_interfaces_I_DESCRIPTOR_", code); - } -} - -#define _GO_interfaces_I1_DESCRIPTOR_ "go.interfaces.I1" -#define _GO_interfaces_I1_J_ (0x10a) @implementation GoInterfacesI1 { } @@ -156,20 +107,13 @@ static void proxyGoInterfacesI(id obj, int code, GoSeq* in, GoSeq* out) { } - (void)j { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_interfaces_I1_DESCRIPTOR_, _GO_interfaces_I1_J_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_I1_J(refnum); } @end -#define _GO_interfaces_I2_DESCRIPTOR_ "go.interfaces.I2" -#define _GO_interfaces_I2_G_ (0x10a) - @implementation GoInterfacesI2 { } @@ -180,20 +124,13 @@ static void proxyGoInterfacesI(id obj, int code, GoSeq* in, GoSeq* out) { } - (void)g { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_interfaces_I2_DESCRIPTOR_, _GO_interfaces_I2_G_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxyinterfaces_I2_G(refnum); } @end -#define _GO_interfaces_I3_DESCRIPTOR_ "go.interfaces.I3" -#define _GO_interfaces_I3_F_ (0x10a) - @implementation GoInterfacesI3 { } @@ -204,41 +141,21 @@ static void proxyGoInterfacesI(id obj, int code, GoSeq* in, GoSeq* out) { } - (GoInterfacesI1*)f { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_interfaces_I3_DESCRIPTOR_, _GO_interfaces_I3_F_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - GoInterfacesI1* ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoInterfacesI1 alloc] initWithRef:ret0__ref]; + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t r0 = proxyinterfaces_I3_F(refnum); + GoInterfacesI1* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoInterfacesI1 alloc] initWithRef:_ret0__ref]; + } } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + return _ret0_; } @end -static void proxyGoInterfacesI3(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_interfaces_I3_F_: { - id o = (id)(obj); - GoInterfacesI1* returnVal = [o f]; - if ([(id)(returnVal) isKindOfClass:[GoInterfacesI1 class]]) { - idretVal_proxy = (id)(returnVal); - go_seq_writeRef(out, retVal_proxy._ref); - } else { - go_seq_writeRef(out, returnVal); - } - } break; - default: - NSLog(@"unknown code %x for _GO_interfaces_I3_DESCRIPTOR_", code); - } -} - -#define _GO_interfaces_WithParam_DESCRIPTOR_ "go.interfaces.WithParam" -#define _GO_interfaces_WithParam_HasParam_ (0x10a) @implementation GoInterfacesWithParam { } @@ -250,87 +167,110 @@ static void proxyGoInterfacesI3(id obj, int code, GoSeq* in, GoSeq* out) { } - (void)hasParam:(BOOL)p0 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeBool(&in_, p0); - go_seq_send(_GO_interfaces_WithParam_DESCRIPTOR_, _GO_interfaces_WithParam_HasParam_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + char _p0 = (char)p0; + proxyinterfaces_WithParam_HasParam(refnum, _p0); } @end -static void proxyGoInterfacesWithParam(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_interfaces_WithParam_HasParam_: { - id o = (id)(obj); - BOOL p0 = go_seq_readBool(in); - [o hasParam:p0]; - } break; - default: - NSLog(@"unknown code %x for _GO_interfaces_WithParam_DESCRIPTOR_", code); - } -} -#define _CALL_Add3_ 1 -#define _CALL_CallErr_ 2 -#define _CALL_Seven_ 3 int32_t GoInterfacesAdd3(id r) { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _r; if ([(id)(r) isKindOfClass:[GoInterfacesI class]]) { id r_proxy = (id)(r); - go_seq_writeRef(&in_, r_proxy._ref); + _r = go_seq_go_to_refnum(r_proxy._ref); } else { - go_seq_writeObjcRef(&in_, r); + _r = go_seq_to_refnum(r); } - go_seq_send(_DESCRIPTOR_, _CALL_Add3_, &in_, &out_); - int32_t ret0_ = go_seq_readInt32(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + int32_t r0 = proxyinterfaces__Add3(_r); + int32_t _ret0_ = (int32_t)r0; + return _ret0_; } BOOL GoInterfacesCallErr(id e, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _e; if ([(id)(e) isKindOfClass:[GoInterfacesError class]]) { id e_proxy = (id)(e); - go_seq_writeRef(&in_, e_proxy._ref); + _e = go_seq_go_to_refnum(e_proxy._ref); } else { - go_seq_writeObjcRef(&in_, e); + _e = go_seq_to_refnum(e); } - go_seq_send(_DESCRIPTOR_, _CALL_CallErr_, &in_, &out_); - NSString* _error = go_seq_readUTF8(&out_); + nstring r0 = proxyinterfaces__CallErr(_e); + NSString *_error = go_seq_to_objc_string(r0); if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } id GoInterfacesSeven() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_Seven_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - id ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoInterfacesI alloc] initWithRef:ret0__ref]; + int32_t r0 = proxyinterfaces__Seven(); + id _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoInterfacesI alloc] initWithRef:_ret0__ref]; + } } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + return _ret0_; +} + +nstring cproxyinterfaces_Error_Err(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + NSError* error = nil; + BOOL returnVal = [o err:&error]; + NSString *error_str = nil; + if (!returnVal) { + error_str = [error localizedDescription]; + if (error_str == nil || error_str.length == 0) { + error_str = @"gobind: unknown error"; + } + } + nstring _error_str = go_seq_from_objc_string(error_str); + return _error_str; +} + +int32_t cproxyinterfaces_I_Rand(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + int32_t returnVal = [o rand]; + int32_t _returnVal = (int32_t)returnVal; + return _returnVal; +} + +void cproxyinterfaces_I1_J(int32_t refnum) { + GoInterfacesI1* o = go_seq_objc_from_refnum(refnum); + [o j]; +} + +void cproxyinterfaces_I2_G(int32_t refnum) { + GoInterfacesI2* o = go_seq_objc_from_refnum(refnum); + [o g]; +} + +int32_t cproxyinterfaces_I3_F(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + GoInterfacesI1* returnVal = [o f]; + int32_t _returnVal; + if ([(id)(returnVal) isKindOfClass:[GoInterfacesI1 class]]) { + id returnVal_proxy = (id)(returnVal); + _returnVal = go_seq_go_to_refnum(returnVal_proxy._ref); + } else { + _returnVal = go_seq_to_refnum(returnVal); + } + return _returnVal; +} + +void cproxyinterfaces_WithParam_HasParam(int32_t refnum, char p0) { + id o = go_seq_objc_from_refnum(refnum); + BOOL _p0 = p0 ? YES : NO; + [o hasParam:_p0]; } __attribute__((constructor)) static void init() { - go_seq_register_proxy("go.interfaces.Error", proxyGoInterfacesError); - go_seq_register_proxy("go.interfaces.I", proxyGoInterfacesI); - go_seq_register_proxy("go.interfaces.I3", proxyGoInterfacesI3); - go_seq_register_proxy("go.interfaces.WithParam", proxyGoInterfacesWithParam); + init_seq(); } diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden index 69069b5..74e7d65 100644 --- a/bind/testdata/issue10788.go.golden +++ b/bind/testdata/issue10788.go.golden @@ -1,80 +1,76 @@ -// Package go_issue10788 is an autogenerated binder stub for package issue10788. +// Package gomobile_bind is an autogenerated binder stub for package issue10788. // gobind -lang=go issue10788 // // File is generated by gobind. Do not edit. -package go_issue10788 +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "issue10788.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "issue10788" ) -const ( - proxyTestInterface_Descriptor = "go.issue10788.TestInterface" - proxyTestInterface_DoSomeWork_Code = 0x10a - proxyTestInterface_MultipleUnnamedParams_Code = 0x20a -) - -func proxyTestInterface_DoSomeWork(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(issue10788.TestInterface) - // Must be a Go object - param_s_ref := in.ReadRef() - param_s := param_s_ref.Get().(*issue10788.TestStruct) - v.DoSomeWork(param_s) -} - -func proxyTestInterface_MultipleUnnamedParams(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(issue10788.TestInterface) - param_p0 := in.ReadInt() - param_p1 := in.ReadString() - param_p2 := in.ReadInt64() - v.MultipleUnnamedParams(param_p0, param_p1, param_p2) -} - -func init() { - _seq.Register(proxyTestInterface_Descriptor, proxyTestInterface_DoSomeWork_Code, proxyTestInterface_DoSomeWork) - _seq.Register(proxyTestInterface_Descriptor, proxyTestInterface_MultipleUnnamedParams_Code, proxyTestInterface_MultipleUnnamedParams) -} - -type proxyTestInterface _seq.Ref - -func (p *proxyTestInterface) DoSomeWork(s *issue10788.TestStruct) { - in := new(_seq.Buffer) - in.WriteGoRef(s) - _seq.Transact((*_seq.Ref)(p), "go.issue10788.TestInterface", proxyTestInterface_DoSomeWork_Code, in) -} - -func (p *proxyTestInterface) MultipleUnnamedParams(p0 int, p1 string, p2 int64) { - in := new(_seq.Buffer) - in.WriteInt(p0) - in.WriteString(p1) - in.WriteInt64(p2) - _seq.Transact((*_seq.Ref)(p), "go.issue10788.TestInterface", proxyTestInterface_MultipleUnnamedParams_Code, in) -} - -const ( - proxyTestStruct_Descriptor = "go.issue10788.TestStruct" - proxyTestStruct_Value_Get_Code = 0x00f - proxyTestStruct_Value_Set_Code = 0x01f -) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum type proxyTestStruct _seq.Ref -func proxyTestStruct_Value_Set(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := in.ReadString() - ref.Get().(*issue10788.TestStruct).Value = v +//export proxyissue10788_TestStruct_Value_Set +func proxyissue10788_TestStruct_Value_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v := decodeString(v, false) + ref.Get().(*issue10788.TestStruct).Value = _v } -func proxyTestStruct_Value_Get(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyissue10788_TestStruct_Value_Get +func proxyissue10788_TestStruct_Value_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*issue10788.TestStruct).Value - out.WriteString(v) + _v := encodeString(v, true) + return _v } -func init() { - _seq.Register(proxyTestStruct_Descriptor, proxyTestStruct_Value_Set_Code, proxyTestStruct_Value_Set) - _seq.Register(proxyTestStruct_Descriptor, proxyTestStruct_Value_Get_Code, proxyTestStruct_Value_Get) +//export proxyissue10788_TestInterface_DoSomeWork +func proxyissue10788_TestInterface_DoSomeWork(refnum C.int32_t, param_s C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue10788.TestInterface) + // Must be a Go object + _param_s_ref := _seq.FromRefNum(int32(param_s)) + _param_s := _param_s_ref.Get().(*issue10788.TestStruct) + v.DoSomeWork(_param_s) +} + +//export proxyissue10788_TestInterface_MultipleUnnamedParams +func proxyissue10788_TestInterface_MultipleUnnamedParams(refnum C.int32_t, param_p0 C.nint, param_p1 C.nstring, param_p2 C.int64_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(issue10788.TestInterface) + _param_p0 := int(param_p0) + _param_p1 := decodeString(param_p1, false) + _param_p2 := int64(param_p2) + v.MultipleUnnamedParams(_param_p0, _param_p1, _param_p2) +} + +type proxyissue10788_TestInterface _seq.Ref + +func (p *proxyissue10788_TestInterface) DoSomeWork(param_s *issue10788.TestStruct) { + var _param_s C.int32_t = _seq.NullRefNum + if param_s != nil { + _param_s = C.int32_t(_seq.ToRefNum(param_s)) + } + C.cproxyissue10788_TestInterface_DoSomeWork(C.int32_t(p.Num), _param_s) +} + +func (p *proxyissue10788_TestInterface) MultipleUnnamedParams(param_p0 int, param_p1 string, param_p2 int64) { + _param_p0 := C.nint(param_p0) + _param_p1 := encodeString(param_p1, false) + _param_p2 := C.int64_t(param_p2) + C.cproxyissue10788_TestInterface_MultipleUnnamedParams(C.int32_t(p.Num), _param_p0, _param_p1, _param_p2) } diff --git a/bind/testdata/issue10788.java.c.golden b/bind/testdata/issue10788.java.c.golden new file mode 100644 index 0000000..13da27c --- /dev/null +++ b/bind/testdata/issue10788.java.c.golden @@ -0,0 +1,89 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java issue10788 +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "issue10788.h" +#include "_cgo_export.h" + + +static jclass proxy_class_issue10788_TestInterface; +static jmethodID proxy_class_issue10788_TestInterface_cons; +static jmethodID mid_TestInterface_DoSomeWork; +static jmethodID mid_TestInterface_MultipleUnnamedParams; +static jclass proxy_class_issue10788_TestStruct; +static jmethodID proxy_class_issue10788_TestStruct_cons; + +JNIEXPORT void JNICALL +Java_go_issue10788_Issue10788_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/issue10788/Issue10788$TestStruct"); + proxy_class_issue10788_TestStruct = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue10788_TestStruct_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/issue10788/Issue10788$TestInterface$Proxy"); + proxy_class_issue10788_TestInterface = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue10788_TestInterface_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/issue10788/Issue10788$TestInterface"); + mid_TestInterface_DoSomeWork = (*env)->GetMethodID(env, clazz, "DoSomeWork", "(Lgo/issue10788/Issue10788$TestStruct;)V"); + mid_TestInterface_MultipleUnnamedParams = (*env)->GetMethodID(env, clazz, "MultipleUnnamedParams", "(JLjava/lang/String;J)V"); + +} + +JNIEXPORT void JNICALL +Java_go_issue10788_Issue10788_00024TestStruct_setValue(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum(env, this); + nstring _v = go_seq_from_java_string(env, v, 0); + proxyissue10788_TestStruct_Value_Set(o, _v); + if (_v.chars != NULL) { + (*env)->ReleaseStringChars(env, v, _v.chars); + } +} + +JNIEXPORT jstring JNICALL +Java_go_issue10788_Issue10788_00024TestStruct_getValue(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + nstring r0 = proxyissue10788_TestStruct_Value_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_issue10788_Issue10788_00024TestInterface_00024Proxy_DoSomeWork(JNIEnv* env, jobject this, jobject s) { + int32_t o = go_seq_to_refnum(env, this); + int32_t _s = go_seq_to_refnum(env, s); + proxyissue10788_TestInterface_DoSomeWork(o, _s); +} + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s) { + JNIEnv *env = go_seq_push_local_frame(12); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue10788_TestInterface, proxy_class_issue10788_TestInterface_cons); + jobject _s = go_seq_from_refnum(env, s, proxy_class_issue10788_TestStruct, proxy_class_issue10788_TestStruct_cons); + (*env)->CallVoidMethod(env, o, mid_TestInterface_DoSomeWork, _s); + go_seq_pop_local_frame(env); +} + +JNIEXPORT void JNICALL +Java_go_issue10788_Issue10788_00024TestInterface_00024Proxy_MultipleUnnamedParams(JNIEnv* env, jobject this, jlong p0, jstring p1, jlong p2) { + int32_t o = go_seq_to_refnum(env, this); + nint _p0 = (nint)p0; + nstring _p1 = go_seq_from_java_string(env, p1, 0); + int64_t _p2 = (int64_t)p2; + proxyissue10788_TestInterface_MultipleUnnamedParams(o, _p0, _p1, _p2); + if (_p1.chars != NULL) { + (*env)->ReleaseStringChars(env, p1, _p1.chars); + } +} + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2) { + JNIEnv *env = go_seq_push_local_frame(16); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue10788_TestInterface, proxy_class_issue10788_TestInterface_cons); + jlong _p0 = (jlong)p0; + jstring _p1 = go_seq_to_java_string(env, p1); + jlong _p2 = (jlong)p2; + (*env)->CallVoidMethod(env, o, mid_TestInterface_MultipleUnnamedParams, _p0, _p1, _p2); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/issue10788.java.golden b/bind/testdata/issue10788.java.golden index 24be140..0111b4c 100644 --- a/bind/testdata/issue10788.java.golden +++ b/bind/testdata/issue10788.java.golden @@ -7,114 +7,24 @@ package go.issue10788; import go.Seq; public abstract class Issue10788 { - private Issue10788() {} // uninstantiable - - public interface TestInterface extends go.Seq.Object { - public void DoSomeWork(TestStruct s); - - public void MultipleUnnamedParams(long p0, String p1, long p2); - - public static abstract class Stub implements TestInterface { - static final String DESCRIPTOR = "go.issue10788.TestInterface"; - - private final go.Seq.Ref ref; - public Stub() { - ref = go.Seq.createRef(this); - } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_DoSomeWork: { - TestStruct param_s; - param_s = new TestStruct(in.readRef()); - this.DoSomeWork(param_s); - return; - } - case Proxy.CALL_MultipleUnnamedParams: { - long param_p0; - param_p0 = in.readInt(); - String param_p1; - param_p1 = in.readString(); - long param_p2; - param_p2 = in.readInt64(); - this.MultipleUnnamedParams(param_p0, param_p1, param_p2); - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } - } - - static final class Proxy implements TestInterface { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - - private go.Seq.Ref ref; - - Proxy(go.Seq.Ref ref) { this.ref = ref; } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void DoSomeWork(TestStruct s) { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - _in.writeRef(s != null ? s.ref() : null); - Seq.send(DESCRIPTOR, CALL_DoSomeWork, _in, _out); - } - - public void MultipleUnnamedParams(long p0, String p1, long p2) { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - _in.writeInt(p0); - _in.writeString(p1); - _in.writeInt64(p2); - Seq.send(DESCRIPTOR, CALL_MultipleUnnamedParams, _in, _out); - } - - static final int CALL_DoSomeWork = 0x10a; - static final int CALL_MultipleUnnamedParams = 0x20a; - } + static { + Seq.touch(); // for loading the native library + init(); } + private Issue10788() {} // uninstantiable + + private static native void init(); + public static final class TestStruct implements go.Seq.Object { - private static final String DESCRIPTOR = "go.issue10788.TestStruct"; - private static final int FIELD_Value_GET = 0x00f; - private static final int FIELD_Value_SET = 0x01f; - - private go.Seq.Ref ref; + private final go.Seq.Ref ref; private TestStruct(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); - } - - public String getValue() { - Seq in = new Seq(); - Seq out = new Seq(); - in.writeRef(ref); - Seq.send(DESCRIPTOR, FIELD_Value_GET, in, out); - return out.readString(); - } - - public void setValue(String v) { - Seq in = new Seq(); - in.writeRef(ref); - in.writeString(v); - Seq.send(DESCRIPTOR, FIELD_Value_SET, in, null); - } + public final native String getValue(); + public final native void setValue(String v); @Override public boolean equals(Object o) { if (o == null || !(o instanceof TestStruct)) { @@ -143,8 +53,32 @@ public abstract class Issue10788 { b.append("Value:").append(getValue()).append(","); return b.append("}").toString(); } - } - private static final String DESCRIPTOR = "issue10788"; + public interface TestInterface extends go.Seq.Object { + public void DoSomeWork(TestStruct s); + public void MultipleUnnamedParams(long p0, String p1, long p2); + public static abstract class Stub implements TestInterface { + private final go.Seq.Ref ref; + public Stub() { + ref = go.Seq.createRef(this); + } + + public final go.Seq.Ref ref() { return ref; } + + } + + static final class Proxy implements TestInterface { + private go.Seq.Ref ref; + + Proxy(go.Seq.Ref ref) { this.ref = ref; } + + public final go.Seq.Ref ref() { return ref; } + + public native void DoSomeWork(TestStruct s); + public native void MultipleUnnamedParams(long p0, String p1, long p2); + } + } + + } diff --git a/bind/testdata/issue10788.java.h.golden b/bind/testdata/issue10788.java.h.golden new file mode 100644 index 0000000..895f15f --- /dev/null +++ b/bind/testdata/issue10788.java.h.golden @@ -0,0 +1,15 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java issue10788 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue10788_H__ +#define __Issue10788_H__ + +#include + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s); + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2); + +#endif diff --git a/bind/testdata/issue10788.objc.go.h.golden b/bind/testdata/issue10788.objc.go.h.golden new file mode 100644 index 0000000..5c480a8 --- /dev/null +++ b/bind/testdata/issue10788.objc.go.h.golden @@ -0,0 +1,15 @@ +// Objective-C API for talking to issue10788 Go package. +// gobind -lang=objc issue10788 +// +// File is generated by gobind. Do not edit. + +#ifndef __issue10788_H__ +#define __issue10788_H__ + +#include +#include +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s); + +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2); + +#endif diff --git a/bind/testdata/issue10788.objc.m.golden b/bind/testdata/issue10788.objc.m.golden index 53ce9b7..e70a323 100644 --- a/bind/testdata/issue10788.objc.m.golden +++ b/bind/testdata/issue10788.objc.m.golden @@ -6,6 +6,7 @@ #include "GoIssue10788.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.issue10788"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.issue10788"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "issue10788" - @class GoIssue10788TestInterface; @interface GoIssue10788TestInterface : NSObject { @@ -26,9 +25,6 @@ static NSString* errDomain = @"go.issue10788"; - (void)multipleUnnamedParams:(int)p0 p1:(NSString*)p1 p2:(int64_t)p2; @end -#define _GO_issue10788_TestStruct_DESCRIPTOR_ "go.issue10788.TestStruct" -#define _GO_issue10788_TestStruct_FIELD_Value_GET_ (0x00f) -#define _GO_issue10788_TestStruct_FIELD_Value_SET_ (0x01f) @implementation GoIssue10788TestStruct { } @@ -40,32 +36,20 @@ static NSString* errDomain = @"go.issue10788"; } - (NSString*)value { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_GET_, &in_, &out_); - NSString* ret_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxyissue10788_TestStruct_Value_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; } - (void)setValue:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, v); - go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxyissue10788_TestStruct_Value_Set(refnum, _v); } @end -#define _GO_issue10788_TestInterface_DESCRIPTOR_ "go.issue10788.TestInterface" -#define _GO_issue10788_TestInterface_DoSomeWork_ (0x10a) -#define _GO_issue10788_TestInterface_MultipleUnnamedParams_ (0x20a) - @implementation GoIssue10788TestInterface { } @@ -76,58 +60,50 @@ static NSString* errDomain = @"go.issue10788"; } - (void)doSomeWork:(GoIssue10788TestStruct*)s { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); + int32_t refnum = go_seq_go_to_refnum(self._ref); + int32_t _s; if ([(id)(s) isKindOfClass:[GoIssue10788TestStruct class]]) { id s_proxy = (id)(s); - go_seq_writeRef(&in_, s_proxy._ref); + _s = go_seq_go_to_refnum(s_proxy._ref); } else { - go_seq_writeObjcRef(&in_, s); + _s = go_seq_to_refnum(s); } - go_seq_send(_GO_issue10788_TestInterface_DESCRIPTOR_, _GO_issue10788_TestInterface_DoSomeWork_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + proxyissue10788_TestInterface_DoSomeWork(refnum, _s); } - (void)multipleUnnamedParams:(int)p0 p1:(NSString*)p1 p2:(int64_t)p2 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeInt(&in_, p0); - go_seq_writeUTF8(&in_, p1); - go_seq_writeInt64(&in_, p2); - go_seq_send(_GO_issue10788_TestInterface_DESCRIPTOR_, _GO_issue10788_TestInterface_MultipleUnnamedParams_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + nint _p0 = (nint)p0; + nstring _p1 = go_seq_from_objc_string(p1); + int64_t _p2 = (int64_t)p2; + proxyissue10788_TestInterface_MultipleUnnamedParams(refnum, _p0, _p1, _p2); } @end -static void proxyGoIssue10788TestInterface(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_issue10788_TestInterface_DoSomeWork_: { - id o = (id)(obj); - GoSeqRef* s_ref = go_seq_readRef(in); - GoIssue10788TestStruct* s = s_ref.obj; - if (s == NULL) { - s = [[GoIssue10788TestStruct alloc] initWithRef:s_ref]; + + +void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s) { + id o = go_seq_objc_from_refnum(refnum); + GoIssue10788TestStruct* _s = nil; + GoSeqRef* _s_ref = go_seq_from_refnum(s); + if (_s_ref != NULL) { + _s = _s_ref.obj; + if (_s == nil) { + _s = [[GoIssue10788TestStruct alloc] initWithRef:_s_ref]; } - [o doSomeWork:s]; - } break; - case _GO_issue10788_TestInterface_MultipleUnnamedParams_: { - id o = (id)(obj); - int p0 = go_seq_readInt(in); - NSString* p1 = go_seq_readUTF8(in); - int64_t p2 = go_seq_readInt64(in); - [o multipleUnnamedParams:p0 p1:p1 p2:p2]; - } break; - default: - NSLog(@"unknown code %x for _GO_issue10788_TestInterface_DESCRIPTOR_", code); } + [o doSomeWork:_s]; } +void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2) { + id o = go_seq_objc_from_refnum(refnum); + int _p0 = (int)p0; + NSString *_p1 = go_seq_to_objc_string(p1); + int64_t _p2 = (int64_t)p2; + [o multipleUnnamedParams:_p0 p1:_p1 p2:_p2]; +} __attribute__((constructor)) static void init() { - go_seq_register_proxy("go.issue10788.TestInterface", proxyGoIssue10788TestInterface); + init_seq(); } diff --git a/bind/testdata/issue12328.go.golden b/bind/testdata/issue12328.go.golden index e86a738..fbcf4fa 100644 --- a/bind/testdata/issue12328.go.golden +++ b/bind/testdata/issue12328.go.golden @@ -1,39 +1,46 @@ -// Package go_issue12328 is an autogenerated binder stub for package issue12328. +// Package gomobile_bind is an autogenerated binder stub for package issue12328. // gobind -lang=go issue12328 // // File is generated by gobind. Do not edit. -package go_issue12328 +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "issue12328.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "issue12328" ) -const ( - proxyT_Descriptor = "go.issue12328.T" - proxyT_Err_Get_Code = 0x00f - proxyT_Err_Set_Code = 0x01f -) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum type proxyT _seq.Ref -func proxyT_Err_Set(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := in.ReadError() - ref.Get().(*issue12328.T).Err = v +//export proxyissue12328_T_Err_Set +func proxyissue12328_T_Err_Set(refnum C.int32_t, v C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) + _v_str := decodeString(v, false) + _v := toError(_v_str) + ref.Get().(*issue12328.T).Err = _v } -func proxyT_Err_Get(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyissue12328_T_Err_Get +func proxyissue12328_T_Err_Get(refnum C.int32_t) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*issue12328.T).Err + var _v_str string if v == nil { - out.WriteString("") + _v_str = "" } else { - out.WriteString(v.Error()) + _v_str = v.Error() } -} - -func init() { - _seq.Register(proxyT_Descriptor, proxyT_Err_Set_Code, proxyT_Err_Set) - _seq.Register(proxyT_Descriptor, proxyT_Err_Get_Code, proxyT_Err_Get) + _v := encodeString(_v_str, true) + return _v } diff --git a/bind/testdata/issue12328.java.c.golden b/bind/testdata/issue12328.java.c.golden new file mode 100644 index 0000000..7fb843f --- /dev/null +++ b/bind/testdata/issue12328.java.c.golden @@ -0,0 +1,41 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java issue12328 +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "issue12328.h" +#include "_cgo_export.h" + + +static jclass proxy_class_issue12328_T; +static jmethodID proxy_class_issue12328_T_cons; + +JNIEXPORT void JNICALL +Java_go_issue12328_Issue12328_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/issue12328/Issue12328$T"); + proxy_class_issue12328_T = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue12328_T_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); +} + +JNIEXPORT void JNICALL +Java_go_issue12328_Issue12328_00024T_setErr(JNIEnv *env, jobject this, jstring v) { + int32_t o = go_seq_to_refnum(env, this); + nstring _v = go_seq_from_java_string(env, v, 0); + proxyissue12328_T_Err_Set(o, _v); + if (_v.chars != NULL) { + (*env)->ReleaseStringChars(env, v, _v.chars); + } +} + +JNIEXPORT jstring JNICALL +Java_go_issue12328_Issue12328_00024T_getErr(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + nstring r0 = proxyissue12328_T_Err_Get(o); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + diff --git a/bind/testdata/issue12328.java.golden b/bind/testdata/issue12328.java.golden index f27bf71..a2492aa 100644 --- a/bind/testdata/issue12328.java.golden +++ b/bind/testdata/issue12328.java.golden @@ -7,37 +7,24 @@ package go.issue12328; import go.Seq; public abstract class Issue12328 { + static { + Seq.touch(); // for loading the native library + init(); + } + private Issue12328() {} // uninstantiable + private static native void init(); + public static final class T implements go.Seq.Object { - private static final String DESCRIPTOR = "go.issue12328.T"; - private static final int FIELD_Err_GET = 0x00f; - private static final int FIELD_Err_SET = 0x01f; - - private go.Seq.Ref ref; + private final go.Seq.Ref ref; private T(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); - } - - public String getErr() { - Seq in = new Seq(); - Seq out = new Seq(); - in.writeRef(ref); - Seq.send(DESCRIPTOR, FIELD_Err_GET, in, out); - return out.readString(); - } - - public void setErr(String v) { - Seq in = new Seq(); - in.writeRef(ref); - in.writeString(v); - Seq.send(DESCRIPTOR, FIELD_Err_SET, in, null); - } + public final native String getErr(); + public final native void setErr(String v); @Override public boolean equals(Object o) { if (o == null || !(o instanceof T)) { @@ -66,8 +53,7 @@ public abstract class Issue12328 { b.append("Err:").append(getErr()).append(","); return b.append("}").toString(); } - } - private static final String DESCRIPTOR = "issue12328"; + } diff --git a/bind/testdata/issue12328.java.h.golden b/bind/testdata/issue12328.java.h.golden new file mode 100644 index 0000000..0d54708 --- /dev/null +++ b/bind/testdata/issue12328.java.h.golden @@ -0,0 +1,11 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java issue12328 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue12328_H__ +#define __Issue12328_H__ + +#include + +#endif diff --git a/bind/testdata/issue12328.objc.go.h.golden b/bind/testdata/issue12328.objc.go.h.golden new file mode 100644 index 0000000..cdf8789 --- /dev/null +++ b/bind/testdata/issue12328.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to issue12328 Go package. +// gobind -lang=objc issue12328 +// +// File is generated by gobind. Do not edit. + +#ifndef __issue12328_H__ +#define __issue12328_H__ + +#include +#include +#endif diff --git a/bind/testdata/issue12328.objc.m.golden b/bind/testdata/issue12328.objc.m.golden index 75323b7..05095e8 100644 --- a/bind/testdata/issue12328.objc.m.golden +++ b/bind/testdata/issue12328.objc.m.golden @@ -6,6 +6,7 @@ #include "GoIssue12328.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.issue12328"; @@ -13,11 +14,6 @@ static NSString* errDomain = @"go.issue12328"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "issue12328" - -#define _GO_issue12328_T_DESCRIPTOR_ "go.issue12328.T" -#define _GO_issue12328_T_FIELD_Err_GET_ (0x00f) -#define _GO_issue12328_T_FIELD_Err_SET_ (0x01f) @implementation GoIssue12328T { } @@ -29,26 +25,21 @@ static NSString* errDomain = @"go.issue12328"; } - (NSString*)err { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_issue12328_T_DESCRIPTOR_, _GO_issue12328_T_FIELD_Err_GET_, &in_, &out_); - NSString* ret_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring r0 = proxyissue12328_T_Err_Get(refnum); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; } - (void)setErr:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, v); - go_seq_send(_GO_issue12328_T_DESCRIPTOR_, _GO_issue12328_T_FIELD_Err_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _v = go_seq_from_objc_string(v); + proxyissue12328_T_Err_Set(refnum, _v); } @end +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/issue12403.go.golden b/bind/testdata/issue12403.go.golden index 0da8901..585ee18 100644 --- a/bind/testdata/issue12403.go.golden +++ b/bind/testdata/issue12403.go.golden @@ -1,59 +1,65 @@ -// Package go_issue12403 is an autogenerated binder stub for package issue12403. +// Package gomobile_bind is an autogenerated binder stub for package issue12403. // gobind -lang=go issue12403 // // File is generated by gobind. Do not edit. -package go_issue12403 +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "issue12403.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "issue12403" ) -const ( - proxyParsable_Descriptor = "go.issue12403.Parsable" - proxyParsable_FromJSON_Code = 0x10a - proxyParsable_ToJSON_Code = 0x20a -) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum -func proxyParsable_FromJSON(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyissue12403_Parsable_FromJSON +func proxyissue12403_Parsable_FromJSON(refnum C.int32_t, param_jstr C.nstring) C.nstring { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(issue12403.Parsable) - param_jstr := in.ReadString() - res := v.FromJSON(param_jstr) - out.WriteString(res) + _param_jstr := decodeString(param_jstr, false) + res_0 := v.FromJSON(_param_jstr) + _res_0 := encodeString(res_0, true) + return _res_0 } -func proxyParsable_ToJSON(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxyissue12403_Parsable_ToJSON +func proxyissue12403_Parsable_ToJSON(refnum C.int32_t) (C.nstring, C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(issue12403.Parsable) - res, err := v.ToJSON() - out.WriteString(res) - if err == nil { - out.WriteString("") + res_0, res_1 := v.ToJSON() + _res_0 := encodeString(res_0, true) + var _res_1_str string + if res_1 == nil { + _res_1_str = "" } else { - out.WriteString(err.Error()) + _res_1_str = res_1.Error() } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 } -func init() { - _seq.Register(proxyParsable_Descriptor, proxyParsable_FromJSON_Code, proxyParsable_FromJSON) - _seq.Register(proxyParsable_Descriptor, proxyParsable_ToJSON_Code, proxyParsable_ToJSON) +type proxyissue12403_Parsable _seq.Ref + +func (p *proxyissue12403_Parsable) FromJSON(param_jstr string) string { + _param_jstr := encodeString(param_jstr, false) + res := C.cproxyissue12403_Parsable_FromJSON(C.int32_t(p.Num), _param_jstr) + _res := decodeString(res, true) + return _res } -type proxyParsable _seq.Ref - -func (p *proxyParsable) FromJSON(jstr string) string { - in := new(_seq.Buffer) - in.WriteString(jstr) - out := _seq.Transact((*_seq.Ref)(p), "go.issue12403.Parsable", proxyParsable_FromJSON_Code, in) - res_0 := out.ReadString() - return res_0 -} - -func (p *proxyParsable) ToJSON() (string, error) { - in := new(_seq.Buffer) - out := _seq.Transact((*_seq.Ref)(p), "go.issue12403.Parsable", proxyParsable_ToJSON_Code, in) - res_0 := out.ReadString() - res_1 := out.ReadError() +func (p *proxyissue12403_Parsable) ToJSON() (string, error) { + res := C.cproxyissue12403_Parsable_ToJSON(C.int32_t(p.Num)) + res_0 := decodeString(res.r0, true) + res_1_str := decodeString(res.r1, true) + res_1 := toError(res_1_str) return res_0, res_1 } diff --git a/bind/testdata/issue12403.java.c.golden b/bind/testdata/issue12403.java.c.golden new file mode 100644 index 0000000..511180f --- /dev/null +++ b/bind/testdata/issue12403.java.c.golden @@ -0,0 +1,75 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java issue12403 +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "issue12403.h" +#include "_cgo_export.h" + + +static jclass proxy_class_issue12403_Parsable; +static jmethodID proxy_class_issue12403_Parsable_cons; +static jmethodID mid_Parsable_FromJSON; +static jmethodID mid_Parsable_ToJSON; + +JNIEXPORT void JNICALL +Java_go_issue12403_Issue12403_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/issue12403/Issue12403$Parsable$Proxy"); + proxy_class_issue12403_Parsable = (*env)->NewGlobalRef(env, clazz); + proxy_class_issue12403_Parsable_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/issue12403/Issue12403$Parsable"); + mid_Parsable_FromJSON = (*env)->GetMethodID(env, clazz, "FromJSON", "(Ljava/lang/String;)Ljava/lang/String;"); + mid_Parsable_ToJSON = (*env)->GetMethodID(env, clazz, "ToJSON", "()Ljava/lang/String;"); + +} + +JNIEXPORT jstring JNICALL +Java_go_issue12403_Issue12403_00024Parsable_00024Proxy_FromJSON(JNIEnv* env, jobject this, jstring jstr) { + int32_t o = go_seq_to_refnum(env, this); + nstring _jstr = go_seq_from_java_string(env, jstr, 0); + nstring r0 = proxyissue12403_Parsable_FromJSON(o, _jstr); + if (_jstr.chars != NULL) { + (*env)->ReleaseStringChars(env, jstr, _jstr.chars); + } + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr) { + JNIEnv *env = go_seq_push_local_frame(12); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue12403_Parsable, proxy_class_issue12403_Parsable_cons); + jstring _jstr = go_seq_to_java_string(env, jstr); + jstring res = (*env)->CallObjectMethod(env, o, mid_Parsable_FromJSON, _jstr); + nstring _res = go_seq_from_java_string(env, res, 1); + go_seq_pop_local_frame(env); + return _res; +} + +JNIEXPORT jstring JNICALL +Java_go_issue12403_Issue12403_00024Parsable_00024Proxy_ToJSON(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + struct proxyissue12403_Parsable_ToJSON_return res = proxyissue12403_Parsable_ToJSON(o); + jstring _r0 = go_seq_to_java_string(env, res.r0); + jstring _r1 = go_seq_to_java_string(env, res.r1); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_issue12403_Parsable, proxy_class_issue12403_Parsable_cons); + jstring res = (*env)->CallObjectMethod(env, o, mid_Parsable_ToJSON); + nstring _res = go_seq_from_java_string(env, res, 1); + jstring exc = go_seq_get_exception_message(env); + nstring _exc = go_seq_from_java_string(env, exc, 1); + cproxyissue12403_Parsable_ToJSON_return sres = { + _res, _exc + }; + go_seq_pop_local_frame(env); + return sres; +} + diff --git a/bind/testdata/issue12403.java.golden b/bind/testdata/issue12403.java.golden index a6df7ef..8359c4c 100644 --- a/bind/testdata/issue12403.java.golden +++ b/bind/testdata/issue12403.java.golden @@ -7,96 +7,39 @@ package go.issue12403; import go.Seq; public abstract class Issue12403 { + static { + Seq.touch(); // for loading the native library + init(); + } + private Issue12403() {} // uninstantiable + private static native void init(); + public interface Parsable extends go.Seq.Object { public String FromJSON(String jstr); - public String ToJSON() throws Exception; - public static abstract class Stub implements Parsable { - static final String DESCRIPTOR = "go.issue12403.Parsable"; - private final go.Seq.Ref ref; public Stub() { ref = go.Seq.createRef(this); } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_FromJSON: { - String param_jstr; - param_jstr = in.readString(); - String result = this.FromJSON(param_jstr); - out.writeString(result); - return; - } - case Proxy.CALL_ToJSON: { - try { - String result = this.ToJSON(); - out.writeString(result); - out.writeString(null); - } catch (Exception e) { - String result = null; - out.writeString(result); - out.writeString(e.getMessage()); - } - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } } static final class Proxy implements Parsable { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - private go.Seq.Ref ref; Proxy(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public String FromJSON(String jstr) { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - String _result; - _in = new go.Seq(); - _in.writeRef(ref); - _in.writeString(jstr); - Seq.send(DESCRIPTOR, CALL_FromJSON, _in, _out); - _result = _out.readString(); - return _result; - } - - public String ToJSON() throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - String _result; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_ToJSON, _in, _out); - _result = _out.readString(); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - return _result; - } - - static final int CALL_FromJSON = 0x10a; - static final int CALL_ToJSON = 0x20a; + public native String FromJSON(String jstr); + public native String ToJSON() throws Exception; } } - private static final String DESCRIPTOR = "issue12403"; + } diff --git a/bind/testdata/issue12403.java.h.golden b/bind/testdata/issue12403.java.h.golden new file mode 100644 index 0000000..a2f7fbb --- /dev/null +++ b/bind/testdata/issue12403.java.h.golden @@ -0,0 +1,19 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java issue12403 +// +// File is generated by gobind. Do not edit. + +#ifndef __Issue12403_H__ +#define __Issue12403_H__ + +#include + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr); + +typedef struct cproxyissue12403_Parsable_ToJSON_return { + nstring r0; + nstring r1; +} cproxyissue12403_Parsable_ToJSON_return; +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum); + +#endif diff --git a/bind/testdata/issue12403.objc.go.h.golden b/bind/testdata/issue12403.objc.go.h.golden new file mode 100644 index 0000000..d418219 --- /dev/null +++ b/bind/testdata/issue12403.objc.go.h.golden @@ -0,0 +1,19 @@ +// Objective-C API for talking to issue12403 Go package. +// gobind -lang=objc issue12403 +// +// File is generated by gobind. Do not edit. + +#ifndef __issue12403_H__ +#define __issue12403_H__ + +#include +#include +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr); + +typedef struct cproxyissue12403_Parsable_ToJSON_return { + nstring r0; + nstring r1; +} cproxyissue12403_Parsable_ToJSON_return; +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum); + +#endif diff --git a/bind/testdata/issue12403.objc.m.golden b/bind/testdata/issue12403.objc.m.golden index cbc8011..40660fa 100644 --- a/bind/testdata/issue12403.objc.m.golden +++ b/bind/testdata/issue12403.objc.m.golden @@ -6,6 +6,7 @@ #include "GoIssue12403.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.issue12403"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.issue12403"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "issue12403" - @class GoIssue12403Parsable; @interface GoIssue12403Parsable : NSObject { @@ -26,10 +25,6 @@ static NSString* errDomain = @"go.issue12403"; - (BOOL)toJSON:(NSString**)ret0_ error:(NSError**)error; @end -#define _GO_issue12403_Parsable_DESCRIPTOR_ "go.issue12403.Parsable" -#define _GO_issue12403_Parsable_FromJSON_ (0x10a) -#define _GO_issue12403_Parsable_ToJSON_ (0x20a) - @implementation GoIssue12403Parsable { } @@ -40,69 +35,59 @@ static NSString* errDomain = @"go.issue12403"; } - (NSString*)fromJSON:(NSString*)jstr { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeUTF8(&in_, jstr); - go_seq_send(_GO_issue12403_Parsable_DESCRIPTOR_, _GO_issue12403_Parsable_FromJSON_, &in_, &out_); - NSString* ret0_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + nstring _jstr = go_seq_from_objc_string(jstr); + nstring r0 = proxyissue12403_Parsable_FromJSON(refnum, _jstr); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; } - (BOOL)toJSON:(NSString**)ret0_ error:(NSError**)error { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_issue12403_Parsable_DESCRIPTOR_, _GO_issue12403_Parsable_ToJSON_, &in_, &out_); - NSString* ret0__val = go_seq_readUTF8(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__val; - } - NSString* _error = go_seq_readUTF8(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + struct proxyissue12403_Parsable_ToJSON_return res = proxyissue12403_Parsable_ToJSON(refnum); + NSString *_ret0_ = go_seq_to_objc_string(res.r0); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } @end -static void proxyGoIssue12403Parsable(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_issue12403_Parsable_FromJSON_: { - id o = (id)(obj); - NSString* jstr = go_seq_readUTF8(in); - NSString* returnVal = [o fromJSON:jstr]; - go_seq_writeUTF8(out, returnVal); - } break; - case _GO_issue12403_Parsable_ToJSON_: { - id o = (id)(obj); - NSString* ret0_; - NSError* error = NULL; - BOOL returnVal = [o toJSON:&ret0_ error:&error]; - go_seq_writeUTF8(out, ret0_); - if (returnVal) { - go_seq_writeUTF8(out, NULL); - } else { - NSString* errorDesc = [error localizedDescription]; - if (errorDesc == NULL || errorDesc.length == 0) { - errorDesc = @"gobind: unknown error"; - } - go_seq_writeUTF8(out, errorDesc); - } - } break; - default: - NSLog(@"unknown code %x for _GO_issue12403_Parsable_DESCRIPTOR_", code); - } + + +nstring cproxyissue12403_Parsable_FromJSON(int32_t refnum, nstring jstr) { + id o = go_seq_objc_from_refnum(refnum); + NSString *_jstr = go_seq_to_objc_string(jstr); + NSString* returnVal = [o fromJSON:_jstr]; + nstring _returnVal = go_seq_from_objc_string(returnVal); + return _returnVal; } +struct cproxyissue12403_Parsable_ToJSON_return cproxyissue12403_Parsable_ToJSON(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + NSString* ret0_; + NSError* error = nil; + BOOL returnVal = [o toJSON:&ret0_ error:&error]; + nstring _ret0_ = go_seq_from_objc_string(ret0_); + NSString *error_str = nil; + if (!returnVal) { + error_str = [error localizedDescription]; + if (error_str == nil || error_str.length == 0) { + error_str = @"gobind: unknown error"; + } + } + nstring _error_str = go_seq_from_objc_string(error_str); + cproxyissue12403_Parsable_ToJSON_return _sres = { + _ret0_, _error_str + }; + return _sres; +} __attribute__((constructor)) static void init() { - go_seq_register_proxy("go.issue12403.Parsable", proxyGoIssue12403Parsable); + init_seq(); } diff --git a/bind/testdata/structs.go.golden b/bind/testdata/structs.go.golden index 3c17b1a..69cc85b 100644 --- a/bind/testdata/structs.go.golden +++ b/bind/testdata/structs.go.golden @@ -1,139 +1,137 @@ -// Package go_structs is an autogenerated binder stub for package structs. +// Package gomobile_bind is an autogenerated binder stub for package structs. // gobind -lang=go structs // // File is generated by gobind. Do not edit. -package go_structs +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "structs.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "structs" ) -const ( - proxyI_Descriptor = "go.structs.I" - proxyI_M_Code = 0x10a -) - -func proxyI_M(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := ref.Get().(structs.I) - v.M() -} - -func init() { - _seq.Register(proxyI_Descriptor, proxyI_M_Code, proxyI_M) -} - -type proxyI _seq.Ref - -func (p *proxyI) M() { - in := new(_seq.Buffer) - _seq.Transact((*_seq.Ref)(p), "go.structs.I", proxyI_M_Code, in) -} - -func proxy_Identity(out, in *_seq.Buffer) { - // Must be a Go object - param_s_ref := in.ReadRef() - param_s := param_s_ref.Get().(*structs.S) - res := structs.Identity(param_s) - out.WriteGoRef(res) -} - -func proxy_IdentityWithError(out, in *_seq.Buffer) { - // Must be a Go object - param_s_ref := in.ReadRef() - param_s := param_s_ref.Get().(*structs.S) - res, err := structs.IdentityWithError(param_s) - out.WriteGoRef(res) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) - } -} - -const ( - proxyS_Descriptor = "go.structs.S" - proxyS_X_Get_Code = 0x00f - proxyS_X_Set_Code = 0x01f - proxyS_Y_Get_Code = 0x10f - proxyS_Y_Set_Code = 0x11f - proxyS_Identity_Code = 0x00c - proxyS_Sum_Code = 0x10c -) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum type proxyS _seq.Ref -func proxyS_X_Set(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := in.ReadFloat64() - ref.Get().(*structs.S).X = v +//export proxystructs_S_X_Set +func proxystructs_S_X_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*structs.S).X = _v } -func proxyS_X_Get(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxystructs_S_X_Get +func proxystructs_S_X_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*structs.S).X - out.WriteFloat64(v) + _v := C.double(v) + return _v } -func proxyS_Y_Set(out, in *_seq.Buffer) { - ref := in.ReadRef() - v := in.ReadFloat64() - ref.Get().(*structs.S).Y = v +//export proxystructs_S_Y_Set +func proxystructs_S_Y_Set(refnum C.int32_t, v C.double) { + ref := _seq.FromRefNum(int32(refnum)) + _v := float64(v) + ref.Get().(*structs.S).Y = _v } -func proxyS_Y_Get(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxystructs_S_Y_Get +func proxystructs_S_Y_Get(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*structs.S).Y - out.WriteFloat64(v) + _v := C.double(v) + return _v } -func proxyS_Identity(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxystructs_S_Identity +func proxystructs_S_Identity(refnum C.int32_t) (C.int32_t, C.nstring) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*structs.S) - res, err := v.Identity() - out.WriteGoRef(res) - if err == nil { - out.WriteString("") - } else { - out.WriteString(err.Error()) + res_0, res_1 := v.Identity() + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) } + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 } -func proxyS_Sum(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxystructs_S_Sum +func proxystructs_S_Sum(refnum C.int32_t) C.double { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*structs.S) - res := v.Sum() - out.WriteFloat64(res) + res_0 := v.Sum() + _res_0 := C.double(res_0) + return _res_0 } -func init() { - _seq.Register(proxyS_Descriptor, proxyS_X_Set_Code, proxyS_X_Set) - _seq.Register(proxyS_Descriptor, proxyS_X_Get_Code, proxyS_X_Get) - _seq.Register(proxyS_Descriptor, proxyS_Y_Set_Code, proxyS_Y_Set) - _seq.Register(proxyS_Descriptor, proxyS_Y_Get_Code, proxyS_Y_Get) - _seq.Register(proxyS_Descriptor, proxyS_Identity_Code, proxyS_Identity) - _seq.Register(proxyS_Descriptor, proxyS_Sum_Code, proxyS_Sum) -} - -const ( - proxyS2_Descriptor = "go.structs.S2" - proxyS2_M_Code = 0x00c -) - type proxyS2 _seq.Ref -func proxyS2_M(out, in *_seq.Buffer) { - ref := in.ReadRef() +//export proxystructs_S2_M +func proxystructs_S2_M(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) v := ref.Get().(*structs.S2) v.M() } -func init() { - _seq.Register(proxyS2_Descriptor, proxyS2_M_Code, proxyS2_M) +//export proxystructs_I_M +func proxystructs_I_M(refnum C.int32_t) { + ref := _seq.FromRefNum(int32(refnum)) + v := ref.Get().(structs.I) + v.M() } -func init() { - _seq.Register("structs", 1, proxy_Identity) - _seq.Register("structs", 2, proxy_IdentityWithError) +type proxystructs_I _seq.Ref + +func (p *proxystructs_I) M() { + C.cproxystructs_I_M(C.int32_t(p.Num)) +} + +//export proxystructs__Identity +func proxystructs__Identity(param_s C.int32_t) C.int32_t { + // Must be a Go object + _param_s_ref := _seq.FromRefNum(int32(param_s)) + _param_s := _param_s_ref.Get().(*structs.S) + res_0 := structs.Identity(_param_s) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + return _res_0 +} + +//export proxystructs__IdentityWithError +func proxystructs__IdentityWithError(param_s C.int32_t) (C.int32_t, C.nstring) { + // Must be a Go object + _param_s_ref := _seq.FromRefNum(int32(param_s)) + _param_s := _param_s_ref.Get().(*structs.S) + res_0, res_1 := structs.IdentityWithError(_param_s) + var _res_0 C.int32_t = _seq.NullRefNum + if res_0 != nil { + _res_0 = C.int32_t(_seq.ToRefNum(res_0)) + } + var _res_1_str string + if res_1 == nil { + _res_1_str = "" + } else { + _res_1_str = res_1.Error() + } + _res_1 := encodeString(_res_1_str, true) + return _res_0, _res_1 } diff --git a/bind/testdata/structs.java.c.golden b/bind/testdata/structs.java.c.golden new file mode 100644 index 0000000..a54d17f --- /dev/null +++ b/bind/testdata/structs.java.c.golden @@ -0,0 +1,122 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java structs +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "structs.h" +#include "_cgo_export.h" + + +static jclass proxy_class_structs_I; +static jmethodID proxy_class_structs_I_cons; +static jmethodID mid_I_M; +static jclass proxy_class_structs_S; +static jmethodID proxy_class_structs_S_cons; +static jclass proxy_class_structs_S2; +static jmethodID proxy_class_structs_S2_cons; + +JNIEXPORT void JNICALL +Java_go_structs_Structs_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/structs/Structs$S"); + proxy_class_structs_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_S_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/structs/Structs$S2"); + proxy_class_structs_S2 = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_S2_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/structs/Structs$I$Proxy"); + proxy_class_structs_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_structs_I_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/structs/Structs$I"); + mid_I_M = (*env)->GetMethodID(env, clazz, "M", "()V"); + +} + +JNIEXPORT jobject JNICALL +Java_go_structs_Structs_Identity(JNIEnv* env, jclass clazz, jobject s) { + int32_t _s = go_seq_to_refnum(env, s); + int32_t r0 = proxystructs__Identity(_s); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_structs_S, proxy_class_structs_S_cons); + return _r0; +} + +JNIEXPORT jobject JNICALL +Java_go_structs_Structs_IdentityWithError(JNIEnv* env, jclass clazz, jobject s) { + int32_t _s = go_seq_to_refnum(env, s); + struct proxystructs__IdentityWithError_return res = proxystructs__IdentityWithError(_s); + jobject _r0 = go_seq_from_refnum(env, res.r0, proxy_class_structs_S, proxy_class_structs_S_cons); + jstring _r1 = go_seq_to_java_string(env, res.r1); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT jobject JNICALL +Java_go_structs_Structs_00024S_Identity(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + struct proxystructs_S_Identity_return res = proxystructs_S_Identity(o); + jobject _r0 = go_seq_from_refnum(env, res.r0, proxy_class_structs_S, proxy_class_structs_S_cons); + jstring _r1 = go_seq_to_java_string(env, res.r1); + go_seq_maybe_throw_exception(env, _r1); + return _r0; +} + +JNIEXPORT jdouble JNICALL +Java_go_structs_Structs_00024S_Sum(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + double r0 = proxystructs_S_Sum(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_structs_Structs_00024S_setX(JNIEnv *env, jobject this, jdouble v) { + int32_t o = go_seq_to_refnum(env, this); + double _v = (double)v; + proxystructs_S_X_Set(o, _v); +} + +JNIEXPORT jdouble JNICALL +Java_go_structs_Structs_00024S_getX(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + double r0 = proxystructs_S_X_Get(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_structs_Structs_00024S_setY(JNIEnv *env, jobject this, jdouble v) { + int32_t o = go_seq_to_refnum(env, this); + double _v = (double)v; + proxystructs_S_Y_Set(o, _v); +} + +JNIEXPORT jdouble JNICALL +Java_go_structs_Structs_00024S_getY(JNIEnv *env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + double r0 = proxystructs_S_Y_Get(o); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_structs_Structs_00024S2_M(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + proxystructs_S2_M(o); +} + +JNIEXPORT void JNICALL +Java_go_structs_Structs_00024I_00024Proxy_M(JNIEnv* env, jobject this) { + int32_t o = go_seq_to_refnum(env, this); + proxystructs_I_M(o); +} + +void cproxystructs_I_M(int32_t refnum) { + JNIEnv *env = go_seq_push_local_frame(10); + jobject o = go_seq_from_refnum(env, refnum, proxy_class_structs_I, proxy_class_structs_I_cons); + (*env)->CallVoidMethod(env, o, mid_I_M); + go_seq_pop_local_frame(env); +} + diff --git a/bind/testdata/structs.java.golden b/bind/testdata/structs.java.golden index 46353cd..377437e 100644 --- a/bind/testdata/structs.java.golden +++ b/bind/testdata/structs.java.golden @@ -7,163 +7,30 @@ package go.structs; import go.Seq; public abstract class Structs { + static { + Seq.touch(); // for loading the native library + init(); + } + private Structs() {} // uninstantiable - public interface I extends go.Seq.Object { - public void M(); - - public static abstract class Stub implements I { - static final String DESCRIPTOR = "go.structs.I"; - - private final go.Seq.Ref ref; - public Stub() { - ref = go.Seq.createRef(this); - } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - case Proxy.CALL_M: { - this.M(); - return; - } - default: - throw new RuntimeException("unknown code: "+ code); - } - } - } - - static final class Proxy implements I { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - - private go.Seq.Ref ref; - - Proxy(go.Seq.Ref ref) { this.ref = ref; } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - public void M() { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_M, _in, _out); - } - - static final int CALL_M = 0x10a; - } - } - - public static S Identity(S s) { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - S _result; - _in = new go.Seq(); - _in.writeRef(s != null ? s.ref() : null); - Seq.send(DESCRIPTOR, CALL_Identity, _in, _out); - _result = new S(_out.readRef()); - return _result; - } - - public static S IdentityWithError(S s) throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - S _result; - _in = new go.Seq(); - _in.writeRef(s != null ? s.ref() : null); - Seq.send(DESCRIPTOR, CALL_IdentityWithError, _in, _out); - _result = new S(_out.readRef()); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - return _result; - } + private static native void init(); public static final class S implements go.Seq.Object { - private static final String DESCRIPTOR = "go.structs.S"; - private static final int FIELD_X_GET = 0x00f; - private static final int FIELD_X_SET = 0x01f; - private static final int FIELD_Y_GET = 0x10f; - private static final int FIELD_Y_SET = 0x11f; - private static final int CALL_Identity = 0x00c; - private static final int CALL_Sum = 0x10c; - - private go.Seq.Ref ref; + private final go.Seq.Ref ref; private S(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } + public final go.Seq.Ref ref() { return ref; } - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); - } + public final native double getX(); + public final native void setX(double v); - public double getX() { - Seq in = new Seq(); - Seq out = new Seq(); - in.writeRef(ref); - Seq.send(DESCRIPTOR, FIELD_X_GET, in, out); - return out.readFloat64(); - } - - public void setX(double v) { - Seq in = new Seq(); - in.writeRef(ref); - in.writeFloat64(v); - Seq.send(DESCRIPTOR, FIELD_X_SET, in, null); - } - - public double getY() { - Seq in = new Seq(); - Seq out = new Seq(); - in.writeRef(ref); - Seq.send(DESCRIPTOR, FIELD_Y_GET, in, out); - return out.readFloat64(); - } - - public void setY(double v) { - Seq in = new Seq(); - in.writeRef(ref); - in.writeFloat64(v); - Seq.send(DESCRIPTOR, FIELD_Y_SET, in, null); - } - - public S Identity() throws Exception { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - S _result; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_Identity, _in, _out); - _result = new S(_out.readRef()); - String _err = _out.readString(); - if (_err != null && !_err.isEmpty()) { - throw new Exception(_err); - } - return _result; - } - - public double Sum() { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - double _result; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_Sum, _in, _out); - _result = _out.readFloat64(); - return _result; - } + public final native double getY(); + public final native void setY(double v); + public native S Identity() throws Exception; + public native double Sum(); @Override public boolean equals(Object o) { if (o == null || !(o instanceof S)) { return false; @@ -193,31 +60,16 @@ public abstract class Structs { b.append("Y:").append(getY()).append(","); return b.append("}").toString(); } - } public static final class S2 implements go.Seq.Object, I { - private static final String DESCRIPTOR = "go.structs.S2"; - private static final int CALL_M = 0x00c; - - private go.Seq.Ref ref; + private final go.Seq.Ref ref; private S2(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); - } - - public void M() { - go.Seq _in = null; - go.Seq _out = null; - _in = new go.Seq(); - _in.writeRef(ref); - Seq.send(DESCRIPTOR, CALL_M, _in, _out); - } + public final go.Seq.Ref ref() { return ref; } + public native void M(); @Override public boolean equals(Object o) { if (o == null || !(o instanceof S2)) { return false; @@ -235,10 +87,32 @@ public abstract class Structs { b.append("S2").append("{"); return b.append("}").toString(); } - } - private static final int CALL_Identity = 1; - private static final int CALL_IdentityWithError = 2; - private static final String DESCRIPTOR = "structs"; + public interface I extends go.Seq.Object { + public void M(); + public static abstract class Stub implements I { + private final go.Seq.Ref ref; + public Stub() { + ref = go.Seq.createRef(this); + } + + public final go.Seq.Ref ref() { return ref; } + + } + + static final class Proxy implements I { + private go.Seq.Ref ref; + + Proxy(go.Seq.Ref ref) { this.ref = ref; } + + public final go.Seq.Ref ref() { return ref; } + + public native void M(); + } + } + + + public static native S Identity(S s); + public static native S IdentityWithError(S s) throws Exception; } diff --git a/bind/testdata/structs.java.h.golden b/bind/testdata/structs.java.h.golden new file mode 100644 index 0000000..25ea098 --- /dev/null +++ b/bind/testdata/structs.java.h.golden @@ -0,0 +1,13 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java structs +// +// File is generated by gobind. Do not edit. + +#ifndef __Structs_H__ +#define __Structs_H__ + +#include + +void cproxystructs_I_M(int32_t refnum); + +#endif diff --git a/bind/testdata/structs.objc.go.h.golden b/bind/testdata/structs.objc.go.h.golden new file mode 100644 index 0000000..737f8fc --- /dev/null +++ b/bind/testdata/structs.objc.go.h.golden @@ -0,0 +1,13 @@ +// Objective-C API for talking to structs Go package. +// gobind -lang=objc structs +// +// File is generated by gobind. Do not edit. + +#ifndef __structs_H__ +#define __structs_H__ + +#include +#include +void cproxystructs_I_M(int32_t refnum); + +#endif diff --git a/bind/testdata/structs.objc.m.golden b/bind/testdata/structs.objc.m.golden index e904b14..48f8426 100644 --- a/bind/testdata/structs.objc.m.golden +++ b/bind/testdata/structs.objc.m.golden @@ -6,6 +6,7 @@ #include "GoStructs.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.structs"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.structs"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "structs" - @class GoStructsI; @interface GoStructsI : NSObject { @@ -25,13 +24,6 @@ static NSString* errDomain = @"go.structs"; - (void)m; @end -#define _GO_structs_S_DESCRIPTOR_ "go.structs.S" -#define _GO_structs_S_FIELD_X_GET_ (0x00f) -#define _GO_structs_S_FIELD_X_SET_ (0x01f) -#define _GO_structs_S_FIELD_Y_GET_ (0x10f) -#define _GO_structs_S_FIELD_Y_SET_ (0x11f) -#define _GO_structs_S_Identity_ (0x00c) -#define _GO_structs_S_Sum_ (0x10c) @implementation GoStructsS { } @@ -43,85 +35,61 @@ static NSString* errDomain = @"go.structs"; } - (double)x { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_FIELD_X_GET_, &in_, &out_); - double ret_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_X_Get(refnum); + double _r0 = (double)r0; + return _r0; } - (void)setX:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeFloat64(&in_, v); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_FIELD_X_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxystructs_S_X_Set(refnum, _v); } - (double)y { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_FIELD_Y_GET_, &in_, &out_); - double ret_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_Y_Get(refnum); + double _r0 = (double)r0; + return _r0; } - (void)setY:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_writeFloat64(&in_, v); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_FIELD_Y_SET_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + double _v = (double)v; + proxystructs_S_Y_Set(refnum, _v); } - (BOOL)identity:(GoStructsS**)ret0_ error:(NSError**)error { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_Identity_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__ref.obj; - if (*ret0_ == NULL) { - *ret0_ = [[GoStructsS alloc] initWithRef:ret0__ref]; + int32_t refnum = go_seq_go_to_refnum(self._ref); + struct proxystructs_S_Identity_return res = proxystructs_S_Identity(refnum); + GoStructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(res.r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoStructsS alloc] initWithRef:_ret0__ref]; } } - NSString* _error = go_seq_readUTF8(&out_); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } - (double)sum { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_S_DESCRIPTOR_, _GO_structs_S_Sum_, &in_, &out_); - double ret0_ = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + int32_t refnum = go_seq_go_to_refnum(self._ref); + double r0 = proxystructs_S_Sum(refnum); + double _ret0_ = (double)r0; + return _ret0_; } @end -#define _GO_structs_S2_DESCRIPTOR_ "go.structs.S2" -#define _GO_structs_S2_M_ (0x00c) @implementation GoStructsS2 { } @@ -133,19 +101,12 @@ static NSString* errDomain = @"go.structs"; } - (void)m { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_S2_DESCRIPTOR_, _GO_structs_S2_M_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxystructs_S2_M(refnum); } @end -#define _GO_structs_I_DESCRIPTOR_ "go.structs.I" -#define _GO_structs_I_M_ (0x10a) - @implementation GoStructsI { } @@ -156,78 +117,66 @@ static NSString* errDomain = @"go.structs"; } - (void)m { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeRef(&in_, self._ref); - go_seq_send(_GO_structs_I_DESCRIPTOR_, _GO_structs_I_M_, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t refnum = go_seq_go_to_refnum(self._ref); + proxystructs_I_M(refnum); } @end -static void proxyGoStructsI(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - case _GO_structs_I_M_: { - id o = (id)(obj); - [o m]; - } break; - default: - NSLog(@"unknown code %x for _GO_structs_I_DESCRIPTOR_", code); - } -} -#define _CALL_Identity_ 1 -#define _CALL_IdentityWithError_ 2 GoStructsS* GoStructsIdentity(GoStructsS* s) { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _s; if ([(id)(s) isKindOfClass:[GoStructsS class]]) { id s_proxy = (id)(s); - go_seq_writeRef(&in_, s_proxy._ref); + _s = go_seq_go_to_refnum(s_proxy._ref); } else { - go_seq_writeObjcRef(&in_, s); + _s = go_seq_to_refnum(s); } - go_seq_send(_DESCRIPTOR_, _CALL_Identity_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - GoStructsS* ret0_ = ret0__ref.obj; - if (ret0_ == NULL) { - ret0_ = [[GoStructsS alloc] initWithRef:ret0__ref]; + int32_t r0 = proxystructs__Identity(_s); + GoStructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoStructsS alloc] initWithRef:_ret0__ref]; + } } - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + return _ret0_; } BOOL GoStructsIdentityWithError(GoStructsS* s, GoStructsS** ret0_, NSError** error) { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _s; if ([(id)(s) isKindOfClass:[GoStructsS class]]) { id s_proxy = (id)(s); - go_seq_writeRef(&in_, s_proxy._ref); + _s = go_seq_go_to_refnum(s_proxy._ref); } else { - go_seq_writeObjcRef(&in_, s); + _s = go_seq_to_refnum(s); } - go_seq_send(_DESCRIPTOR_, _CALL_IdentityWithError_, &in_, &out_); - GoSeqRef* ret0__ref = go_seq_readRef(&out_); - if (ret0_ != NULL) { - *ret0_ = ret0__ref.obj; - if (*ret0_ == NULL) { - *ret0_ = [[GoStructsS alloc] initWithRef:ret0__ref]; + struct proxystructs__IdentityWithError_return res = proxystructs__IdentityWithError(_s); + GoStructsS* _ret0_ = nil; + GoSeqRef* _ret0__ref = go_seq_from_refnum(res.r0); + if (_ret0__ref != NULL) { + _ret0_ = _ret0__ref.obj; + if (_ret0_ == nil) { + _ret0_ = [[GoStructsS alloc] initWithRef:_ret0__ref]; } } - NSString* _error = go_seq_readUTF8(&out_); + NSString *_error = go_seq_to_objc_string(res.r1); + *ret0_ = _ret0_; if ([_error length] != 0 && error != nil) { NSMutableDictionary* details = [NSMutableDictionary dictionary]; [details setValue:_error forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:errDomain code:1 userInfo:details]; } - go_seq_free(&in_); - go_seq_free(&out_); return ([_error length] == 0); } +void cproxystructs_I_M(int32_t refnum) { + id o = go_seq_objc_from_refnum(refnum); + [o m]; +} + __attribute__((constructor)) static void init() { - go_seq_register_proxy("go.structs.I", proxyGoStructsI); + init_seq(); } diff --git a/bind/testdata/try.go.golden b/bind/testdata/try.go.golden index a7a9493..e1df038 100644 --- a/bind/testdata/try.go.golden +++ b/bind/testdata/try.go.golden @@ -1,19 +1,29 @@ -// Package go_try is an autogenerated binder stub for package try. +// Package gomobile_bind is an autogenerated binder stub for package try. // gobind -lang=go try // // File is generated by gobind. Do not edit. -package go_try +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "try.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "try" ) -func proxy_This(out, in *_seq.Buffer) { - res := try.This() - out.WriteString(res) -} +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum -func init() { - _seq.Register("try", 1, proxy_This) +//export proxytry__This +func proxytry__This() C.nstring { + res_0 := try.This() + _res_0 := encodeString(res_0, true) + return _res_0 } diff --git a/bind/testdata/try.java.c.golden b/bind/testdata/try.java.c.golden new file mode 100644 index 0000000..8107f1d --- /dev/null +++ b/bind/testdata/try.java.c.golden @@ -0,0 +1,25 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java try +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "try.h" +#include "_cgo_export.h" + + + +JNIEXPORT void JNICALL +Java_go_try__Try_init(JNIEnv *env, jclass _unused) { + jclass clazz; +} + +JNIEXPORT jstring JNICALL +Java_go_try__Try_This(JNIEnv* env, jclass clazz) { + nstring r0 = proxytry__This(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + diff --git a/bind/testdata/try.java.golden b/bind/testdata/try.java.golden index 4f9c31d..0aa6946 100644 --- a/bind/testdata/try.java.golden +++ b/bind/testdata/try.java.golden @@ -7,18 +7,15 @@ package go.try_; import go.Seq; public abstract class Try { - private Try() {} // uninstantiable - - public static String This() { - go.Seq _in = null; - go.Seq _out = null; - _out = new go.Seq(); - String _result; - Seq.send(DESCRIPTOR, CALL_This, _in, _out); - _result = _out.readString(); - return _result; + static { + Seq.touch(); // for loading the native library + init(); } - private static final int CALL_This = 1; - private static final String DESCRIPTOR = "try"; + private Try() {} // uninstantiable + + private static native void init(); + + + public static native String This(); } diff --git a/bind/testdata/try.java.h.golden b/bind/testdata/try.java.h.golden new file mode 100644 index 0000000..02e89f8 --- /dev/null +++ b/bind/testdata/try.java.h.golden @@ -0,0 +1,11 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java try +// +// File is generated by gobind. Do not edit. + +#ifndef __Try_H__ +#define __Try_H__ + +#include + +#endif diff --git a/bind/testdata/try.objc.go.h.golden b/bind/testdata/try.objc.go.h.golden new file mode 100644 index 0000000..d3798cf --- /dev/null +++ b/bind/testdata/try.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to try Go package. +// gobind -lang=objc try +// +// File is generated by gobind. Do not edit. + +#ifndef __try_H__ +#define __try_H__ + +#include +#include +#endif diff --git a/bind/testdata/try.objc.m.golden b/bind/testdata/try.objc.m.golden index cedbd97..cecba96 100644 --- a/bind/testdata/try.objc.m.golden +++ b/bind/testdata/try.objc.m.golden @@ -6,6 +6,7 @@ #include "GoTry.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.try"; @@ -13,17 +14,13 @@ static NSString* errDomain = @"go.try"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "try" - -#define _CALL_This_ 1 NSString* GoTryThis() { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send(_DESCRIPTOR_, _CALL_This_, &in_, &out_); - NSString* ret0_ = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret0_; + nstring r0 = proxytry__This(); + NSString *_ret0_ = go_seq_to_objc_string(r0); + return _ret0_; } +__attribute__((constructor)) static void init() { + init_seq(); +} diff --git a/bind/testdata/vars.go.golden b/bind/testdata/vars.go.golden index 2dc1ecc..5ef1baf 100644 --- a/bind/testdata/vars.go.golden +++ b/bind/testdata/vars.go.golden @@ -1,145 +1,201 @@ -// Package go_vars is an autogenerated binder stub for package vars. +// Package gomobile_bind is an autogenerated binder stub for package vars. // gobind -lang=go vars // // File is generated by gobind. Do not edit. -package go_vars +package gomobile_bind + +/* +#include +#include +#include "seq.h" +#include "vars.h" + +*/ +import "C" import ( _seq "golang.org/x/mobile/bind/seq" "vars" ) -func var_setABool(out, in *_seq.Buffer) { - v := in.ReadBool() - vars.ABool = v -} -func var_getABool(out, in *_seq.Buffer) { - out.WriteBool(vars.ABool) -} -func var_setAFloat(out, in *_seq.Buffer) { - v := in.ReadFloat64() - vars.AFloat = v -} -func var_getAFloat(out, in *_seq.Buffer) { - out.WriteFloat64(vars.AFloat) -} -func var_setAFloat32(out, in *_seq.Buffer) { - v := in.ReadFloat32() - vars.AFloat32 = v -} -func var_getAFloat32(out, in *_seq.Buffer) { - out.WriteFloat32(vars.AFloat32) -} -func var_setAFloat64(out, in *_seq.Buffer) { - v := in.ReadFloat64() - vars.AFloat64 = v -} -func var_getAFloat64(out, in *_seq.Buffer) { - out.WriteFloat64(vars.AFloat64) -} -func var_setAString(out, in *_seq.Buffer) { - v := in.ReadString() - vars.AString = v -} -func var_getAString(out, in *_seq.Buffer) { - out.WriteString(vars.AString) -} -func var_setAStructPtr(out, in *_seq.Buffer) { - // Must be a Go object - v_ref := in.ReadRef() - v := v_ref.Get().(*vars.S) - vars.AStructPtr = v -} -func var_getAStructPtr(out, in *_seq.Buffer) { - out.WriteGoRef(vars.AStructPtr) -} -func var_setAnInt(out, in *_seq.Buffer) { - v := in.ReadInt() - vars.AnInt = v -} -func var_getAnInt(out, in *_seq.Buffer) { - out.WriteInt(vars.AnInt) -} -func var_setAnInt16(out, in *_seq.Buffer) { - v := in.ReadInt16() - vars.AnInt16 = v -} -func var_getAnInt16(out, in *_seq.Buffer) { - out.WriteInt16(vars.AnInt16) -} -func var_setAnInt32(out, in *_seq.Buffer) { - v := in.ReadInt32() - vars.AnInt32 = v -} -func var_getAnInt32(out, in *_seq.Buffer) { - out.WriteInt32(vars.AnInt32) -} -func var_setAnInt64(out, in *_seq.Buffer) { - v := in.ReadInt64() - vars.AnInt64 = v -} -func var_getAnInt64(out, in *_seq.Buffer) { - out.WriteInt64(vars.AnInt64) -} -func var_setAnInt8(out, in *_seq.Buffer) { - v := in.ReadInt8() - vars.AnInt8 = v -} -func var_getAnInt8(out, in *_seq.Buffer) { - out.WriteInt8(vars.AnInt8) -} -func var_setAnInterface(out, in *_seq.Buffer) { - var v vars.I - v_ref := in.ReadRef() - if v_ref.Num < 0 { // go object - v = v_ref.Get().(vars.I) - } else if v_ref.Num != _seq.NullRefNum { // foreign object - v = (*proxyI)(v_ref) - } - vars.AnInterface = v -} -func var_getAnInterface(out, in *_seq.Buffer) { - out.WriteGoRef(vars.AnInterface) -} - -const ( - proxyI_Descriptor = "go.vars.I" -) - -type proxyI _seq.Ref - -const ( - proxyS_Descriptor = "go.vars.S" -) +// suppress the error if seq ends up unused +var _ = _seq.FromRefNum type proxyS _seq.Ref -func init() { +type proxyvars_I _seq.Ref + +//export var_setvars_ABool +func var_setvars_ABool(v C.char) { + _v := v != 0 + vars.ABool = _v } -func init() { - _seq.Register("vars.ABool", 1, var_setABool) - _seq.Register("vars.ABool", 2, var_getABool) - _seq.Register("vars.AFloat", 1, var_setAFloat) - _seq.Register("vars.AFloat", 2, var_getAFloat) - _seq.Register("vars.AFloat32", 1, var_setAFloat32) - _seq.Register("vars.AFloat32", 2, var_getAFloat32) - _seq.Register("vars.AFloat64", 1, var_setAFloat64) - _seq.Register("vars.AFloat64", 2, var_getAFloat64) - _seq.Register("vars.AString", 1, var_setAString) - _seq.Register("vars.AString", 2, var_getAString) - _seq.Register("vars.AStructPtr", 1, var_setAStructPtr) - _seq.Register("vars.AStructPtr", 2, var_getAStructPtr) - _seq.Register("vars.AnInt", 1, var_setAnInt) - _seq.Register("vars.AnInt", 2, var_getAnInt) - _seq.Register("vars.AnInt16", 1, var_setAnInt16) - _seq.Register("vars.AnInt16", 2, var_getAnInt16) - _seq.Register("vars.AnInt32", 1, var_setAnInt32) - _seq.Register("vars.AnInt32", 2, var_getAnInt32) - _seq.Register("vars.AnInt64", 1, var_setAnInt64) - _seq.Register("vars.AnInt64", 2, var_getAnInt64) - _seq.Register("vars.AnInt8", 1, var_setAnInt8) - _seq.Register("vars.AnInt8", 2, var_getAnInt8) - _seq.Register("vars.AnInterface", 1, var_setAnInterface) - _seq.Register("vars.AnInterface", 2, var_getAnInterface) +//export var_getvars_ABool +func var_getvars_ABool() C.char { + v := vars.ABool + var _v C.char = 0 + if v { + _v = 1 + } + return _v +} + +//export var_setvars_AFloat +func var_setvars_AFloat(v C.double) { + _v := float64(v) + vars.AFloat = _v +} + +//export var_getvars_AFloat +func var_getvars_AFloat() C.double { + v := vars.AFloat + _v := C.double(v) + return _v +} + +//export var_setvars_AFloat32 +func var_setvars_AFloat32(v C.float) { + _v := float32(v) + vars.AFloat32 = _v +} + +//export var_getvars_AFloat32 +func var_getvars_AFloat32() C.float { + v := vars.AFloat32 + _v := C.float(v) + return _v +} + +//export var_setvars_AFloat64 +func var_setvars_AFloat64(v C.double) { + _v := float64(v) + vars.AFloat64 = _v +} + +//export var_getvars_AFloat64 +func var_getvars_AFloat64() C.double { + v := vars.AFloat64 + _v := C.double(v) + return _v +} + +//export var_setvars_AString +func var_setvars_AString(v C.nstring) { + _v := decodeString(v, false) + vars.AString = _v +} + +//export var_getvars_AString +func var_getvars_AString() C.nstring { + v := vars.AString + _v := encodeString(v, true) + return _v +} + +//export var_setvars_AStructPtr +func var_setvars_AStructPtr(v C.int32_t) { + // Must be a Go object + _v_ref := _seq.FromRefNum(int32(v)) + _v := _v_ref.Get().(*vars.S) + vars.AStructPtr = _v +} + +//export var_getvars_AStructPtr +func var_getvars_AStructPtr() C.int32_t { + v := vars.AStructPtr + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v +} + +//export var_setvars_AnInt +func var_setvars_AnInt(v C.nint) { + _v := int(v) + vars.AnInt = _v +} + +//export var_getvars_AnInt +func var_getvars_AnInt() C.nint { + v := vars.AnInt + _v := C.nint(v) + return _v +} + +//export var_setvars_AnInt16 +func var_setvars_AnInt16(v C.int16_t) { + _v := int16(v) + vars.AnInt16 = _v +} + +//export var_getvars_AnInt16 +func var_getvars_AnInt16() C.int16_t { + v := vars.AnInt16 + _v := C.int16_t(v) + return _v +} + +//export var_setvars_AnInt32 +func var_setvars_AnInt32(v C.int32_t) { + _v := int32(v) + vars.AnInt32 = _v +} + +//export var_getvars_AnInt32 +func var_getvars_AnInt32() C.int32_t { + v := vars.AnInt32 + _v := C.int32_t(v) + return _v +} + +//export var_setvars_AnInt64 +func var_setvars_AnInt64(v C.int64_t) { + _v := int64(v) + vars.AnInt64 = _v +} + +//export var_getvars_AnInt64 +func var_getvars_AnInt64() C.int64_t { + v := vars.AnInt64 + _v := C.int64_t(v) + return _v +} + +//export var_setvars_AnInt8 +func var_setvars_AnInt8(v C.int8_t) { + _v := int8(v) + vars.AnInt8 = _v +} + +//export var_getvars_AnInt8 +func var_getvars_AnInt8() C.int8_t { + v := vars.AnInt8 + _v := C.int8_t(v) + return _v +} + +//export var_setvars_AnInterface +func var_setvars_AnInterface(v C.int32_t) { + var _v vars.I + _v_ref := _seq.FromRefNum(int32(v)) + if _v_ref != nil { + if _v_ref.Num < 0 { // go object + _v = _v_ref.Get().(vars.I) + } else { // foreign object + _v = (*proxyvars_I)(_v_ref) + } + } + vars.AnInterface = _v +} + +//export var_getvars_AnInterface +func var_getvars_AnInterface() C.int32_t { + v := vars.AnInterface + var _v C.int32_t = _seq.NullRefNum + if v != nil { + _v = C.int32_t(_seq.ToRefNum(v)) + } + return _v } diff --git a/bind/testdata/vars.java.c.golden b/bind/testdata/vars.java.c.golden new file mode 100644 index 0000000..dedc189 --- /dev/null +++ b/bind/testdata/vars.java.c.golden @@ -0,0 +1,189 @@ +// JNI functions for the Go <=> Java bridge. +// gobind -lang=java vars +// +// File is generated by gobind. Do not edit. + +#include +#include +#include "seq.h" +#include "vars.h" +#include "_cgo_export.h" + + +static jclass proxy_class_vars_I; +static jmethodID proxy_class_vars_I_cons; +static jclass proxy_class_vars_S; +static jmethodID proxy_class_vars_S_cons; + +JNIEXPORT void JNICALL +Java_go_vars_Vars_init(JNIEnv *env, jclass _unused) { + jclass clazz; + clazz = (*env)->FindClass(env, "go/vars/Vars$S"); + proxy_class_vars_S = (*env)->NewGlobalRef(env, clazz); + proxy_class_vars_S_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/vars/Vars$I$Proxy"); + proxy_class_vars_I = (*env)->NewGlobalRef(env, clazz); + proxy_class_vars_I_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/vars/Vars$I"); + +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setABool(JNIEnv *env, jclass clazz, jboolean v) { + char _v = (char)v; + var_setvars_ABool(_v); +} + +JNIEXPORT jboolean JNICALL +Java_go_vars_Vars_getABool(JNIEnv *env, jclass clazz) { + char r0 = var_getvars_ABool(); + jboolean _r0 = r0 ? JNI_TRUE : JNI_FALSE; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAFloat(JNIEnv *env, jclass clazz, jdouble v) { + double _v = (double)v; + var_setvars_AFloat(_v); +} + +JNIEXPORT jdouble JNICALL +Java_go_vars_Vars_getAFloat(JNIEnv *env, jclass clazz) { + double r0 = var_getvars_AFloat(); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAFloat32(JNIEnv *env, jclass clazz, jfloat v) { + float _v = (float)v; + var_setvars_AFloat32(_v); +} + +JNIEXPORT jfloat JNICALL +Java_go_vars_Vars_getAFloat32(JNIEnv *env, jclass clazz) { + float r0 = var_getvars_AFloat32(); + jfloat _r0 = (jfloat)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAFloat64(JNIEnv *env, jclass clazz, jdouble v) { + double _v = (double)v; + var_setvars_AFloat64(_v); +} + +JNIEXPORT jdouble JNICALL +Java_go_vars_Vars_getAFloat64(JNIEnv *env, jclass clazz) { + double r0 = var_getvars_AFloat64(); + jdouble _r0 = (jdouble)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAString(JNIEnv *env, jclass clazz, jstring v) { + nstring _v = go_seq_from_java_string(env, v, 0); + var_setvars_AString(_v); + if (_v.chars != NULL) { + (*env)->ReleaseStringChars(env, v, _v.chars); + } +} + +JNIEXPORT jstring JNICALL +Java_go_vars_Vars_getAString(JNIEnv *env, jclass clazz) { + nstring r0 = var_getvars_AString(); + jstring _r0 = go_seq_to_java_string(env, r0); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAStructPtr(JNIEnv *env, jclass clazz, jobject v) { + int32_t _v = go_seq_to_refnum(env, v); + var_setvars_AStructPtr(_v); +} + +JNIEXPORT jobject JNICALL +Java_go_vars_Vars_getAStructPtr(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AStructPtr(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_vars_S, proxy_class_vars_S_cons); + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInt(JNIEnv *env, jclass clazz, jlong v) { + nint _v = (nint)v; + var_setvars_AnInt(_v); +} + +JNIEXPORT jlong JNICALL +Java_go_vars_Vars_getAnInt(JNIEnv *env, jclass clazz) { + nint r0 = var_getvars_AnInt(); + jlong _r0 = (jlong)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInt16(JNIEnv *env, jclass clazz, jshort v) { + int16_t _v = (int16_t)v; + var_setvars_AnInt16(_v); +} + +JNIEXPORT jshort JNICALL +Java_go_vars_Vars_getAnInt16(JNIEnv *env, jclass clazz) { + int16_t r0 = var_getvars_AnInt16(); + jshort _r0 = (jshort)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInt32(JNIEnv *env, jclass clazz, jint v) { + int32_t _v = (int32_t)v; + var_setvars_AnInt32(_v); +} + +JNIEXPORT jint JNICALL +Java_go_vars_Vars_getAnInt32(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AnInt32(); + jint _r0 = (jint)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInt64(JNIEnv *env, jclass clazz, jlong v) { + int64_t _v = (int64_t)v; + var_setvars_AnInt64(_v); +} + +JNIEXPORT jlong JNICALL +Java_go_vars_Vars_getAnInt64(JNIEnv *env, jclass clazz) { + int64_t r0 = var_getvars_AnInt64(); + jlong _r0 = (jlong)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInt8(JNIEnv *env, jclass clazz, jbyte v) { + int8_t _v = (int8_t)v; + var_setvars_AnInt8(_v); +} + +JNIEXPORT jbyte JNICALL +Java_go_vars_Vars_getAnInt8(JNIEnv *env, jclass clazz) { + int8_t r0 = var_getvars_AnInt8(); + jbyte _r0 = (jbyte)r0; + return _r0; +} + +JNIEXPORT void JNICALL +Java_go_vars_Vars_setAnInterface(JNIEnv *env, jclass clazz, jobject v) { + int32_t _v = go_seq_to_refnum(env, v); + var_setvars_AnInterface(_v); +} + +JNIEXPORT jobject JNICALL +Java_go_vars_Vars_getAnInterface(JNIEnv *env, jclass clazz) { + int32_t r0 = var_getvars_AnInterface(); + jobject _r0 = go_seq_from_refnum(env, r0, proxy_class_vars_I, proxy_class_vars_I_cons); + return _r0; +} + diff --git a/bind/testdata/vars.java.golden b/bind/testdata/vars.java.golden index efda725..8a6b8fe 100644 --- a/bind/testdata/vars.java.golden +++ b/bind/testdata/vars.java.golden @@ -7,211 +7,21 @@ package go.vars; import go.Seq; public abstract class Vars { + static { + Seq.touch(); // for loading the native library + init(); + } + private Vars() {} // uninstantiable - public static void setABool(boolean v) { - Seq in = new Seq(); - in.writeBool(v); - Seq.send("vars.ABool", 1, in, null); - } + private static native void init(); - public static boolean getABool() { - Seq out = new Seq(); - Seq.send("vars.ABool", 2, null, out); - boolean v = out.readBool(); - return v; - } - - public static void setAFloat(double v) { - Seq in = new Seq(); - in.writeFloat64(v); - Seq.send("vars.AFloat", 1, in, null); - } - - public static double getAFloat() { - Seq out = new Seq(); - Seq.send("vars.AFloat", 2, null, out); - double v = out.readFloat64(); - return v; - } - - public static void setAFloat32(float v) { - Seq in = new Seq(); - in.writeFloat32(v); - Seq.send("vars.AFloat32", 1, in, null); - } - - public static float getAFloat32() { - Seq out = new Seq(); - Seq.send("vars.AFloat32", 2, null, out); - float v = out.readFloat32(); - return v; - } - - public static void setAFloat64(double v) { - Seq in = new Seq(); - in.writeFloat64(v); - Seq.send("vars.AFloat64", 1, in, null); - } - - public static double getAFloat64() { - Seq out = new Seq(); - Seq.send("vars.AFloat64", 2, null, out); - double v = out.readFloat64(); - return v; - } - - public static void setAString(String v) { - Seq in = new Seq(); - in.writeString(v); - Seq.send("vars.AString", 1, in, null); - } - - public static String getAString() { - Seq out = new Seq(); - Seq.send("vars.AString", 2, null, out); - String v = out.readString(); - return v; - } - - public static void setAStructPtr(S v) { - Seq in = new Seq(); - in.writeRef(v != null ? v.ref() : null); - Seq.send("vars.AStructPtr", 1, in, null); - } - - public static S getAStructPtr() { - Seq out = new Seq(); - Seq.send("vars.AStructPtr", 2, null, out); - S v = new S(out.readRef()); - return v; - } - - public static void setAnInt(long v) { - Seq in = new Seq(); - in.writeInt(v); - Seq.send("vars.AnInt", 1, in, null); - } - - public static long getAnInt() { - Seq out = new Seq(); - Seq.send("vars.AnInt", 2, null, out); - long v = out.readInt(); - return v; - } - - public static void setAnInt16(short v) { - Seq in = new Seq(); - in.writeInt16(v); - Seq.send("vars.AnInt16", 1, in, null); - } - - public static short getAnInt16() { - Seq out = new Seq(); - Seq.send("vars.AnInt16", 2, null, out); - short v = out.readInt16(); - return v; - } - - public static void setAnInt32(int v) { - Seq in = new Seq(); - in.writeInt32(v); - Seq.send("vars.AnInt32", 1, in, null); - } - - public static int getAnInt32() { - Seq out = new Seq(); - Seq.send("vars.AnInt32", 2, null, out); - int v = out.readInt32(); - return v; - } - - public static void setAnInt64(long v) { - Seq in = new Seq(); - in.writeInt64(v); - Seq.send("vars.AnInt64", 1, in, null); - } - - public static long getAnInt64() { - Seq out = new Seq(); - Seq.send("vars.AnInt64", 2, null, out); - long v = out.readInt64(); - return v; - } - - public static void setAnInt8(byte v) { - Seq in = new Seq(); - in.writeInt8(v); - Seq.send("vars.AnInt8", 1, in, null); - } - - public static byte getAnInt8() { - Seq out = new Seq(); - Seq.send("vars.AnInt8", 2, null, out); - byte v = out.readInt8(); - return v; - } - - public static void setAnInterface(I v) { - Seq in = new Seq(); - in.writeRef(v != null ? v.ref() : null); - Seq.send("vars.AnInterface", 1, in, null); - } - - public static I getAnInterface() { - Seq out = new Seq(); - Seq.send("vars.AnInterface", 2, null, out); - I v = new I.Proxy(out.readRef()); - return v; - } - - public interface I extends go.Seq.Object { - public static abstract class Stub implements I { - static final String DESCRIPTOR = "go.vars.I"; - - private final go.Seq.Ref ref; - public Stub() { - ref = go.Seq.createRef(this); - } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - switch (code) { - default: - throw new RuntimeException("unknown code: "+ code); - } - } - } - - static final class Proxy implements I { - static final String DESCRIPTOR = Stub.DESCRIPTOR; - - private go.Seq.Ref ref; - - Proxy(go.Seq.Ref ref) { this.ref = ref; } - - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("cycle: cannot call proxy"); - } - - } - } - - public static final class S implements go.Seq.Object { - private static final String DESCRIPTOR = "go.vars.S"; - - private go.Seq.Ref ref; + public static final class S implements go.Seq.Object, I { + private final go.Seq.Ref ref; private S(go.Seq.Ref ref) { this.ref = ref; } - public go.Seq.Ref ref() { return ref; } - - public void call(int code, go.Seq in, go.Seq out) { - throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); - } + public final go.Seq.Ref ref() { return ref; } @Override public boolean equals(Object o) { if (o == null || !(o instanceof S)) { @@ -230,8 +40,64 @@ public abstract class Vars { b.append("S").append("{"); return b.append("}").toString(); } - } - private static final String DESCRIPTOR = "vars"; + public interface I extends go.Seq.Object { + public static abstract class Stub implements I { + private final go.Seq.Ref ref; + public Stub() { + ref = go.Seq.createRef(this); + } + + public final go.Seq.Ref ref() { return ref; } + + } + + static final class Proxy implements I { + private go.Seq.Ref ref; + + Proxy(go.Seq.Ref ref) { this.ref = ref; } + + public final go.Seq.Ref ref() { return ref; } + + } + } + + + public static native void setABool(boolean v); + public static native boolean getABool(); + + public static native void setAFloat(double v); + public static native double getAFloat(); + + public static native void setAFloat32(float v); + public static native float getAFloat32(); + + public static native void setAFloat64(double v); + public static native double getAFloat64(); + + public static native void setAString(String v); + public static native String getAString(); + + public static native void setAStructPtr(S v); + public static native S getAStructPtr(); + + public static native void setAnInt(long v); + public static native long getAnInt(); + + public static native void setAnInt16(short v); + public static native short getAnInt16(); + + public static native void setAnInt32(int v); + public static native int getAnInt32(); + + public static native void setAnInt64(long v); + public static native long getAnInt64(); + + public static native void setAnInt8(byte v); + public static native byte getAnInt8(); + + public static native void setAnInterface(I v); + public static native I getAnInterface(); + } diff --git a/bind/testdata/vars.java.h.golden b/bind/testdata/vars.java.h.golden new file mode 100644 index 0000000..6ef9a45 --- /dev/null +++ b/bind/testdata/vars.java.h.golden @@ -0,0 +1,11 @@ +// JNI function headers for the Go <=> Java bridge. +// gobind -lang=java vars +// +// File is generated by gobind. Do not edit. + +#ifndef __Vars_H__ +#define __Vars_H__ + +#include + +#endif diff --git a/bind/testdata/vars.objc.go.h.golden b/bind/testdata/vars.objc.go.h.golden new file mode 100644 index 0000000..aad1c5a --- /dev/null +++ b/bind/testdata/vars.objc.go.h.golden @@ -0,0 +1,11 @@ +// Objective-C API for talking to vars Go package. +// gobind -lang=objc vars +// +// File is generated by gobind. Do not edit. + +#ifndef __vars_H__ +#define __vars_H__ + +#include +#include +#endif diff --git a/bind/testdata/vars.objc.h.golden b/bind/testdata/vars.objc.h.golden index da431d0..6a9645f 100644 --- a/bind/testdata/vars.objc.h.golden +++ b/bind/testdata/vars.objc.h.golden @@ -22,7 +22,7 @@ @protocol GoVarsI @end -@interface GoVars : NSObject +@interface GoVars : NSObject + (BOOL) aBool; + (void) setABool:(BOOL)v; diff --git a/bind/testdata/vars.objc.m.golden b/bind/testdata/vars.objc.m.golden index 6261133..5d87788 100644 --- a/bind/testdata/vars.objc.m.golden +++ b/bind/testdata/vars.objc.m.golden @@ -6,6 +6,7 @@ #include "GoVars.h" #include #include "seq.h" +#include "_cgo_export.h" static NSString* errDomain = @"go.vars"; @@ -13,8 +14,6 @@ static NSString* errDomain = @"go.vars"; -(GoSeqRef*) _ref; @end -#define _DESCRIPTOR_ "vars" - @class GoVarsI; @interface GoVarsI : NSObject { @@ -24,7 +23,6 @@ static NSString* errDomain = @"go.vars"; - (id)initWithRef:(id)ref; @end -#define _GO_vars_S_DESCRIPTOR_ "go.vars.S" @implementation GoVarsS { } @@ -37,8 +35,6 @@ static NSString* errDomain = @"go.vars"; @end -#define _GO_vars_I_DESCRIPTOR_ "go.vars.I" - @implementation GoVarsI { } @@ -50,263 +46,169 @@ static NSString* errDomain = @"go.vars"; @end -static void proxyGoVarsI(id obj, int code, GoSeq* in, GoSeq* out) { - switch (code) { - default: - NSLog(@"unknown code %x for _GO_vars_I_DESCRIPTOR_", code); - } -} @implementation GoVars + (void) setABool:(BOOL)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeBool(&in_, v); - go_seq_send("vars.ABool", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + char _v = (char)v; + var_setvars_ABool(_v); } + (BOOL) aBool { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.ABool", 2, &in_, &out_); - BOOL ret = go_seq_readBool(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + char r0 = var_getvars_ABool(); + BOOL _r0 = r0 ? YES : NO; + return _r0; } + (void) setAFloat:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeFloat64(&in_, v); - go_seq_send("vars.AFloat", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + double _v = (double)v; + var_setvars_AFloat(_v); } + (double) aFloat { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AFloat", 2, &in_, &out_); - double ret = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + double r0 = var_getvars_AFloat(); + double _r0 = (double)r0; + return _r0; } + (void) setAFloat32:(float)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeFloat32(&in_, v); - go_seq_send("vars.AFloat32", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + float _v = (float)v; + var_setvars_AFloat32(_v); } + (float) aFloat32 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AFloat32", 2, &in_, &out_); - float ret = go_seq_readFloat32(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + float r0 = var_getvars_AFloat32(); + float _r0 = (float)r0; + return _r0; } + (void) setAFloat64:(double)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeFloat64(&in_, v); - go_seq_send("vars.AFloat64", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + double _v = (double)v; + var_setvars_AFloat64(_v); } + (double) aFloat64 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AFloat64", 2, &in_, &out_); - double ret = go_seq_readFloat64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + double r0 = var_getvars_AFloat64(); + double _r0 = (double)r0; + return _r0; } + (void) setAString:(NSString*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeUTF8(&in_, v); - go_seq_send("vars.AString", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + nstring _v = go_seq_from_objc_string(v); + var_setvars_AString(_v); } + (NSString*) aString { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AString", 2, &in_, &out_); - NSString* ret = go_seq_readUTF8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + nstring r0 = var_getvars_AString(); + NSString *_r0 = go_seq_to_objc_string(r0); + return _r0; } + (void) setAStructPtr:(GoVarsS*)v { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _v; if ([(id)(v) isKindOfClass:[GoVarsS class]]) { id v_proxy = (id)(v); - go_seq_writeRef(&in_, v_proxy._ref); + _v = go_seq_go_to_refnum(v_proxy._ref); } else { - go_seq_writeObjcRef(&in_, v); + _v = go_seq_to_refnum(v); } - go_seq_send("vars.AStructPtr", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + var_setvars_AStructPtr(_v); } + (GoVarsS*) aStructPtr { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AStructPtr", 2, &in_, &out_); - GoSeqRef* ret_ref = go_seq_readRef(&out_); - GoVarsS* ret = ret_ref.obj; - if (ret == NULL) { - ret = [[GoVarsS alloc] initWithRef:ret_ref]; + int32_t r0 = var_getvars_AStructPtr(); + GoVarsS* _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoVarsS alloc] initWithRef:_r0_ref]; + } } - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + return _r0; } + (void) setAnInt:(int)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt(&in_, v); - go_seq_send("vars.AnInt", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + nint _v = (nint)v; + var_setvars_AnInt(_v); } + (int) anInt { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInt", 2, &in_, &out_); - int ret = go_seq_readInt(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + nint r0 = var_getvars_AnInt(); + int _r0 = (int)r0; + return _r0; } + (void) setAnInt16:(int16_t)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt16(&in_, v); - go_seq_send("vars.AnInt16", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int16_t _v = (int16_t)v; + var_setvars_AnInt16(_v); } + (int16_t) anInt16 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInt16", 2, &in_, &out_); - int16_t ret = go_seq_readInt16(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + int16_t r0 = var_getvars_AnInt16(); + int16_t _r0 = (int16_t)r0; + return _r0; } + (void) setAnInt32:(int32_t)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt32(&in_, v); - go_seq_send("vars.AnInt32", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int32_t _v = (int32_t)v; + var_setvars_AnInt32(_v); } + (int32_t) anInt32 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInt32", 2, &in_, &out_); - int32_t ret = go_seq_readInt32(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + int32_t r0 = var_getvars_AnInt32(); + int32_t _r0 = (int32_t)r0; + return _r0; } + (void) setAnInt64:(int64_t)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt64(&in_, v); - go_seq_send("vars.AnInt64", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int64_t _v = (int64_t)v; + var_setvars_AnInt64(_v); } + (int64_t) anInt64 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInt64", 2, &in_, &out_); - int64_t ret = go_seq_readInt64(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + int64_t r0 = var_getvars_AnInt64(); + int64_t _r0 = (int64_t)r0; + return _r0; } + (void) setAnInt8:(int8_t)v { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_writeInt8(&in_, v); - go_seq_send("vars.AnInt8", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + int8_t _v = (int8_t)v; + var_setvars_AnInt8(_v); } + (int8_t) anInt8 { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInt8", 2, &in_, &out_); - int8_t ret = go_seq_readInt8(&out_); - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + int8_t r0 = var_getvars_AnInt8(); + int8_t _r0 = (int8_t)r0; + return _r0; } + (void) setAnInterface:(id)v { - GoSeq in_ = {}; - GoSeq out_ = {}; + int32_t _v; if ([(id)(v) isKindOfClass:[GoVarsI class]]) { id v_proxy = (id)(v); - go_seq_writeRef(&in_, v_proxy._ref); + _v = go_seq_go_to_refnum(v_proxy._ref); } else { - go_seq_writeObjcRef(&in_, v); + _v = go_seq_to_refnum(v); } - go_seq_send("vars.AnInterface", 1, &in_, &out_); - go_seq_free(&in_); - go_seq_free(&out_); + var_setvars_AnInterface(_v); } + (id) anInterface { - GoSeq in_ = {}; - GoSeq out_ = {}; - go_seq_send("vars.AnInterface", 2, &in_, &out_); - GoSeqRef* ret_ref = go_seq_readRef(&out_); - id ret = ret_ref.obj; - if (ret == NULL) { - ret = [[GoVarsI alloc] initWithRef:ret_ref]; + int32_t r0 = var_getvars_AnInterface(); + id _r0 = nil; + GoSeqRef* _r0_ref = go_seq_from_refnum(r0); + if (_r0_ref != NULL) { + _r0 = _r0_ref.obj; + if (_r0 == nil) { + _r0 = [[GoVarsI alloc] initWithRef:_r0_ref]; + } } - go_seq_free(&in_); - go_seq_free(&out_); - return ret; + return _r0; } @end __attribute__((constructor)) static void init() { - go_seq_register_proxy("go.vars.I", proxyGoVarsI); + init_seq(); } diff --git a/bind/types.go b/bind/types.go index 91708b5..2f368dd 100644 --- a/bind/types.go +++ b/bind/types.go @@ -5,6 +5,7 @@ package bind import ( + "fmt" "go/types" "log" ) @@ -115,3 +116,22 @@ func isExported(t types.Type) bool { return true } } + +func isRefType(t types.Type) bool { + if isErrorType(t) { + return false + } + switch t := t.(type) { + case *types.Named: + switch u := t.Underlying().(type) { + case *types.Interface: + return true + default: + panic(fmt.Sprintf("unsupported named type: %s / %T", u, u)) + } + case *types.Pointer: + return isRefType(t.Elem()) + default: + return false + } +} diff --git a/cmd/gobind/gen.go b/cmd/gobind/gen.go index d080d96..6b7624f 100644 --- a/cmd/gobind/gen.go +++ b/cmd/gobind/gen.go @@ -20,26 +20,33 @@ func genPkg(p *types.Package) { fname := defaultFileName(*lang, p) switch *lang { case "java": - w, closer := writer(fname, p) - processErr(bind.GenJava(w, fset, p, *javaPkg)) + w, closer := writer(fname) + processErr(bind.GenJava(w, fset, p, *javaPkg, bind.Java)) + closer() + cname := "java_" + p.Name() + ".c" + w, closer = writer(cname) + processErr(bind.GenJava(w, fset, p, *javaPkg, bind.JavaC)) + closer() + hname := p.Name() + ".h" + w, closer = writer(hname) + processErr(bind.GenJava(w, fset, p, *javaPkg, bind.JavaH)) closer() case "go": - w, closer := writer(fname, p) + w, closer := writer(fname) processErr(bind.GenGo(w, fset, p)) closer() case "objc": - if fname == "" { - processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, true)) - processErr(bind.GenObjc(os.Stdout, fset, p, *prefix, false)) - } else { - hname := fname[:len(fname)-2] + ".h" - w, closer := writer(hname, p) - processErr(bind.GenObjc(w, fset, p, *prefix, true)) - closer() - w, closer = writer(fname, p) - processErr(bind.GenObjc(w, fset, p, *prefix, false)) - closer() - } + gohname := p.Name() + ".h" + w, closer := writer(gohname) + processErr(bind.GenObjc(w, fset, p, *prefix, bind.ObjcGoH)) + closer() + hname := fname[:len(fname)-2] + ".h" + w, closer = writer(hname) + processErr(bind.GenObjc(w, fset, p, *prefix, bind.ObjcH)) + closer() + w, closer = writer(fname) + processErr(bind.GenObjc(w, fset, p, *prefix, bind.ObjcM)) + closer() default: errorf("unknown target language: %q", *lang) } @@ -59,18 +66,19 @@ func processErr(err error) { var fset = token.NewFileSet() -func writer(fname string, pkg *types.Package) (w io.Writer, closer func()) { - if fname == "" { +func writer(fname string) (w io.Writer, closer func()) { + if *outdir == "" { return os.Stdout, func() { return } } - dir := filepath.Dir(fname) + name := filepath.Join(*outdir, fname) + dir := filepath.Dir(name) if err := os.MkdirAll(dir, 0755); err != nil { errorf("invalid output dir: %v", err) os.Exit(exitStatus) } - f, err := os.Create(fname) + f, err := os.Create(name) if err != nil { errorf("invalid output dir: %v", err) os.Exit(exitStatus) @@ -84,21 +92,17 @@ func writer(fname string, pkg *types.Package) (w io.Writer, closer func()) { } func defaultFileName(lang string, pkg *types.Package) string { - if *outdir == "" { - return "" - } - switch lang { case "java": firstRune, size := utf8.DecodeRuneInString(pkg.Name()) className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] - return filepath.Join(*outdir, className+".java") + return className + ".java" case "go": - return filepath.Join(*outdir, "go_"+pkg.Name()+".go") + return "go_" + pkg.Name() + ".go" case "objc": firstRune, size := utf8.DecodeRuneInString(pkg.Name()) className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:] - return filepath.Join(*outdir, "Go"+className+".m") + return "Go" + className + ".m" } errorf("unknown target language: %q", lang) os.Exit(exitStatus) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index 7d5c2c1..41cacb5 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -138,6 +138,28 @@ type binder struct { pkgs []*types.Package } +func (b *binder) GenGoSupport(outdir string) error { + bindPkg, err := ctx.Import("golang.org/x/mobile/bind", "", build.FindOnly) + if err != nil { + return err + } + return copyFile(filepath.Join(outdir, "seq.go"), filepath.Join(bindPkg.Dir, "seq.go.support")) +} + +func (b *binder) GenObjcSupport(outdir string) error { + objcPkg, err := ctx.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly) + if err != nil { + return err + } + if err := copyFile(filepath.Join(outdir, "seq_darwin.m"), filepath.Join(objcPkg.Dir, "seq_darwin.m.support")); err != nil { + return err + } + if err := copyFile(filepath.Join(outdir, "seq_darwin.go"), filepath.Join(objcPkg.Dir, "seq_darwin.go.support")); err != nil { + return err + } + return copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(objcPkg.Dir, "seq.h")) +} + func (b *binder) GenObjc(pkg *types.Package, outdir string) (string, error) { const bindPrefixDefault = "Go" if bindPrefix == "" { @@ -152,6 +174,7 @@ func (b *binder) GenObjc(pkg *types.Package, outdir string) (string, error) { fileBase := bindPrefix + name mfile := filepath.Join(outdir, fileBase+".m") hfile := filepath.Join(outdir, fileBase+".h") + gohfile := filepath.Join(outdir, pkg.Name()+".h") generate := func(w io.Writer) error { if buildX { @@ -160,7 +183,7 @@ func (b *binder) GenObjc(pkg *types.Package, outdir string) (string, error) { if buildN { return nil } - return bind.GenObjc(w, b.fset, pkg, bindPrefix, false) + return bind.GenObjc(w, b.fset, pkg, bindPrefix, bind.ObjcM) } if err := writeFile(mfile, generate); err != nil { return "", err @@ -169,25 +192,43 @@ func (b *binder) GenObjc(pkg *types.Package, outdir string) (string, error) { if buildN { return nil } - return bind.GenObjc(w, b.fset, pkg, bindPrefix, true) + return bind.GenObjc(w, b.fset, pkg, bindPrefix, bind.ObjcH) } if err := writeFile(hfile, generate); err != nil { return "", err } + generate = func(w io.Writer) error { + if buildN { + return nil + } + return bind.GenObjc(w, b.fset, pkg, bindPrefix, bind.ObjcGoH) + } + if err := writeFile(gohfile, generate); err != nil { + return "", err + } - objcPkg, err := ctx.Import("golang.org/x/mobile/bind/objc", "", build.FindOnly) - if err != nil { - return "", err - } - if err := copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(objcPkg.Dir, "seq.h")); err != nil { - return "", err - } return fileBase, nil } -func (b *binder) GenJava(pkg *types.Package, outdir string) error { +func (b *binder) GenJavaSupport(outdir string) error { + javaPkg, err := ctx.Import("golang.org/x/mobile/bind/java", "", build.FindOnly) + if err != nil { + return err + } + if err := copyFile(filepath.Join(outdir, "seq_android.go"), filepath.Join(javaPkg.Dir, "seq_android.go.support")); err != nil { + return err + } + if err := copyFile(filepath.Join(outdir, "seq_android.c"), filepath.Join(javaPkg.Dir, "seq_android.c.support")); err != nil { + return err + } + return copyFile(filepath.Join(outdir, "seq.h"), filepath.Join(javaPkg.Dir, "seq.h")) +} + +func (b *binder) GenJava(pkg *types.Package, outdir, javadir string) error { className := strings.Title(pkg.Name()) - javaFile := filepath.Join(outdir, className+".java") + javaFile := filepath.Join(javadir, className+".java") + cFile := filepath.Join(outdir, "java_"+pkg.Name()+".c") + hFile := filepath.Join(outdir, pkg.Name()+".h") bindOption := "-lang=java" if bindJavaPkg != "" { bindOption += " -javapkg=" + bindJavaPkg @@ -195,22 +236,36 @@ func (b *binder) GenJava(pkg *types.Package, outdir string) error { generate := func(w io.Writer) error { if buildX { - printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkg.Path()) + printcmd("gobind %s -outdir=%s %s", bindOption, javadir, pkg.Path()) } if buildN { return nil } - return bind.GenJava(w, b.fset, pkg, bindJavaPkg) + return bind.GenJava(w, b.fset, pkg, bindJavaPkg, bind.Java) } if err := writeFile(javaFile, generate); err != nil { return err } - return nil + generate = func(w io.Writer) error { + if buildN { + return nil + } + return bind.GenJava(w, b.fset, pkg, bindJavaPkg, bind.JavaC) + } + if err := writeFile(cFile, generate); err != nil { + return err + } + generate = func(w io.Writer) error { + if buildN { + return nil + } + return bind.GenJava(w, b.fset, pkg, bindJavaPkg, bind.JavaH) + } + return writeFile(hFile, generate) } func (b *binder) GenGo(pkg *types.Package, outdir string) error { pkgName := "go_" + pkg.Name() - outdir = filepath.Join(outdir, pkgName) goFile := filepath.Join(outdir, pkgName+"main.go") generate := func(w io.Writer) error { diff --git a/cmd/gomobile/bind_androidapp.go b/cmd/gomobile/bind_androidapp.go index 8fc8552..bd86a1a 100644 --- a/cmd/gomobile/bind_androidapp.go +++ b/cmd/gomobile/bind_androidapp.go @@ -15,7 +15,6 @@ import ( "path/filepath" "strconv" "strings" - "text/template" ) func goAndroidBind(pkgs []*build.Package, androidArchs []string) error { @@ -71,29 +70,21 @@ func goAndroidBind(pkgs []*build.Package, androidArchs []string) error { return err } + srcDir := filepath.Join(tmpdir, "gomobile_bind") for _, pkg := range typesPkgs { - if err := binder.GenGo(pkg, tmpdir); err != nil { + if err := binder.GenGo(pkg, srcDir); err != nil { return err } } err = writeFile(mainFile, func(w io.Writer) error { - return androidMainTmpl.Execute(w, binder.pkgs) + _, err := w.Write(androidMainFile) + return err }) if err != nil { return fmt.Errorf("failed to create the main package for android: %v", err) } - err = goBuild( - mainFile, - env, - "-buildmode=c-shared", - "-o="+filepath.Join(androidDir, "src/main/jniLibs/"+toolchain.abi+"/libgojni.so"), - ) - if err != nil { - return err - } - p, err := ctx.Import("golang.org/x/mobile/bind", cwd, build.ImportComment) if err != nil { return fmt.Errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind`) @@ -105,15 +96,31 @@ func goAndroidBind(pkgs []*build.Package, androidArchs []string) error { if bindJavaPkg == "" { pkgpath = "go/" + pkg.Name() } - if err := binder.GenJava(pkg, filepath.Join(androidDir, "src/main/java/"+pkgpath)); err != nil { + if err := binder.GenJava(pkg, srcDir, filepath.Join(androidDir, "src/main/java/"+pkgpath)); err != nil { return err } } + if err := binder.GenJavaSupport(srcDir); err != nil { + return err + } + if err := binder.GenGoSupport(srcDir); err != nil { + return err + } javaDir := filepath.Join(androidDir, "src/main/java/go") if err := mkdir(javaDir); err != nil { return err } + err = goBuild( + mainFile, + env, + "-buildmode=c-shared", + "-o="+filepath.Join(androidDir, "src/main/jniLibs/"+toolchain.abi+"/libgojni.so"), + ) + if err != nil { + return err + } + for _, javaFile := range []string{"Seq.java", "LoadJNI.java"} { src := filepath.Join(repo, "bind/java/"+javaFile) dst := filepath.Join(javaDir, javaFile) @@ -127,17 +134,16 @@ func goAndroidBind(pkgs []*build.Package, androidArchs []string) error { return buildAAR(androidDir, pkgs, androidArchs) } -var androidMainTmpl = template.Must(template.New("android.go").Parse(` +var androidMainFile = []byte(` package main import ( _ "golang.org/x/mobile/bind/java" -{{range .}} _ "../go_{{.Name}}" -{{end}} + _ "../gomobile_bind" ) func main() {} -`)) +`) // AAR is the format for the binary distribution of an Android Library Project // and it is a ZIP archive with extension .aar. diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 57f255a..0c706a7 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -35,7 +35,7 @@ func goIOSBind(pkgs []*build.Package) error { buildO = title + ".framework" } - srcDir := filepath.Join(tmpdir, "src") + srcDir := filepath.Join(tmpdir, "src", "gomobile_bind") for _, pkg := range typesPkgs { if err := binder.GenGo(pkg, srcDir); err != nil { return err @@ -43,19 +43,25 @@ func goIOSBind(pkgs []*build.Package) error { } mainFile := filepath.Join(tmpdir, "src/iosbin/main.go") err = writeFile(mainFile, func(w io.Writer) error { - return iosBindTmpl.Execute(w, pkgs) + _, err := w.Write(iosBindFile) + return err }) if err != nil { return fmt.Errorf("failed to create the binding package for iOS: %v", err) } - objcDir := filepath.Join(tmpdir, "objc") fileBases := make([]string, len(typesPkgs)) for i, pkg := range typesPkgs { - if fileBases[i], err = binder.GenObjc(pkg, objcDir); err != nil { + if fileBases[i], err = binder.GenObjc(pkg, srcDir); err != nil { return err } } + if err := binder.GenObjcSupport(srcDir); err != nil { + return err + } + if err := binder.GenGoSupport(srcDir); err != nil { + return err + } cmd := exec.Command("xcrun", "lipo", "-create") @@ -97,7 +103,7 @@ func goIOSBind(pkgs []*build.Package) error { headerFiles[0] = title + ".h" err = copyFile( headers+"/"+title+".h", - tmpdir+"/objc/"+bindPrefix+title+".h", + srcDir+"/"+bindPrefix+title+".h", ) if err != nil { return err @@ -107,7 +113,7 @@ func goIOSBind(pkgs []*build.Package) error { headerFiles[i] = fileBase + ".h" err = copyFile( headers+"/"+fileBase+".h", - tmpdir+"/objc/"+fileBase+".h") + srcDir+"/"+fileBase+".h") if err != nil { return err } @@ -172,48 +178,20 @@ func goIOSBindArchive(name, path string, env, fileBases []string) (string, error return "", err } - objs, mfiles := make([]string, len(fileBases)), make([]string, len(fileBases)) - for i, b := range fileBases { - objs[i], mfiles[i] = b+".o", b+".m" - } - - args := append([]string{ - "-I", ".", - "-g", "-O2", - "-fobjc-arc", // enable ARC - "-c", - }, mfiles...) - - cmd := exec.Command(getenv(env, "CC"), args...) - cmd.Args = append(cmd.Args, strings.Split(getenv(env, "CGO_CFLAGS"), " ")...) - cmd.Dir = filepath.Join(tmpdir, "objc") - cmd.Env = append([]string{}, env...) - if err := runCmd(cmd); err != nil { - return "", err - } - - arArgs := append([]string{"-q", "-s", archive}, objs...) - cmd = exec.Command("ar", arArgs...) - cmd.Dir = filepath.Join(tmpdir, "objc") - if err := runCmd(cmd); err != nil { - return "", err - } return archive, nil } -var iosBindTmpl = template.Must(template.New("ios.go").Parse(` +var iosBindFile = []byte(` package main import ( - _ "golang.org/x/mobile/bind/objc" -{{range .}} _ "../go_{{.Name}}" -{{end}} + _ "../gomobile_bind" ) import "C" func main() {} -`)) +`) var iosBindHeaderTmpl = template.Must(template.New("ios.h").Parse(` // Objective-C API for talking to the following Go packages diff --git a/cmd/gomobile/bind_test.go b/cmd/gomobile/bind_test.go index 1b1e985..09a89d1 100644 --- a/cmd/gomobile/bind_test.go +++ b/cmd/gomobile/bind_test.go @@ -106,13 +106,23 @@ rm -r -f "$WORK/fakegopath" mkdir -p $WORK/fakegopath/pkg cp $GOMOBILE/pkg_android_arm/golang.org/x/mobile/asset.a $WORK/fakegopath/pkg/android_arm/golang.org/x/mobile/asset.a mkdir -p $WORK/fakegopath/pkg/android_arm/golang.org/x/mobile -mkdir -p $WORK/go_asset -gobind -lang=go -outdir=$WORK/go_asset golang.org/x/mobile/asset +mkdir -p $WORK/gomobile_bind +gobind -lang=go -outdir=$WORK/gomobile_bind golang.org/x/mobile/asset mkdir -p $WORK/androidlib -GOOS=android GOARCH=arm CC=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-gcc{{.EXE}} CXX=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-g++{{.EXE}} CGO_ENABLED=1 GOARM=7 go build -p={{.NumCPU}} -pkgdir=$GOMOBILE/pkg_android_arm -tags="" -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so $WORK/androidlib/main.go mkdir -p $WORK/android/src/main/java/{{.JavaPkgDir}} {{.GobindJavaCmd}} -outdir=$WORK/android/src/main/java/{{.JavaPkgDir}} golang.org/x/mobile/asset +mkdir -p $WORK/gomobile_bind +mkdir -p $WORK/gomobile_bind +cp $GOPATH/src/golang.org/x/mobile/bind/java/seq_android.go.support $WORK/gomobile_bind/seq_android.go +mkdir -p $WORK/gomobile_bind +cp $GOPATH/src/golang.org/x/mobile/bind/java/seq_android.c.support $WORK/gomobile_bind/seq_android.c +mkdir -p $WORK/gomobile_bind +cp $GOPATH/src/golang.org/x/mobile/bind/java/seq.h $WORK/gomobile_bind/seq.h +mkdir -p $WORK/gomobile_bind +cp $GOPATH/src/golang.org/x/mobile/bind/seq.go.support $WORK/gomobile_bind/seq.go +mkdir -p $WORK/gomobile_bind mkdir -p $WORK/android/src/main/java/go +GOOS=android GOARCH=arm CC=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-gcc{{.EXE}} CXX=$GOMOBILE/android-{{.NDK}}/arm/bin/arm-linux-androideabi-g++{{.EXE}} CGO_ENABLED=1 GOARM=7 go build -p={{.NumCPU}} -pkgdir=$GOMOBILE/pkg_android_arm -tags="" -x -buildmode=c-shared -o=$WORK/android/src/main/jniLibs/armeabi-v7a/libgojni.so $WORK/androidlib/main.go rm $WORK/android/src/main/java/go/Seq.java ln -s $GOPATH/src/golang.org/x/mobile/bind/java/Seq.java $WORK/android/src/main/java/go/Seq.java rm $WORK/android/src/main/java/go/LoadJNI.java