Reduce number of codegen'd classes needed for Services

This reduces the number of classes defined, which reduces memory usage.
It also reduces the number of methods defined, which is important
because of the dex limit.

This should have virtually zero performance degradation because the
contiguous switch uses tableswitch bytecode.
diff --git a/compiler/src/test/golden/TestServiceNano.java.txt b/compiler/src/test/golden/TestServiceNano.java.txt
index 7fd611f..f8c1ff3 100644
--- a/compiler/src/test/golden/TestServiceNano.java.txt
+++ b/compiler/src/test/golden/TestServiceNano.java.txt
@@ -300,70 +300,98 @@
     }
   }
 
+  private static final int METHODID_UNARY_CALL = 0;
+  private static final int METHODID_STREAMING_OUTPUT_CALL = 1;
+  private static final int METHODID_STREAMING_INPUT_CALL = 2;
+  private static final int METHODID_FULL_BIDI_CALL = 3;
+  private static final int METHODID_HALF_BIDI_CALL = 4;
+
+  private static class MethodHandlers<Req, Resp> implements
+      io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+      io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+    private final TestService serviceImpl;
+    private final int methodId;
+
+    public MethodHandlers(TestService serviceImpl, int methodId) {
+      this.serviceImpl = serviceImpl;
+      this.methodId = methodId;
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_UNARY_CALL:
+          serviceImpl.unaryCall((io.grpc.testing.integration.nano.Test.SimpleRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.SimpleResponse>) responseObserver);
+          break;
+        case METHODID_STREAMING_OUTPUT_CALL:
+          serviceImpl.streamingOutputCall((io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest) request,
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+          break;
+        default:
+          throw new AssertionError();
+      }
+    }
+
+    @java.lang.SuppressWarnings("unchecked")
+    public io.grpc.stub.StreamObserver<Req> invoke(
+        io.grpc.stub.StreamObserver<Resp> responseObserver) {
+      switch (methodId) {
+        case METHODID_STREAMING_INPUT_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.streamingInputCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>) responseObserver);
+        case METHODID_FULL_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.fullBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+        case METHODID_HALF_BIDI_CALL:
+          return (io.grpc.stub.StreamObserver<Req>) serviceImpl.halfBidiCall(
+              (io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>) responseObserver);
+        default:
+          throw new AssertionError();
+      }
+    }
+  }
+
   public static io.grpc.ServerServiceDefinition bindService(
       final TestService serviceImpl) {
     return io.grpc.ServerServiceDefinition.builder(SERVICE_NAME)
-      .addMethod(
-        METHOD_UNARY_CALL,
-        asyncUnaryCall(
-          new io.grpc.stub.ServerCalls.UnaryMethod<
+        .addMethod(
+          METHOD_UNARY_CALL,
+          asyncUnaryCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.SimpleRequest,
-              io.grpc.testing.integration.nano.Test.SimpleResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.nano.Test.SimpleRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.SimpleResponse> responseObserver) {
-              serviceImpl.unaryCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_OUTPUT_CALL,
-        asyncServerStreamingCall(
-          new io.grpc.stub.ServerCalls.ServerStreamingMethod<
+              io.grpc.testing.integration.nano.Test.SimpleResponse>(
+                serviceImpl, METHODID_UNARY_CALL)))
+        .addMethod(
+          METHOD_STREAMING_OUTPUT_CALL,
+          asyncServerStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public void invoke(
-                io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest request,
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              serviceImpl.streamingOutputCall(request, responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_STREAMING_INPUT_CALL,
-        asyncClientStreamingCall(
-          new io.grpc.stub.ServerCalls.ClientStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_STREAMING_OUTPUT_CALL)))
+        .addMethod(
+          METHOD_STREAMING_INPUT_CALL,
+          asyncClientStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingInputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingInputCallResponse> responseObserver) {
-              return serviceImpl.streamingInputCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_FULL_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingInputCallResponse>(
+                serviceImpl, METHODID_STREAMING_INPUT_CALL)))
+        .addMethod(
+          METHOD_FULL_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.fullBidiCall(responseObserver);
-            }
-          }))
-      .addMethod(
-        METHOD_HALF_BIDI_CALL,
-        asyncBidiStreamingCall(
-          new io.grpc.stub.ServerCalls.BidiStreamingMethod<
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_FULL_BIDI_CALL)))
+        .addMethod(
+          METHOD_HALF_BIDI_CALL,
+          asyncBidiStreamingCall(
+            new MethodHandlers<
               io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest,
-              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>() {
-            @java.lang.Override
-            public io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallRequest> invoke(
-                io.grpc.stub.StreamObserver<io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse> responseObserver) {
-              return serviceImpl.halfBidiCall(responseObserver);
-            }
-          })).build();
+              io.grpc.testing.integration.nano.Test.StreamingOutputCallResponse>(
+                serviceImpl, METHODID_HALF_BIDI_CALL)))
+        .build();
   }
 }