2
0
mirror of synced 2025-02-23 23:08:14 +00:00
mobile/bind/seq/ref.go
Elias Naur 6fca37c69e mobile/bind: replace seq serialization with direct calls
The seq serialization machinery is a historic artifact from when Go
mobile code had to run in a separate process. Now that Go code is running
in-process, replace the explicit serialization with direct calls and pass
arguments on the stack.

The benefits are a much smaller bind runtime, much less garbage (and, in
Java, fewer objects with finalizers), less argument copying, and faster
cross-language calls.
The cost is a more complex generator, because some of the work from the
bind runtime is moved to generated code. Generated code now handles
conversion between Go and Java/ObjC types, multiple return values and memory
management of byte slice and string arguments.

To overcome the lack of calling C code between Go packages, all bound
packages now end up in the same (fake) package, "gomobile_bind", instead of
separate packages (go_<pkgname>). To avoid name clashes, the package name is
added as a prefix to generated functions and types.

Also, don't copy byte arrays passed to Go, saving call time and
allowing read([]byte)-style interfaces to foreign callers (#12113).

Finally, add support for nil interfaces and struct pointers to objc.

This is a large CL, but most of the changes stem from changing testdata.

The full benchcmp output on the CL/20095 benchmarks on my Nexus 5 is
reproduced below. Note that the savings for the JavaSlice* benchmarks are
skewed because byte slices are no longer copied before passing them to Go.

benchmark                                 old ns/op     new ns/op     delta
BenchmarkJavaEmpty                        26.0          19.0          -26.92%
BenchmarkJavaEmptyDirect                  23.0          22.0          -4.35%
BenchmarkJavaNoargs                       7685          2339          -69.56%
BenchmarkJavaNoargsDirect                 17405         8041          -53.80%
BenchmarkJavaOnearg                       26887         2366          -91.20%
BenchmarkJavaOneargDirect                 34266         7910          -76.92%
BenchmarkJavaOneret                       38325         2245          -94.14%
BenchmarkJavaOneretDirect                 46265         7708          -83.34%
BenchmarkJavaManyargs                     41720         2535          -93.92%
BenchmarkJavaManyargsDirect               51026         8373          -83.59%
BenchmarkJavaRefjava                      38139         21260         -44.26%
BenchmarkJavaRefjavaDirect                42706         28150         -34.08%
BenchmarkJavaRefgo                        34403         6843          -80.11%
BenchmarkJavaRefgoDirect                  40193         16582         -58.74%
BenchmarkJavaStringShort                  32366         9323          -71.20%
BenchmarkJavaStringShortDirect            41973         19118         -54.45%
BenchmarkJavaStringLong                   127879        94420         -26.16%
BenchmarkJavaStringLongDirect             133776        114760        -14.21%
BenchmarkJavaStringShortUnicode           32562         9221          -71.68%
BenchmarkJavaStringShortUnicodeDirect     41464         19094         -53.95%
BenchmarkJavaStringLongUnicode            131015        89401         -31.76%
BenchmarkJavaStringLongUnicodeDirect      134130        90786         -32.31%
BenchmarkJavaSliceShort                   42462         7538          -82.25%
BenchmarkJavaSliceShortDirect             52940         17017         -67.86%
BenchmarkJavaSliceLong                    138391        8466          -93.88%
BenchmarkJavaSliceLongDirect              205804        15666         -92.39%
BenchmarkGoEmpty                          3.00          3.00          +0.00%
BenchmarkGoEmptyDirect                    3.00          3.00          +0.00%
BenchmarkGoNoarg                          40342         13716         -66.00%
BenchmarkGoNoargDirect                    46691         13569         -70.94%
BenchmarkGoOnearg                         43529         13757         -68.40%
BenchmarkGoOneargDirect                   44867         14078         -68.62%
BenchmarkGoOneret                         45456         13559         -70.17%
BenchmarkGoOneretDirect                   44694         13442         -69.92%
BenchmarkGoRefjava                        55111         28071         -49.06%
BenchmarkGoRefjavaDirect                  60883         26872         -55.86%
BenchmarkGoRefgo                          57038         29223         -48.77%
BenchmarkGoRefgoDirect                    56153         27812         -50.47%
BenchmarkGoManyargs                       67967         17398         -74.40%
BenchmarkGoManyargsDirect                 60617         16998         -71.96%
BenchmarkGoStringShort                    57538         22600         -60.72%
BenchmarkGoStringShortDirect              52627         22704         -56.86%
BenchmarkGoStringLong                     128485        52530         -59.12%
BenchmarkGoStringLongDirect               138377        52079         -62.36%
BenchmarkGoStringShortUnicode             57062         22994         -59.70%
BenchmarkGoStringShortUnicodeDirect       62563         22938         -63.34%
BenchmarkGoStringLongUnicode              139913        55553         -60.29%
BenchmarkGoStringLongUnicodeDirect        150863        57791         -61.69%
BenchmarkGoSliceShort                     59279         20215         -65.90%
BenchmarkGoSliceShortDirect               60160         21136         -64.87%
BenchmarkGoSliceLong                      411225        301870        -26.59%
BenchmarkGoSliceLongDirect                399029        298915        -25.09%

Fixes golang/go#12619
Fixes golang/go#12113
Fixes golang/go#13033

Change-Id: I2b45e9e98a1248e3c23a5137f775f7364908bec7
Reviewed-on: https://go-review.googlesource.com/19821
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
2016-03-03 15:03:45 +00:00

113 lines
2.4 KiB
Go

// 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
//#cgo LDFLAGS: -llog
//#include <android/log.h>
//#include <string.h>
//import "C"
import (
"fmt"
"runtime"
"sync"
)
type countedObj struct {
obj interface{}
cnt int32
}
// 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 {
sync.Mutex
next int32 // next reference number to use for Go object, always negative
refs map[interface{}]int32
objs map[int32]countedObj
}
func init() {
refs.Lock()
refs.next = -24 // Go objects get negative reference numbers. Arbitrary starting point.
refs.refs = make(map[interface{}]int32)
refs.objs = make(map[int32]countedObj)
refs.Unlock()
}
// A Ref represents a Java or Go object passed across the language
// boundary.
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()
o, ok := refs.objs[r.Num]
refs.Unlock()
if !ok {
panic(fmt.Sprintf("unknown ref %d", r.Num))
}
return o.obj
}
// Delete decrements the reference count and removes the pinned object
// from the object map when the reference count becomes zero.
func Delete(num int32) {
refs.Lock()
defer refs.Unlock()
o, ok := refs.objs[num]
if !ok {
panic(fmt.Sprintf("seq.Delete unknown refnum: %d", num))
}
if o.cnt <= 1 {
delete(refs.objs, num)
delete(refs.refs, o.obj)
} else {
refs.objs[num] = countedObj{o.obj, o.cnt - 1}
}
}