go.mobile/bind/java: tests of object reference tracking
LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/112700044
This commit is contained in:
Родитель
6a88edec71
Коммит
5487fc8103
|
@ -0,0 +1,64 @@
|
|||
package go;
|
||||
|
||||
import go.testpkg.Testpkg;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SeqTest extends TestCase {
|
||||
static {
|
||||
Go.init(null);
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
long res = Testpkg.instance.Add(3, 4);
|
||||
assertEquals("Unexpected arithmetic failure", 7, res);
|
||||
}
|
||||
|
||||
public void testGoRefGC() {
|
||||
Testpkg.S s = Testpkg.instance.New();
|
||||
System.gc();
|
||||
Testpkg.instance.GC();
|
||||
long collected = Testpkg.instance.NumSCollected();
|
||||
assertEquals("Only S should be pinned", 0, collected);
|
||||
|
||||
s = null;
|
||||
System.gc();
|
||||
Testpkg.instance.GC();
|
||||
collected = Testpkg.instance.NumSCollected();
|
||||
assertEquals("S should be collected", 1, collected);
|
||||
}
|
||||
|
||||
boolean finalizedAnI;
|
||||
|
||||
private class AnI extends Testpkg.I.Stub {
|
||||
boolean called;
|
||||
public void F() {
|
||||
called = true;
|
||||
}
|
||||
@Override
|
||||
public void finalize() throws Throwable {
|
||||
finalizedAnI = true;
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
public void testJavaRefGC() {
|
||||
finalizedAnI = false;
|
||||
AnI obj = new AnI();
|
||||
Testpkg.instance.Call(obj);
|
||||
assertTrue("want F to be called", obj.called);
|
||||
obj = null;
|
||||
Testpkg.instance.GC();
|
||||
System.gc();
|
||||
assertTrue("want obj to be collected", finalizedAnI);
|
||||
}
|
||||
|
||||
public void testJavaRefKeep() {
|
||||
finalizedAnI = false;
|
||||
AnI obj = new AnI();
|
||||
Testpkg.instance.Keep(obj);
|
||||
obj = null;
|
||||
System.gc();
|
||||
assertFalse("want obj to be kept live by Go", finalizedAnI);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// 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.
|
||||
|
||||
//+build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.mobile/app"
|
||||
|
||||
_ "code.google.com/p/go.mobile/bind/java/testpkg/go_testpkg"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app.Run()
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# 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.
|
||||
|
||||
# TODO(crawshaw):
|
||||
# This script does not yet run the tests, it just sets them
|
||||
# up so they can be run by Android Studio.
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -f test.bash ]; then
|
||||
echo 'test.bash must be run from $GOPATH/src/code.google.com/p/go.mobile/bind/java'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$ANDROID_APP" ]; then
|
||||
echo 'ERROR: Environment variable ANDROID_APP is unset.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $ANDROID_APP/src/main/jniLibs/armeabi \
|
||||
$ANDROID_APP/src/main/java/go/testpkg
|
||||
ln -sf $PWD/*.java $ANDROID_APP/src/main/java/go
|
||||
ln -sf $PWD/testpkg/Testpkg.java $ANDROID_APP/src/main/java/go/testpkg
|
||||
CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 \
|
||||
go build -ldflags="-shared" javatest.go
|
||||
mv -f javatest $ANDROID_APP/src/main/jniLibs/armeabi/libgojni.so
|
|
@ -0,0 +1,160 @@
|
|||
// Java Package testpkg is a proxy for talking to a Go program.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
// Or do, I'm a comment, not a cop.
|
||||
package go.testpkg;
|
||||
|
||||
import go.Seq;
|
||||
|
||||
public final class Testpkg {
|
||||
public long Add(long x, long y) {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
long _result;
|
||||
_in.writeInt(x);
|
||||
_in.writeInt(y);
|
||||
Seq.send(DESCRIPTOR, CALL_Add, _in, _out);
|
||||
_result = _out.readInt();
|
||||
return _result;
|
||||
}
|
||||
|
||||
public void Call(I i) {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
_in.writeRef(i.ref());
|
||||
Seq.send(DESCRIPTOR, CALL_Call, _in, _out);
|
||||
}
|
||||
|
||||
public void GC() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
Seq.send(DESCRIPTOR, CALL_GC, _in, _out);
|
||||
}
|
||||
|
||||
public interface I extends go.Seq.Object {
|
||||
public void F();
|
||||
|
||||
public static abstract class Stub implements I {
|
||||
static final String DESCRIPTOR = "go.testpkg.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_F: {
|
||||
// TODO(crawshaw): handle catching a Exception
|
||||
this.F();
|
||||
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 F() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
Seq.send(DESCRIPTOR, CALL_F, _in, _out);
|
||||
}
|
||||
|
||||
static final int CALL_F = 0x0a01;
|
||||
}
|
||||
}
|
||||
|
||||
public void Keep(I i) {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
_in.writeRef(i.ref());
|
||||
Seq.send(DESCRIPTOR, CALL_Keep, _in, _out);
|
||||
}
|
||||
|
||||
public S New() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
S _result;
|
||||
Seq.send(DESCRIPTOR, CALL_New, _in, _out);
|
||||
_result = new S(_out.readRef());
|
||||
return _result;
|
||||
}
|
||||
|
||||
public long NumSCollected() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
long _result;
|
||||
Seq.send(DESCRIPTOR, CALL_NumSCollected, _in, _out);
|
||||
_result = _out.readInt();
|
||||
return _result;
|
||||
}
|
||||
|
||||
public static final class S implements go.Seq.Object {
|
||||
private static final String DESCRIPTOR = "go.testpkg.S";
|
||||
private static final int CALL_F = 0x0c00;
|
||||
|
||||
private 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("cycle: cannot call concrete proxy");
|
||||
}
|
||||
|
||||
|
||||
public void F() {
|
||||
go.Seq _in = new go.Seq();
|
||||
go.Seq _out = new go.Seq();
|
||||
_in.writeRef(ref);
|
||||
Seq.send(DESCRIPTOR, CALL_F, _in, _out);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof S)) {
|
||||
return false;
|
||||
}
|
||||
S that = (S)o;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return java.util.Arrays.hashCode(new Object[] {});
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
// TODO(crawshaw): use String() string if it is defined.
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("S").append("{");
|
||||
return b.append("}").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final int CALL_Add = 1;
|
||||
private static final int CALL_Call = 2;
|
||||
private static final int CALL_GC = 3;
|
||||
private static final int CALL_Keep = 4;
|
||||
private static final int CALL_New = 5;
|
||||
private static final int CALL_NumSCollected = 6;
|
||||
private static final String DESCRIPTOR = "testpkg";
|
||||
|
||||
public static Testpkg instance = new Testpkg();
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
// Package go_testpkg is an autogenerated binder stub for package testpkg.
|
||||
//
|
||||
// File is generated by gobind. Do not edit.
|
||||
// Or do, I'm a comment, not a cop.
|
||||
package go_testpkg
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.mobile/bind/java/testpkg"
|
||||
"code.google.com/p/go.mobile/bind/seq"
|
||||
)
|
||||
|
||||
func proxy_Add(out, in *seq.Buffer) {
|
||||
param_x := in.ReadInt()
|
||||
param_y := in.ReadInt()
|
||||
res := testpkg.Add(param_x, param_y)
|
||||
// TODO out.WriteNoException();
|
||||
out.WriteInt(res)
|
||||
}
|
||||
|
||||
func proxy_Call(out, in *seq.Buffer) {
|
||||
var param_i testpkg.I
|
||||
param_i_ref := in.ReadRef()
|
||||
if param_i_ref.Num < 0 {
|
||||
param_i = param_i_ref.Get().(testpkg.I)
|
||||
} else {
|
||||
param_i = (*proxyI)(param_i_ref)
|
||||
}
|
||||
testpkg.Call(param_i)
|
||||
// TODO out.WriteNoException();
|
||||
}
|
||||
|
||||
func proxy_GC(out, in *seq.Buffer) {
|
||||
testpkg.GC()
|
||||
// TODO out.WriteNoException();
|
||||
}
|
||||
|
||||
const (
|
||||
proxyIDescriptor = "go.testpkg.I"
|
||||
proxyIFCode = 0x0a01
|
||||
)
|
||||
|
||||
type proxyI seq.Ref
|
||||
|
||||
func (p *proxyI) F() {
|
||||
out := new(seq.Buffer)
|
||||
//out.WriteRef((*seq.Ref)(p))
|
||||
seq.Transact((*seq.Ref)(p), proxyIFCode, out)
|
||||
}
|
||||
|
||||
func proxy_Keep(out, in *seq.Buffer) {
|
||||
var param_i testpkg.I
|
||||
param_i_ref := in.ReadRef()
|
||||
if param_i_ref.Num < 0 {
|
||||
param_i = param_i_ref.Get().(testpkg.I)
|
||||
} else {
|
||||
param_i = (*proxyI)(param_i_ref)
|
||||
}
|
||||
testpkg.Keep(param_i)
|
||||
// TODO out.WriteNoException();
|
||||
}
|
||||
|
||||
func proxy_New(out, in *seq.Buffer) {
|
||||
res := testpkg.New()
|
||||
// TODO out.WriteNoException();
|
||||
out.WriteGoRef(res)
|
||||
}
|
||||
|
||||
func proxy_NumSCollected(out, in *seq.Buffer) {
|
||||
res := testpkg.NumSCollected()
|
||||
// TODO out.WriteNoException();
|
||||
out.WriteInt(res)
|
||||
}
|
||||
|
||||
const (
|
||||
proxySDescriptor = "go.testpkg.S"
|
||||
proxySFCode = 0x0c00
|
||||
)
|
||||
|
||||
type proxyS seq.Ref
|
||||
|
||||
func proxySF(out, in *seq.Buffer) {
|
||||
ref := in.ReadRef()
|
||||
v := ref.Get().(*testpkg.S)
|
||||
v.F()
|
||||
// TODO out.WriteNoException();
|
||||
}
|
||||
|
||||
func init() {
|
||||
seq.Register(proxySDescriptor, proxySFCode, proxySF)
|
||||
}
|
||||
|
||||
func init() {
|
||||
seq.Register("testpkg", 1, proxy_Add)
|
||||
seq.Register("testpkg", 2, proxy_Call)
|
||||
seq.Register("testpkg", 3, proxy_GC)
|
||||
seq.Register("testpkg", 4, proxy_Keep)
|
||||
seq.Register("testpkg", 5, proxy_New)
|
||||
seq.Register("testpkg", 6, proxy_NumSCollected)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// Package testpkg contains bound functions for testing the cgo-JNI interface.
|
||||
package testpkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type I interface {
|
||||
F()
|
||||
}
|
||||
|
||||
func Call(i I) {
|
||||
i.F()
|
||||
}
|
||||
|
||||
var keep []I
|
||||
|
||||
func Keep(i I) {
|
||||
keep = append(keep, i)
|
||||
}
|
||||
|
||||
var numSCollected int
|
||||
|
||||
type S struct {
|
||||
// *S already has a finalizer, so we need another object
|
||||
// to count successful collections.
|
||||
innerObj *int
|
||||
}
|
||||
|
||||
func (*S) F() {
|
||||
fmt.Println("called F on *S")
|
||||
}
|
||||
|
||||
func finalizeInner(*int) {
|
||||
numSCollected++
|
||||
}
|
||||
|
||||
func New() *S {
|
||||
s := &S{innerObj: new(int)}
|
||||
runtime.SetFinalizer(s.innerObj, finalizeInner)
|
||||
return s
|
||||
}
|
||||
|
||||
func GC() {
|
||||
runtime.GC()
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
func Add(x, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
func NumSCollected() int {
|
||||
return numSCollected
|
||||
}
|
Загрузка…
Ссылка в новой задаче