Seq.java 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package go;
  2. import android.util.Log;
  3. import android.util.SparseArray;
  4. import android.util.SparseIntArray;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. // Seq is a sequence of machine-dependent encoded values.
  8. // Used by automatically generated language bindings to talk to Go.
  9. public class Seq {
  10. @SuppressWarnings("UnusedDeclaration")
  11. private long memptr; // holds C-allocated pointer
  12. public Seq() {
  13. ensure(64);
  14. }
  15. // Ensure that at least size bytes can be written to the Seq.
  16. // Any existing data in the buffer is preserved.
  17. public native void ensure(int size);
  18. // Moves the internal buffer offset back to zero.
  19. // Length and contents are maintained. Data can be read after a reset.
  20. public native void resetOffset();
  21. public native void log(String label);
  22. public native byte readInt8();
  23. public native short readInt16();
  24. public native int readInt32();
  25. public native long readInt64();
  26. public long readInt() { return readInt64(); }
  27. public native float readFloat32();
  28. public native double readFloat64();
  29. public native String readUTF16();
  30. public native byte[] readByteArray();
  31. public native void writeInt8(byte v);
  32. public native void writeInt16(short v);
  33. public native void writeInt32(int v);
  34. public native void writeInt64(long v);
  35. public void writeInt(long v) { writeInt64(v); }
  36. public native void writeFloat32(float v);
  37. public native void writeFloat64(double v);
  38. public native void writeUTF16(String v);
  39. public native void writeByteArray(byte[] v);
  40. public void writeRef(Ref ref) {
  41. writeInt32(ref.refnum);
  42. }
  43. public Ref readRef() {
  44. int refnum = readInt32();
  45. return tracker.get(refnum);
  46. }
  47. // Informs the Go ref tracker that Java is done with this ref.
  48. static native void destroyRef(int refnum);
  49. // createRef creates a Ref to a Java object.
  50. public static Ref createRef(Seq.Object o) {
  51. return tracker.createRef(o);
  52. }
  53. // sends a function invocation request to Go.
  54. //
  55. // Blocks until the function completes.
  56. // If the request is for a method, the first element in src is
  57. // a Ref to the receiver.
  58. public static native void send(String descriptor, int code, Seq src, Seq dst);
  59. // recv returns the next request from Go for a Java call.
  60. static native void recv(Seq in, Receive params);
  61. // recvRes sends the result of a Java call back to Go.
  62. static native void recvRes(int handle, Seq out);
  63. static final class Receive {
  64. int refnum;
  65. int code;
  66. int handle;
  67. }
  68. protected void finalize() throws Throwable {
  69. super.finalize();
  70. free();
  71. }
  72. private native void free();
  73. private static final ExecutorService receivePool = Executors.newCachedThreadPool();
  74. // receive listens for callback requests from Go, invokes them on a thread
  75. // pool and sends the responses.
  76. public static void receive() {
  77. Seq.Receive params = new Seq.Receive();
  78. while (true) {
  79. final Seq in = new Seq();
  80. Seq.recv(in, params);
  81. final int code = params.code;
  82. final int handle = params.handle;
  83. final int refnum = params.refnum;
  84. if (code == -1) {
  85. // Special signal from seq.FinalizeRef.
  86. tracker.dec(refnum);
  87. Seq out = new Seq();
  88. Seq.recvRes(handle, out);
  89. continue;
  90. }
  91. receivePool.execute(new Runnable() {
  92. public void run() {
  93. Ref r = tracker.get(refnum);
  94. Seq out = new Seq();
  95. r.obj.call(code, in, out);
  96. Seq.recvRes(handle, out);
  97. }
  98. });
  99. }
  100. }
  101. // An Object is a Java object that matches a Go object.
  102. // The implementation of the object may be in either Java or Go,
  103. // with a proxy instance in the other language passing calls
  104. // through to the other language.
  105. //
  106. // Don't implement an Object directly. Instead, look for the
  107. // generated abstract Stub.
  108. public interface Object {
  109. public Ref ref();
  110. public void call(int code, Seq in, Seq out);
  111. }
  112. // A Ref is an object tagged with an integer for passing back and
  113. // forth across the language boundary.
  114. //
  115. // A Ref may represent either an instance of a Java Object subclass,
  116. // or an instance of a Go object. The explicit allocation of a Ref
  117. // is used to pin Go object instances when they are passed to Java.
  118. // The Go Seq library maintains a reference to the instance in a map
  119. // keyed by the Ref number. When the JVM calls finalize, we ask Go
  120. // to clear the entry in the map.
  121. public static final class Ref {
  122. // ref < 0: Go object tracked by Java
  123. // ref > 0: Java object tracked by Go
  124. int refnum;
  125. public Seq.Object obj;
  126. private Ref(int refnum, Seq.Object o) {
  127. this.refnum = refnum;
  128. this.obj = o;
  129. tracker.inc(refnum);
  130. }
  131. @Override
  132. protected void finalize() throws Throwable {
  133. tracker.dec(refnum);
  134. super.finalize();
  135. }
  136. }
  137. static final RefTracker tracker = new RefTracker();
  138. static final class RefTracker {
  139. // Next Java object reference number.
  140. //
  141. // Reference numbers are positive for Java objects,
  142. // and start, arbitrarily at a different offset to Go
  143. // to make debugging by reading Seq hex a little easier.
  144. private int next = 42; // next Java object ref
  145. // TODO(crawshaw): We could cut down allocations for frequently
  146. // sent Go objects by maintaining a map to weak references. This
  147. // however, would require allocating two objects per reference
  148. // instead of one. It also introduces weak references, the bane
  149. // of any Java debugging session.
  150. //
  151. // When we have real code, examine the tradeoffs.
  152. // Number of active references to a Go object. refnum -> count
  153. private SparseIntArray goObjs = new SparseIntArray();
  154. // Java objects that have been passed to Go. refnum -> Ref
  155. // The Ref obj field is non-null.
  156. // This map pins Java objects so they don't get GCed while the
  157. // only reference to them is held by Go code.
  158. private SparseArray<Ref> javaObjs = new SparseArray<Ref>();
  159. // inc increments the reference count to a Go object.
  160. synchronized void inc(int refnum) {
  161. if (refnum > 0) {
  162. return; // we don't count java objects
  163. }
  164. int count = goObjs.get(refnum);
  165. if (count == Integer.MAX_VALUE) {
  166. throw new RuntimeException("refnum " + refnum + " overflow");
  167. }
  168. goObjs.put(refnum, count+1);
  169. }
  170. // dec decrements the reference count to a Go object.
  171. // If the count reaches zero, the Go reference tracker is informed.
  172. synchronized void dec(int refnum) {
  173. if (refnum > 0) {
  174. // Java objects are removed on request of Go.
  175. javaObjs.remove(refnum);
  176. return;
  177. }
  178. int count = goObjs.get(refnum);
  179. if (count == 0) {
  180. throw new RuntimeException("refnum " + refnum + " underflow");
  181. }
  182. count--;
  183. if (count <= 0) {
  184. goObjs.delete(refnum);
  185. Seq.destroyRef(refnum);
  186. } else {
  187. goObjs.put(refnum, count);
  188. }
  189. }
  190. synchronized Ref createRef(Seq.Object o) {
  191. // TODO(crawshaw): use single Ref for null.
  192. if (next == Integer.MAX_VALUE) {
  193. throw new RuntimeException("createRef overflow for " + o);
  194. }
  195. int refnum = next++;
  196. Ref ref = new Ref(refnum, o);
  197. javaObjs.put(refnum, ref);
  198. return ref;
  199. }
  200. // get returns an existing Ref to either a Java or Go object.
  201. // It may be the first time we have seen the Go object.
  202. synchronized Ref get(int refnum) {
  203. if (refnum > 0) {
  204. Ref ref = javaObjs.get(refnum);
  205. if (ref == null) {
  206. throw new RuntimeException("unknown java Ref: "+refnum);
  207. }
  208. return ref;
  209. }
  210. return new Ref(refnum, null);
  211. }
  212. }
  213. }