bind: do not generate unused Seq objects

Updates golang/go#12619

Change-Id: Ie851795580c82ade3ee70bdb3945b23ca72f57e0
Reviewed-on: https://go-review.googlesource.com/17866
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/bind/genjava.go b/bind/genjava.go
index 4ffccf2..30f031d 100644
--- a/bind/genjava.go
+++ b/bind/genjava.go
@@ -87,10 +87,9 @@
 		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("Seq out = 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, out);\n", f.Name())
+		g.Printf("Seq.send(DESCRIPTOR, FIELD_%s_SET, in, null);\n", f.Name())
 		g.Outdent()
 		g.Printf("}\n\n")
 	}
@@ -467,9 +466,8 @@
 	g.Printf("public static void set%s(%s v) {\n", o.Name(), jType)
 	g.Indent()
 	g.Printf("Seq in = new Seq();\n")
-	g.Printf("Seq out = new Seq();\n")
 	g.Printf("in.write%s;\n", seqWrite(o.Type(), "v"))
-	g.Printf("Seq.send(%q, 1, in, out);\n", varDesc)
+	g.Printf("Seq.send(%q, 1, in, null);\n", varDesc)
 	g.Outdent()
 	g.Printf("}\n")
 	g.Printf("\n")
@@ -477,9 +475,8 @@
 	// getter
 	g.Printf("public static %s get%s() {\n", jType, o.Name())
 	g.Indent()
-	g.Printf("Seq in = new Seq();\n")
 	g.Printf("Seq out = new Seq();\n")
-	g.Printf("Seq.send(%q, 2, in, out);\n", varDesc)
+	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")
@@ -498,8 +495,8 @@
 
 	g.Printf(" {\n")
 	g.Indent()
-	g.Printf("go.Seq _in = new go.Seq();\n")
-	g.Printf("go.Seq _out = new go.Seq();\n")
+	g.Printf("go.Seq _in = null;\n")
+	g.Printf("go.Seq _out = null;\n")
 
 	returnsError := false
 	var resultType types.Type
@@ -511,15 +508,21 @@
 			returnsError = true
 		}
 	}
+	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")
 	}
-	params := sig.Params()
 	for i := 0; i < params.Len(); i++ {
 		p := params.At(i)
 		g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i)))
diff --git a/bind/java/seq_android.c b/bind/java/seq_android.c
index 52f7901..8d28911 100644
--- a/bind/java/seq_android.c
+++ b/bind/java/seq_android.c
@@ -77,6 +77,9 @@
 }
 
 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);
@@ -400,13 +403,20 @@
 
 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) {
-		LOG_FATAL("send src is NULL");
+	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) {
-		LOG_FATAL("send dst is NULL");
+	if (dst != NULL) {
+		res = &dst->buf;
+		reslen = &dst->len;
 	}
 
 	GoString desc;
@@ -415,9 +425,13 @@
 		LOG_FATAL("send GetStringUTFChars failed");
 	}
 	desc.n = (*env)->GetStringUTFLength(env, descriptor);
-	Send(desc, (GoInt)code, src->buf, src->len, &dst->buf, &dst->len);
+
+	Send(desc, (GoInt)code, req, reqlen, res, reslen);
 	(*env)->ReleaseStringUTFChars(env, descriptor, desc.p);
-	unpin_arrays(env, src);  // assume 'src' is no longer needed.
+
+	if (src != NULL) {
+		unpin_arrays(env, src);  // assume 'src' is no longer needed.
+	}
 }
 
 JNIEXPORT void JNICALL
diff --git a/bind/java/seq_android.go b/bind/java/seq_android.go
index a3c4a8c..9498e38 100644
--- a/bind/java/seq_android.go
+++ b/bind/java/seq_android.go
@@ -31,18 +31,26 @@
 	if fn == nil {
 		panic(fmt.Sprintf("invalid descriptor(%s) and code(0x%x)", descriptor, code))
 	}
-	in := new(seq.Buffer)
-	if reqlen > 0 {
-		in.Data = (*[maxSliceLen]byte)(unsafe.Pointer(req))[:reqlen]
-	}
-	out := new(seq.Buffer)
-	fn(out, in)
-	// 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)
+	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.