2
0
mirror of synced 2025-02-24 15:28:28 +00:00
mobile/bind/seq/ref.go

151 lines
3.4 KiB
Go
Raw Normal View History

// 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"
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-02-12 18:50:33 +01:00
"runtime"
"sync"
)
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
type countedObj struct {
obj interface{}
cnt int32
}
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-02-12 18:50:33 +01:00
// 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
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
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)
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
refs.objs = make(map[int32]countedObj)
refs.Unlock()
}
// A Ref represents a Java or Go object passed across the language
// boundary.
type Ref struct {
Bind_Num int32
}
type proxy interface {
// Use a strange name and hope that user code does not implement it
Bind_proxy_refnum__() int32
}
// ToRefNum increments the reference count for an object and
// returns its refnum.
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-02-12 18:50:33 +01:00
func ToRefNum(obj interface{}) int32 {
// We don't track foreign objects, so if obj is a proxy
// return its refnum.
if r, ok := obj.(proxy); ok {
refnum := r.Bind_proxy_refnum__()
if refnum <= 0 {
panic(fmt.Errorf("seq: proxy contained invalid Go refnum: %d", refnum))
}
return refnum
}
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-02-12 18:50:33 +01:00
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 num > 0 {
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-02-12 18:50:33 +01:00
// This is a foreign object reference.
// Track its lifetime with a finalizer.
runtime.SetFinalizer(ref, FinalizeRef)
}
return ref
}
// Bind_IncNum increments the foreign reference count and
// return the refnum.
func (r *Ref) Bind_IncNum() int32 {
refnum := r.Bind_Num
IncForeignRef(refnum)
return refnum
}
// Get returns the underlying object.
func (r *Ref) Get() interface{} {
refnum := r.Bind_Num
refs.Lock()
o, ok := refs.objs[refnum]
refs.Unlock()
if !ok {
panic(fmt.Sprintf("unknown ref %d", refnum))
}
// This is a Go reference and its refnum was incremented
// before crossing the language barrier.
Delete(refnum)
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
return o.obj
}
// Inc increments the reference count for a refnum. Called from Bind_proxy_refnum
// functions.
func Inc(num int32) {
refs.Lock()
o, ok := refs.objs[num]
if !ok {
panic(fmt.Sprintf("seq.Inc: unknown refnum: %d", num))
}
refs.objs[num] = countedObj{o.obj, o.cnt + 1}
refs.Unlock()
}
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
// 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()
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
defer refs.Unlock()
o, ok := refs.objs[num]
if !ok {
panic(fmt.Sprintf("seq.Delete unknown refnum: %d", num))
}
bind/java: manage Java object lifetime based on reference count. The gobind framework is supposed to use reference counting to keep track of objects (e.g. pointer to a Go struct, interface values) crossing the language boundary. This change fixes two bugs: 1) no reference counting on Java object: Previously, the lifetime of a Java object was manages in the following way. a. The Java object is pinned in an internal map (javaObjs) when it's constructed. b. When Go receives the reference to the Java object, it creates a proxy object and sets a finalizer on it. The finalizer signals Java to unpin the Java object (remove from the javaObjs map). c. The javaObjs map is also used to identify the Java object when Go asks to invoke a method on it later. When the same Java object is sent to Java more than once, and the finalizer (b) runs after the first use, the second use of the Java object can cause the crash described in golang/go#10933. This change fixes the bug by reference counting the Java object. Java side pins the Java object and increments the refcount whenever it sees the object sent to Go (in Seq.writeRef). When the Go proxy object's finalizer runs, the refcount is decremented. When the refcount becomes 0, the object gets unpined. 2) race in Go object lifetime management: Pinning on a Go object has been done when the Go object is sent to Java but the Go object is not in the pinned object map yet. (bind/seq.WriteGoRef). Unpinning the object occurs when Java finds there are no proxy objects on its side. For this, Java maintains a reference count map (goObjs). When the refcount becomes zero, Java notifies Go so the object is unpinned. Here is a race case: a. Java has a proxy object for a Go object. b. Go is preparing for sending the same Go object. seq.WriteGoRef notices the corresponding entry in the pinned object map already, and returns. The remaining work for sending the object continues. c. The proxy object in Java finalizes and triggers deletion of the object from the pinned object map. d. The remaining work for (b) completes and Java creates a new proxy object. When a method is called for the Go object, the Go object is already removed from the object map on Go side and maybe already GC'd. This change fixes it by converting the pinned object map to reference counter map maintained in Go. The counter increments for each seq.WriteGoRef call. The finalizer of the proxy object in Java causes a decrement of the counter. Fixes golang/go#10933. Renables the skipped testJavaRefGC. Change-Id: I0992e002b1050b6183689e5ab821e058adbb420f Reviewed-on: https://go-review.googlesource.com/10638 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-06-03 06:12:57 -04:00
if o.cnt <= 1 {
delete(refs.objs, num)
delete(refs.refs, o.obj)
} else {
refs.objs[num] = countedObj{o.obj, o.cnt - 1}
}
}