Merge pull request #7514 from apolcyn/move_tools_dep_to_project

moved Grpc.Tools dependency from solution level to project level
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c60531..2f498c08 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,7 +42,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.0.0-pre1")
+set(PACKAGE_VERSION   "1.0.0-pre2")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
diff --git a/INSTALL.md b/INSTALL.md
index 6718aad..7bdb9b2 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -55,3 +55,55 @@
  $ make
  $ [sudo] make install
 ```
+
+##Windows
+
+There are several ways to build under Windows, of varying complexity depending
+on experience with the tools involved.
+
+<!--
+###Visual Studio
+
+Versions 2013 and 2015 are both supported. You can use [their respective
+community
+editions](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx).
+
+Building the C Core:
+- Open [grpc.sln](https://github.com/grpc/grpc/blob/master/vsprojects/grpc.sln).
+- Select your build target.
+- Build the `grpc` project.
+
+Building the C++ runtime:
+- You need [CMake](https://cmake.org/) on your path to build protobuf (see below
+  for building using solely CMake).
+- Run `vsprojects/build_protos.bat` (needs `cmake.exe` in your path).
+- Open [buildtests_cxx.sln]()
+- Select your build target.
+- build the `grpc++` project.
+-->
+
+###msys2
+
+This approach requires having [msys2](https://msys2.github.io/) installed.
+
+- The Makefile (and source code) should support msys2's mingw32 and mingw64
+  compilers. Building with msys2's native compiler is also possible, but
+  difficult.
+- The Makefile is expecting the Windows versions of OpenSSL (see
+  https://slproweb.com/products/Win32OpenSSL.html). It's also possible to build
+  the Windows version of OpenSSL from scratch. The output should be `libeay32`
+  and `ssleay32`.
+- If you are not installing the above files under msys2's path, you may specify
+  it, for instance, in the following way:
+  ```CPPFLAGS=”-I/c/OpenSSL-Win32/include” LDFLAGS=”-L/c/OpenSSL-Win32/lib” make static_c```
+- [protobuf3](https://github.com/google/protobuf/blob/master/src/README.md#c-installation---windows)
+  must be installed on the msys2 path.
+
+###Cmake (experimental)
+
+- Install [CMake](https://cmake.org/download/).
+- Run it over [grpc's
+  CMakeLists.txt](https://github.com/grpc/grpc/blob/master/CMakeLists.txt) to
+  generate "projects" for your compiler.
+- Build with your compiler of choice. The generated build files should have the
+  protobuf3 dependency baked in.
diff --git a/Makefile b/Makefile
index ed362f9..ad2ff32 100644
--- a/Makefile
+++ b/Makefile
@@ -415,7 +415,7 @@
 Q = @
 endif
 
-VERSION = 1.0.0-pre1
+VERSION = 1.0.0-pre2
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
diff --git a/build.yaml b/build.yaml
index 006d352..c474f66 100644
--- a/build.yaml
+++ b/build.yaml
@@ -7,7 +7,7 @@
   '#3': Use "-preN" suffixes to identify pre-release versions
   '#4': Per-language overrides are possible with (eg) ruby_version tag here
   '#5': See the expand_version.py for all the quirks here
-  version: 1.0.0-pre1
+  version: 1.0.0-pre2
 filegroups:
 - name: census
   public_headers:
@@ -3353,6 +3353,7 @@
   - src/php/ext/grpc/channel.h
   - src/php/ext/grpc/channel_credentials.h
   - src/php/ext/grpc/completion_queue.h
+  - src/php/ext/grpc/php7_wrapper.h
   - src/php/ext/grpc/php_grpc.h
   - src/php/ext/grpc/server.h
   - src/php/ext/grpc/server_credentials.h
diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
index 86909d8..ff22507 100644
--- a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
+++ b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
@@ -2,9 +2,39 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+	<key>AD_UNIT_ID_FOR_BANNER_TEST</key>
+	<string>redacted</string>
+	<key>AD_UNIT_ID_FOR_INTERSTITIAL_TEST</key>
+	<string>redacted</string>
 	<key>CLIENT_ID</key>
 	<string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
 	<key>REVERSED_CLIENT_ID</key>
 	<string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+	<key>API_KEY</key>
+	<string>redacted</string>
+	<key>GCM_SENDER_ID</key>
+	<string>redacted</string>
+	<key>PLIST_VERSION</key>
+	<string>1</string>
+	<key>BUNDLE_ID</key>
+	<string>io.grpc.AuthSample</string>
+	<key>PROJECT_ID</key>
+	<string>grpc-authsample</string>
+	<key>STORAGE_BUCKET</key>
+	<string>grpc-authsample.appspot.com</string>
+	<key>IS_ADS_ENABLED</key>
+	<false/>
+	<key>IS_ANALYTICS_ENABLED</key>
+	<false/>
+	<key>IS_APPINVITE_ENABLED</key>
+	<false/>
+	<key>IS_GCM_ENABLED</key>
+	<false/>
+	<key>IS_SIGNIN_ENABLED</key>
+	<true/>
+	<key>GOOGLE_APP_ID</key>
+	<string>1:15087385131:ios:d547168abe3c362f</string>
+	<key>DATABASE_URL</key>
+	<string>https://grpc-authsample.firebaseio.com</string>
 </dict>
-</plist>
\ No newline at end of file
+</plist>
diff --git a/examples/php/composer.json b/examples/php/composer.json
index a8b790b..d40b5db 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -3,6 +3,6 @@
   "description": "gRPC example for PHP",
   "minimum-stability": "dev",
   "require": {
-    "grpc/grpc": "v0.15.0"
+    "grpc/grpc": "v0.15.2"
   }
 }
diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h
index e96d224..70533aa 100644
--- a/include/grpc++/impl/codegen/async_stream.h
+++ b/include/grpc++/impl/codegen/async_stream.h
@@ -330,6 +330,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -345,6 +348,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
@@ -363,6 +369,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@@ -400,6 +409,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -409,6 +421,9 @@
     if (!ctx_->sent_initial_metadata_) {
       write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        write_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
@@ -421,6 +436,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@@ -459,6 +477,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -474,6 +495,9 @@
     if (!ctx_->sent_initial_metadata_) {
       write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        write_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
@@ -486,6 +510,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index 47ac5be..544dace 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -126,6 +126,9 @@
     meta_buf_.set_output_tag(tag);
     meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_buf_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_buf_);
   }
@@ -135,6 +138,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
@@ -153,6 +159,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index fab85d1..dfac177 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -180,17 +180,23 @@
 
 class CallOpSendInitialMetadata {
  public:
-  CallOpSendInitialMetadata() : send_(false) {}
+  CallOpSendInitialMetadata() : send_(false) {
+    maybe_compression_level_.is_set = false;
+  }
 
   void SendInitialMetadata(
       const std::multimap<grpc::string, grpc::string>& metadata,
       uint32_t flags) {
+    maybe_compression_level_.is_set = false;
     send_ = true;
     flags_ = flags;
     initial_metadata_count_ = metadata.size();
     initial_metadata_ = FillMetadataArray(metadata);
-    // TODO(dgq): expose compression level in API so it can be properly set.
-    maybe_compression_level_.is_set = false;
+  }
+
+  void set_compression_level(grpc_compression_level level) {
+    maybe_compression_level_.is_set = true;
+    maybe_compression_level_.level = level;
   }
 
  protected:
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
index 21ac6c4..2f4be64 100644
--- a/include/grpc++/impl/codegen/method_handler_impl.h
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -65,6 +65,9 @@
         ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_,
                             param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
     if (status.ok()) {
       status = ops.SendMessage(rsp);
     }
@@ -104,6 +107,9 @@
         ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_,
                             param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
     if (status.ok()) {
       status = ops.SendMessage(rsp);
     }
@@ -144,6 +150,9 @@
     if (!param.server_context->sent_initial_metadata_) {
       ops.SendInitialMetadata(param.server_context->initial_metadata_,
                               param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
     }
     ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
     param.call->PerformOps(&ops);
@@ -177,6 +186,9 @@
     if (!param.server_context->sent_initial_metadata_) {
       ops.SendInitialMetadata(param.server_context->initial_metadata_,
                               param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
     }
     ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
     param.call->PerformOps(&ops);
@@ -199,6 +211,9 @@
     if (!context->sent_initial_metadata_) {
       ops->SendInitialMetadata(context->initial_metadata_,
                                context->initial_metadata_flags());
+      if (context->compression_level_set()) {
+        ops->set_compression_level(context->compression_level());
+      }
       context->sent_initial_metadata_ = true;
     }
     ops->ServerSendStatus(context->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index cea13a5..08212af 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -130,7 +130,13 @@
   grpc_compression_level compression_level() const {
     return compression_level_;
   }
-  void set_compression_level(grpc_compression_level level);
+
+  void set_compression_level(grpc_compression_level level) {
+    compression_level_set_ = true;
+    compression_level_ = level;
+  }
+
+  bool compression_level_set() const { return compression_level_set_; }
 
   grpc_compression_algorithm compression_algorithm() const {
     return compression_algorithm_;
@@ -217,6 +223,7 @@
   std::multimap<grpc::string, grpc::string> initial_metadata_;
   std::multimap<grpc::string, grpc::string> trailing_metadata_;
 
+  bool compression_level_set_;
   grpc_compression_level compression_level_;
   grpc_compression_algorithm compression_algorithm_;
 };
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index cbfa410..b2b9727 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -347,6 +347,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -375,6 +378,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -389,6 +395,9 @@
     if (!ctx_->sent_initial_metadata_) {
       ops.SendInitialMetadata(ctx_->initial_metadata_,
                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     call_->PerformOps(&ops);
@@ -413,6 +422,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -434,6 +446,9 @@
     if (!ctx_->sent_initial_metadata_) {
       ops.SendInitialMetadata(ctx_->initial_metadata_,
                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     call_->PerformOps(&ops);
diff --git a/package.json b/package.json
index 3541064..0a6a45f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
diff --git a/package.xml b/package.xml
index 58e7030..65764e8 100644
--- a/package.xml
+++ b/package.xml
@@ -10,7 +10,7 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2016-07-21</date>
+ <date>2016-07-28</date>
  <time>16:06:07</time>
  <version>
   <release>1.0.0</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-- PHP7 Support #7464
+- PHP7 Support continued, reduce code duplication #7543
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -46,6 +46,7 @@
     <file baseinstalldir="/" name="src/php/ext/grpc/channel.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/channel_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/completion_queue.h" role="src" />
+    <file baseinstalldir="/" name="src/php/ext/grpc/php7_wrapper.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/php_grpc.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/server.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
@@ -1115,5 +1116,20 @@
 - PHP7 Support #7464
    </notes>
   </release>
+  <release>
+   <version>
+    <release>1.0.0RC3</release>
+    <api>1.0.0RC3</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2016-07-28</date>
+   <license>BSD</license>
+   <notes>
+- PHP7 Support continued, reduce code duplication #7543
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/requirements.txt b/requirements.txt
index 0ec0e75..bf87de0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,6 +3,6 @@
 cython>=0.23
 enum34>=1.0.4
 futures>=2.2.0
-protobuf>=3.0.0a3
+protobuf>=3.0.0
 six>=1.10
-wheel>=0.29
\ No newline at end of file
+wheel>=0.29
diff --git a/setup.py b/setup.py
index b43ec9a..1dddf55 100644
--- a/setup.py
+++ b/setup.py
@@ -189,7 +189,7 @@
     'futures>=2.2.0',
     # TODO(atash): eventually split the grpcio package into a metapackage
     # depending on protobuf and the runtime component (independent of protobuf)
-    'protobuf>=3.0.0a3',
+    'protobuf>=3.0.0',
 )
 
 SETUP_REQUIRES = INSTALL_REQUIRES + (
diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h
index ff6939e..aa3c22f 100644
--- a/src/compiler/ruby_generator_helpers-inl.h
+++ b/src/compiler/ruby_generator_helpers-inl.h
@@ -48,7 +48,7 @@
       file->name().find_last_of(".proto") == file->name().size() - 1) {
     *file_name_or_error =
         file->name().substr(0, file->name().size() - proto_suffix_length) +
-        "_services.rb";
+        "_services_pb.rb";
     return true;
   } else {
     *file_name_or_error = "Invalid proto file name:  must end with .proto";
@@ -58,7 +58,7 @@
 
 inline grpc::string MessagesRequireName(
     const grpc::protobuf::FileDescriptor *file) {
-  return Replace(file->name(), ".proto", "");
+  return Replace(file->name(), ".proto", "_pb");
 }
 
 // Get leading or trailing comments in a string. Comment lines start with "# ".
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index f000536..dab7f54 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,4 +36,4 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "1.0.0-pre1"; }
+const char *grpc_version_string(void) { return "1.0.0-pre2"; }
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 43117fd..1ca6a2b 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -129,7 +129,8 @@
       deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
       call_(nullptr),
       cq_(nullptr),
-      sent_initial_metadata_(false) {}
+      sent_initial_metadata_(false),
+      compression_level_set_(false) {}
 
 ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
                              size_t metadata_count)
@@ -139,7 +140,8 @@
       deadline_(deadline),
       call_(nullptr),
       cq_(nullptr),
-      sent_initial_metadata_(false) {
+      sent_initial_metadata_(false),
+      compression_level_set_(false) {
   for (size_t i = 0; i < metadata_count; i++) {
     client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
         metadata[i].key,
@@ -194,15 +196,6 @@
   }
 }
 
-void ServerContext::set_compression_level(grpc_compression_level level) {
-  // TODO(dgq): get rid of grpc_call_compression_for_level and propagate the
-  // compression level by adding a new argument to
-  // CallOpSendInitialMetadata::SendInitialMetadata.
-  const grpc_compression_algorithm algorithm_for_level =
-      grpc_call_compression_for_level(call_, level);
-  set_compression_algorithm(algorithm_for_level);
-}
-
 void ServerContext::set_compression_algorithm(
     grpc_compression_algorithm algorithm) {
   char* algorithm_name = NULL;
diff --git a/src/csharp/.nuget/packages.config b/src/csharp/.nuget/packages.config
deleted file mode 100644
index 6154b35..0000000
--- a/src/csharp/.nuget/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="NUnit.ConsoleRunner" version="3.2.0" />
-  <package id="OpenCover" version="4.6.519" />
-  <package id="ReportGenerator" version="2.4.4.0" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
index 34a4e2f..6a1c9fc 100644
--- a/src/csharp/Grpc.Auth/project.json
+++ b/src/csharp/Grpc.Auth/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "title": "gRPC C# Auth",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
@@ -22,7 +22,7 @@
     }
   },
   "dependencies": {
-    "Grpc.Core": "1.0.0-pre1",
+    "Grpc.Core": "1.0.0-pre2",
     "Google.Apis.Auth": "1.11.1"
   },
   "frameworks": {
@@ -32,9 +32,9 @@
         "net45"
       ],
       "dependencies": {
-        "Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027",
-        "NETStandard.Library": "1.5.0-rc2-24027",
-        "System.Threading.Tasks": "4.0.11-rc2-24027"
+        "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
+        "NETStandard.Library": "1.6.0",
+        "System.Threading.Tasks": "4.0.11"
       }
     }
   }
diff --git a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
index 064bc13..d7ebdb4 100644
--- a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
+++ b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
@@ -40,7 +40,7 @@
 {
     public class AppDomainUnloadTest
     {
-#if NETSTANDARD1_5
+#if NETCOREAPP1_0
         [Test]
         [Ignore("Not supported for CoreCLR")]
         public void AppDomainUnloadHookCanCleanupAbandonedCall()
diff --git a/src/csharp/Grpc.Core.Tests/NUnitMain.cs b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
index 24a9f84..870c726 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if NETSTANDARD1_5
+#if NETCOREAPP1_0
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 501992c..19c7a0b 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -46,7 +46,7 @@
     public class SanityTest
     {
         // TODO: make sanity test work for CoreCLR as well
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
         /// <summary>
         /// Because we depend on a native library, sometimes when things go wrong, the
         /// entire NUnit test process crashes. To be able to track down problems better,
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index aa7d951..6a930c1 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -4,4 +4,7 @@
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
   <package id="NUnit" version="3.2.0" targetFramework="net45" />
   <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
-</packages>
\ No newline at end of file
+  <package id="NUnit.ConsoleRunner" version="3.2.0" />
+  <package id="OpenCover" version="4.6.519" />
+  <package id="ReportGenerator" version="2.4.4.0" />
+</packages>
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
index d4c9a2e..014e226 100644
--- a/src/csharp/Grpc.Core.Tests/project.json
+++ b/src/csharp/Grpc.Core.Tests/project.json
@@ -54,16 +54,20 @@
     },
     "Newtonsoft.Json": "8.0.3",
     "NUnit": "3.2.0",
-    "NUnitLite": "3.2.0-*"
+    "NUnitLite": "3.2.0-*",
+    "NUnit.ConsoleRunner": "3.2.0",
+    "OpenCover": "4.6.519",
+    "ReportGenerator": "2.4.4.0"
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   },
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index e9f5c63..37df7ff 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -53,6 +53,6 @@
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.0.0-pre1";
+        public const string CurrentVersion = "1.0.0-pre2";
     }
 }
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
index 7a676f5..1719184 100644
--- a/src/csharp/Grpc.Core/project.json
+++ b/src/csharp/Grpc.Core/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "title": "gRPC C# Core",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
@@ -40,8 +40,8 @@
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027",
-        "System.Threading.Thread": "4.0.0-rc2-24027"
+        "NETStandard.Library": "1.6.0",
+        "System.Threading.Thread": "4.0.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.Examples.MathClient/packages.config b/src/csharp/Grpc.Examples.MathClient/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
index 206d6c5..ad31947 100644
--- a/src/csharp/Grpc.Examples.MathClient/project.json
+++ b/src/csharp/Grpc.Examples.MathClient/project.json
@@ -55,12 +55,13 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.Examples.MathServer/packages.config b/src/csharp/Grpc.Examples.MathServer/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
index 206d6c5..ad31947 100644
--- a/src/csharp/Grpc.Examples.MathServer/project.json
+++ b/src/csharp/Grpc.Examples.MathServer/project.json
@@ -55,12 +55,13 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
index 1a522ca..7ba1074 100644
--- a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if NETSTANDARD1_5
+#if NETCOREAPP1_0
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Examples.Tests/project.json b/src/csharp/Grpc.Examples.Tests/project.json
index b4c4c5f..1cd1848 100644
--- a/src/csharp/Grpc.Examples.Tests/project.json
+++ b/src/csharp/Grpc.Examples.Tests/project.json
@@ -57,12 +57,13 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.Examples/project.json b/src/csharp/Grpc.Examples/project.json
index 7d3f4dc..48ec530 100644
--- a/src/csharp/Grpc.Examples/project.json
+++ b/src/csharp/Grpc.Examples/project.json
@@ -20,7 +20,7 @@
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
index 4463467..dca61e3 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if NETSTANDARD1_5
+#if NETCOREAPP1_0
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.HealthCheck.Tests/project.json b/src/csharp/Grpc.HealthCheck.Tests/project.json
index f44a322..faa4400 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/project.json
+++ b/src/csharp/Grpc.HealthCheck.Tests/project.json
@@ -57,12 +57,13 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
index 906dda3..aa7a6b6 100644
--- a/src/csharp/Grpc.HealthCheck/project.json
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "title": "gRPC C# Healthchecking",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
@@ -22,7 +22,7 @@
     }
   },
   "dependencies": {
-    "Grpc.Core": "1.0.0-pre1",
+    "Grpc.Core": "1.0.0-pre2",
     "Google.Protobuf": "3.0.0-beta3"
   },
   "frameworks": {
@@ -37,7 +37,7 @@
         "portable-net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/project.json b/src/csharp/Grpc.IntegrationTesting.Client/project.json
index 6b61a4b..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.Client/project.json
@@ -57,13 +57,14 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45",
         "net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config b/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
index 6b61a4b..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
@@ -57,13 +57,14 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45",
         "net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/project.json b/src/csharp/Grpc.IntegrationTesting.Server/project.json
index 6b61a4b..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.Server/project.json
@@ -57,13 +57,14 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45",
         "net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config b/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
index 6b61a4b..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
@@ -57,13 +57,14 @@
   },
   "frameworks": {
     "net45": { },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45",
         "net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0"
       }
     }
   }
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
index eb7b55a..c17ede7 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
@@ -49,7 +49,7 @@
         TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
 
         // TODO: replace Moq by some mocking library with CoreCLR support.
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
         [Test]
         public void ExpandedParamOverloadCanBeMocked()
         {
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index e27fe5b..ec407d3 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -145,7 +145,7 @@
 
             if (options.TestCase == "jwt_token_creds")
             {
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsTrue(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
@@ -157,7 +157,7 @@
 
             if (options.TestCase == "compute_engine_creds")
             {
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsFalse(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
@@ -395,7 +395,7 @@
 
         public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
         {
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
             Console.WriteLine("running oauth2_auth_token");
             ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
             string oauth2Token = await credential.GetAccessTokenForRequestAsync();
@@ -421,7 +421,7 @@
 
         public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
         {
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
             Console.WriteLine("running per_rpc_creds");
             ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
 
@@ -731,7 +731,7 @@
         // extracts the client_email field from service account file used for auth test cases
         private static string GetEmailFromServiceAccountFile()
         {
-#if !NETSTANDARD1_5
+#if !NETCOREAPP1_0
             string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
             Assert.IsNotNull(keyFile);
             var jobject = JObject.Parse(File.ReadAllText(keyFile));
diff --git a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
index 100ff0b..21c8adb 100644
--- a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
+++ b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
@@ -49,7 +49,7 @@
         {
             // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
             GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
-#if NETSTANDARD1_5
+#if NETCOREAPP1_0
             return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
 #else
             return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
index dcd9cca..bb61a67 100644
--- a/src/csharp/Grpc.IntegrationTesting/project.json
+++ b/src/csharp/Grpc.IntegrationTesting/project.json
@@ -72,14 +72,15 @@
         "System.IO": ""
       }
     },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45",
         "net45"
       ],
       "dependencies": {
-        "NETStandard.Library": "1.5.0-rc2-24027",
-        "System.Linq.Expressions": "4.0.11-rc2-24027"
+        "Microsoft.NETCore.App": "1.0.0",
+        "NETStandard.Library": "1.6.0",
+        "System.Linq.Expressions": "4.1.0"
       }
     }
   }
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index ffb70ad..1d40ef9 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -30,7 +30,7 @@
 @rem Builds gRPC NuGet packages
 
 @rem Current package versions
-set VERSION=1.0.0-pre1
+set VERSION=1.0.0-pre2
 set PROTOBUF_VERSION=3.0.0-beta3
 
 @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index 3c8f0c5..81fc552 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -68,6 +68,8 @@
 Nan::Callback *CallCredentials::constructor;
 Persistent<FunctionTemplate> CallCredentials::fun_tpl;
 
+static Callback *plugin_callback;
+
 CallCredentials::CallCredentials(grpc_call_credentials *credentials)
     : wrapped_credentials(credentials) {}
 
@@ -88,6 +90,11 @@
                Nan::New<FunctionTemplate>(CreateFromPlugin)).ToLocalChecked());
   Nan::Set(exports, Nan::New("CallCredentials").ToLocalChecked(), ctr);
   constructor = new Nan::Callback(ctr);
+
+  Local<FunctionTemplate> callback_tpl =
+      Nan::New<FunctionTemplate>(PluginCallback);
+  plugin_callback = new Callback(
+      Nan::GetFunction(callback_tpl).ToLocalChecked());
 }
 
 bool CallCredentials::HasInstance(Local<Value> val) {
@@ -195,23 +202,28 @@
     return Nan::ThrowTypeError(
         "The callback's third argument must be an object");
   }
+  if (!info[3]->IsObject()) {
+    return Nan::ThrowTypeError(
+        "The callback's fourth argument must be an object");
+  }
   shared_ptr<Resources> resources(new Resources);
   grpc_status_code code = static_cast<grpc_status_code>(
       Nan::To<uint32_t>(info[0]).FromJust());
   Utf8String details_utf8_str(info[1]);
   char *details = *details_utf8_str;
   grpc_metadata_array array;
+  Local<Object> callback_data = Nan::To<Object>(info[3]).ToLocalChecked();
   if (!CreateMetadataArray(Nan::To<Object>(info[2]).ToLocalChecked(),
                            &array, resources)){
     return Nan::ThrowError("Failed to parse metadata");
   }
   grpc_credentials_plugin_metadata_cb cb =
       reinterpret_cast<grpc_credentials_plugin_metadata_cb>(
-          Nan::Get(info.Callee(),
+          Nan::Get(callback_data,
                    Nan::New("cb").ToLocalChecked()
                    ).ToLocalChecked().As<External>()->Value());
   void *user_data =
-      Nan::Get(info.Callee(),
+      Nan::Get(callback_data,
                Nan::New("user_data").ToLocalChecked()
                ).ToLocalChecked().As<External>()->Value();
   cb(user_data, array.metadata, array.count, code, details);
@@ -227,17 +239,17 @@
   while (!callbacks.empty()) {
     plugin_callback_data *data = callbacks.front();
     callbacks.pop_front();
-    // Attach cb and user_data to plugin_callback so that it can access them later
-    v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
-        Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
-    Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
+    Local<Object> callback_data = Nan::New<Object>();
+    Nan::Set(callback_data, Nan::New("cb").ToLocalChecked(),
              Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
-    Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
+    Nan::Set(callback_data, Nan::New("user_data").ToLocalChecked(),
              Nan::New<v8::External>(data->user_data));
-    const int argc = 2;
+    const int argc = 3;
     v8::Local<v8::Value> argv[argc] = {
       Nan::New(data->service_url).ToLocalChecked(),
-      plugin_callback
+      callback_data,
+      // Get Local<Function> from Nan::Callback*
+      **plugin_callback
     };
     Nan::Callback *callback = state->callback;
     callback->Call(argc, argv);
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 582d560..1bb946a 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-health-check",
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "author": "Google Inc.",
   "description": "Health check service for use with gRPC",
   "repository": {
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index b746d06..51ff1da 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -71,6 +71,8 @@
 
 var common = require('./common.js');
 
+var _ = require('lodash');
+
 /**
  * Create an SSL Credentials object. If using a client-side certificate, both
  * the second and third arguments must be passed.
@@ -92,13 +94,14 @@
  * @return {CallCredentials} The credentials object
  */
 exports.createFromMetadataGenerator = function(metadata_generator) {
-  return CallCredentials.createFromPlugin(function(service_url, callback) {
+  return CallCredentials.createFromPlugin(function(service_url, cb_data,
+                                                   callback) {
     metadata_generator({service_url: service_url}, function(error, metadata) {
       var code = grpc.status.OK;
       var message = '';
       if (error) {
         message = error.message;
-        if (error.hasOwnProperty('code')) {
+        if (error.hasOwnProperty('code') && _.isFinite(error.code)) {
           code = error.code;
         } else {
           code = grpc.status.UNAUTHENTICATED;
@@ -107,7 +110,7 @@
           metadata = new Metadata();
         }
       }
-      callback(code, message, metadata._getCoreRepresentation());
+      callback(code, message, metadata._getCoreRepresentation(), cb_data);
     });
   });
 };
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 0a21572..305843f 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -71,7 +71,10 @@
 var fakeFailingGoogleCredentials = {
   getRequestMetadata: function(service_url, callback) {
     setTimeout(function() {
-      callback(new Error('Authentication failure'));
+      // Google credentials currently adds string error codes to auth errors
+      var error = new Error('Authentication failure');
+      error.code = 'ENOENT';
+      callback(error);
     }, 0);
   }
 };
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index 7efa0d3..8ae5174 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-tools",
-  "version": "1.0.0-pre1",
+  "version": "1.0.0-pre2",
   "author": "Google Inc.",
   "description": "Tools for developing with gRPC on Node.js",
   "homepage": "http://www.grpc.io/",
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
index 646bf43..4a3f3fa 100644
--- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
@@ -43,7 +43,10 @@
  * Use the provided @c userAgentPrefix at the beginning of the HTTP User Agent string for all calls
  * to the specified @c host.
  */
-+ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host;
++ (void)setUserAgentPrefix:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host;
+
+/** The default response size limit is 4MB. Set this to override that default. */
++ (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host;
 
 + (void)closeOpenConnections DEPRECATED_MSG_ATTRIBUTE("The API for this feature is experimental, "
                                                       "and might be removed or modified at any "
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
index bcc3b91..7fab357 100644
--- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
@@ -37,15 +37,16 @@
 
 @implementation GRPCCall (ChannelArg)
 
-+ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host {
-  if (!host) {
-    [NSException raise:NSInvalidArgumentException
-                format:@"host and userAgentPrefix must be provided."];
-  }
++ (void)setUserAgentPrefix:(nonnull NSString *)userAgentPrefix forHost:(nonnull NSString *)host {
   GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
   hostConfig.userAgentPrefix = userAgentPrefix;
 }
 
++ (void)setResponseSizeLimit:(NSUInteger)limit forHost:(nonnull NSString *)host {
+  GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+  hostConfig.responseSizeLimitOverride = @(limit);
+}
+
 + (void)closeOpenConnections {
   [GRPCHost flushChannelCache];
 }
diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h
index ccc5723..184ad09 100644
--- a/src/objective-c/GRPCClient/GRPCCall+Tests.h
+++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h
@@ -57,4 +57,10 @@
  * more than one invocation of the methods of this category.
  */
 + (void)useInsecureConnectionsForHost:(NSString *)host;
+
+/**
+ * Resets all host configurations to their default values, and flushes all connections from the
+ * cache.
+ */
++ (void)resetHostSettings;
 @end
diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m
index b945669..656cba8 100644
--- a/src/objective-c/GRPCClient/GRPCCall+Tests.m
+++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m
@@ -61,4 +61,7 @@
   hostConfig.secure = NO;
 }
 
++ (void)resetHostSettings {
+  [GRPCHost resetAllHostSettings];
+}
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 7b7b79e..e49acee 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -47,7 +47,7 @@
 #endif
 #import "GRPCCompletionQueue.h"
 
-void freeChannelArgs(grpc_channel_args *channel_args) {
+static void FreeChannelArgs(grpc_channel_args *channel_args) {
   for (size_t i = 0; i < channel_args->num_args; ++i) {
     grpc_arg *arg = &channel_args->args[i];
     gpr_free(arg->key);
@@ -65,7 +65,7 @@
  * value responds to @c @selector(intValue). Otherwise, an exception will be raised. The caller of
  * this function is responsible for calling @c freeChannelArgs on a non-NULL returned value.
  */
-grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
+static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
   if (!dictionary) {
     return NULL;
   }
@@ -115,10 +115,12 @@
   }
 
   if (self = [super init]) {
-    _channelArgs = buildChannelArgs(channelArgs);
+    _channelArgs = BuildChannelArgs(channelArgs);
     _host = [host copy];
-    _unmanagedChannel = grpc_cronet_secure_channel_create(cronetEngine, _host.UTF8String, _channelArgs,
-                                                     NULL);
+    _unmanagedChannel = grpc_cronet_secure_channel_create(cronetEngine,
+                                                          _host.UTF8String,
+                                                          _channelArgs,
+                                                          NULL);
   }
 
   return self;
@@ -138,7 +140,7 @@
   }
 
   if (self = [super init]) {
-    _channelArgs = buildChannelArgs(channelArgs);
+    _channelArgs = BuildChannelArgs(channelArgs);
     _host = [host copy];
     if (secure) {
       _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs,
@@ -155,7 +157,7 @@
   // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
   // as in the past that made this call to crash.
   grpc_channel_destroy(_unmanagedChannel);
-  freeChannelArgs(_channelArgs);
+  FreeChannelArgs(_channelArgs);
 }
 
 #ifdef GRPC_COMPILE_WITH_CRONET
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 350c69b..c8b5dd3 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -42,6 +42,7 @@
 @interface GRPCHost : NSObject
 
 + (void)flushChannelCache;
++ (void)resetAllHostSettings;
 
 @property(nonatomic, readonly) NSString *address;
 @property(nonatomic, copy, nullable) NSString *userAgentPrefix;
@@ -53,6 +54,10 @@
 
 @property(nonatomic, copy, nullable) NSString *hostNameOverride;
 
+/** The default response size limit is 4MB. Set this to override that default. */
+@property(nonatomic, strong, nullable) NSNumber *responseSizeLimitOverride;
+
+
 - (nullable instancetype)init NS_UNAVAILABLE;
 /** Host objects initialized with the same address are the same. */
 + (nullable instancetype)hostWithAddress:(NSString *)address;
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 08c699f..477ddf5 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -49,7 +49,7 @@
 
 // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
 // templates/src/core/surface/version.c.template .
-#define GRPC_OBJC_VERSION_STRING @"0.13.0"
+#define GRPC_OBJC_VERSION_STRING @"1.0.0-pre1"
 
 static NSMutableDictionary *kHostCache;
 
@@ -113,6 +113,12 @@
   }
 }
 
++ (void)resetAllHostSettings {
+  @synchronized (kHostCache) {
+    kHostCache = [NSMutableDictionary dictionary];
+  }
+}
+
 - (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path
                               completionQueue:(GRPCCompletionQueue *)queue {
   GRPCChannel *channel;
@@ -209,6 +215,10 @@
   if (_secure && _hostNameOverride) {
     args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
   }
+
+  if (_responseSizeLimitOverride) {
+    args[@GRPC_ARG_MAX_MESSAGE_LENGTH] = _responseSizeLimitOverride;
+  }
   return args;
 }
 
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 1167a71..916a335 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -292,15 +292,6 @@
 
 // TODO(makarandd): Move to a different file that contains only unit tests
 - (void)testExceptions {
-  // Try to set userAgentPrefix for host that is nil. This should cause
-  // an exception.
-  @try {
-    [GRPCCall setUserAgentPrefix:@"Foo" forHost:nil];
-    XCTFail(@"Did not receive an exception when host is nil");
-  } @catch(NSException *theException) {
-    NSLog(@"Received exception as expected: %@", theException.name);
-  }
-
   // Try to set parameters to nil for GRPCCall. This should cause an exception
   @try {
     (void)[[GRPCCall alloc] initWithHost:nil
diff --git a/src/objective-c/tests/InteropTests.h b/src/objective-c/tests/InteropTests.h
index 6d54343..ecab606 100644
--- a/src/objective-c/tests/InteropTests.h
+++ b/src/objective-c/tests/InteropTests.h
@@ -46,4 +46,11 @@
  * Override in a subclass to perform these tests against a specific address.
  */
 + (NSString *)host;
+
+/**
+ * Bytes of overhead of test proto responses due to encoding. This is used to excercise the behavior
+ * when responses are just above or below the max response size. For some reason, the local and
+ * remote servers enconde responses with different overhead (?), so this is defined per-subclass.
+ */
+- (int32_t)encodingOverhead;
 @end
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 494743d..f04a7e6 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -80,10 +80,6 @@
 
 #pragma mark Tests
 
-#ifdef GRPC_COMPILE_WITH_CRONET
-static cronet_engine *cronetEngine = NULL;
-#endif
-
 @implementation InteropTests {
   RMTTestService *_service;
 }
@@ -92,15 +88,22 @@
   return nil;
 }
 
+- (int32_t)encodingOverhead {
+  return 0;
+}
+
 - (void)setUp {
+  self.continueAfterFailure = NO;
+
+  [GRPCCall resetHostSettings];
+
   _service = self.class.host ? [RMTTestService serviceWithHost:self.class.host] : nil;
 #ifdef GRPC_COMPILE_WITH_CRONET
   if (cronetEngine == NULL) {
     // Cronet setup
     [Cronet setHttp2Enabled:YES];
     [Cronet start];
-    cronetEngine = [Cronet getGlobalEngine];
-    [GRPCCall useCronetWithEngine:cronetEngine];
+    [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
   }
 #endif
 }
@@ -146,6 +149,64 @@
   [self waitForExpectationsWithTimeout:16 handler:nil];
 }
 
+- (void)test4MBResponsesAreAccepted {
+  XCTAssertNotNil(self.class.host);
+  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
+
+  RMTSimpleRequest *request = [RMTSimpleRequest message];
+  const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead; // 4MB - encoding overhead
+  request.responseSize = kPayloadSize;
+
+  [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
+    XCTAssertNil(error, @"Finished with unexpected error: %@", error);
+    XCTAssertEqual(response.payload.body.length, kPayloadSize);
+    [expectation fulfill];
+  }];
+
+  [self waitForExpectationsWithTimeout:16 handler:nil];
+}
+
+- (void)testResponsesOverMaxSizeFailWithActionableMessage {
+  XCTAssertNotNil(self.class.host);
+  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
+
+  RMTSimpleRequest *request = [RMTSimpleRequest message];
+  const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead + 1; // 1B over max size
+  request.responseSize = kPayloadSize;
+
+  [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
+    // TODO(jcanizales): Catch the error and rethrow it with an actionable message:
+    // - Use +[GRPCCall setResponseSizeLimit:forHost:] to set a higher limit.
+    // - If you're developing the server, consider using response streaming, or let clients filter
+    //   responses by setting a google.protobuf.FieldMask in the request:
+    //   https://github.com/google/protobuf/blob/master/src/google/protobuf/field_mask.proto
+    XCTAssertEqualObjects(error.localizedDescription, @"Max message size exceeded");
+    [expectation fulfill];
+  }];
+
+  [self waitForExpectationsWithTimeout:16 handler:nil];
+}
+
+- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
+  XCTAssertNotNil(self.class.host);
+  __weak XCTestExpectation *expectation =
+      [self expectationWithDescription:@"HigherResponseSizeLimit"];
+
+  RMTSimpleRequest *request = [RMTSimpleRequest message];
+  const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB
+  request.responseSize = kPayloadSize;
+
+  [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:self.class.host];
+
+  [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
+    XCTAssertNil(error, @"Finished with unexpected error: %@", error);
+    XCTAssertEqual(response.payload.body.length, kPayloadSize);
+    [expectation fulfill];
+  }];
+
+  [self waitForExpectationsWithTimeout:16 handler:nil];
+}
+
 - (void)testClientStreamingRPC {
   XCTAssertNotNil(self.class.host);
   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ClientStreaming"];
diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m
index 56927a8..b41210f 100644
--- a/src/objective-c/tests/InteropTestsLocalCleartext.m
+++ b/src/objective-c/tests/InteropTestsLocalCleartext.m
@@ -47,11 +47,15 @@
   return kLocalCleartextHost;
 }
 
+- (int32_t)encodingOverhead {
+  return 10; // bytes
+}
+
 - (void)setUp {
+  [super setUp];
+
   // Register test server as non-SSL.
   [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost];
-
-  [super setUp];
 }
 
 @end
diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m
index f0f4b1d..1479c58 100644
--- a/src/objective-c/tests/InteropTestsLocalSSL.m
+++ b/src/objective-c/tests/InteropTestsLocalSSL.m
@@ -47,14 +47,18 @@
   return kLocalSSLHost;
 }
 
+- (int32_t)encodingOverhead {
+  return 10; // bytes
+}
+
 - (void)setUp {
+  [super setUp];
+
   // Register test server certificates and name.
   NSBundle *bundle = [NSBundle bundleForClass:self.class];
   NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates"
                                          ofType:@"pem"];
   [GRPCCall useTestCertsPath:certsPath testName:@"foo.test.google.fr" forHost:kLocalSSLHost];
-
-  [super setUp];
 }
 
 - (void)testExceptions {
diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m
index 758cc93..70f8475 100644
--- a/src/objective-c/tests/InteropTestsRemote.m
+++ b/src/objective-c/tests/InteropTestsRemote.m
@@ -47,4 +47,8 @@
   return kRemoteSSLHost;
 }
 
+- (int32_t)encodingOverhead {
+  return 12; // bytes
+}
+
 @end
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
index e6a052a..d1d616c 100644
--- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
@@ -39,12 +39,6 @@
             </BuildableReference>
             <SkippedTests>
                <Test
-                  Identifier = "GRPCClientTests/testConnectionToRemoteServer">
-               </Test>
-               <Test
-                  Identifier = "GRPCClientTests/testMetadata">
-               </Test>
-               <Test
                   Identifier = "InteropTests">
                </Test>
                <Test
diff --git a/src/php/README.md b/src/php/README.md
index 8abedc4..7e9819b 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -9,23 +9,12 @@
 
 ## Environment
 
-Prerequisite: `php` >=5.5, `phpize`, `pecl`, `phpunit`
+Prerequisite:
+* `php` 5.5 or above, 7.0 or above
+* `pear` and `pecl`
+* `phpunit`
 
-**Linux (Debian):**
-
-```sh
-$ sudo apt-get install php5 php5-dev php-pear
-```
-
-**Linux (CentOS):**
-
-```sh
-$ yum install php55w
-$ yum --enablerepo=remi,remi-php55 install php-devel php-pear
-```
-
-**Mac OS X:**
-
+**PEAR:**
 ```sh
 $ curl -O http://pear.php.net/go-pear.phar
 $ sudo php -d detect_unicode=0 go-pear.phar
@@ -72,13 +61,7 @@
 
 ### gRPC PHP extension
 
-Install the gRPC PHP extension from PECL
-
-```sh
-$ sudo pecl install grpc
-```
-
-Or, compile from source
+Compile the gRPC PHP extension
 
 ```sh
 $ cd grpc/src/php/ext/grpc
@@ -148,12 +131,8 @@
 You need to install `protoc-gen-php` to generate stub class `.php` files from service definition `.proto` files.
 
 ```sh
-$ cd grpc/src/php/vendor/stanley-cheung/protobuf-php # if you had run `composer install` in the previous step
-
-OR
-
-$ git clone https://github.com/stanley-cheung/Protobuf-PHP # clone from github repo
-
+$ git clone https://github.com/stanley-cheung/Protobuf-PHP
+$ cd Protobuf-PHP
 $ gem install rake ronn
 $ rake pear:package version=1.0
 $ sudo pear install Protobuf-1.0.tgz
@@ -175,7 +154,7 @@
 ```sh
 $ cd grpc
 $ npm install
-$ nodejs src/node/test/math/math_server.js
+$ node src/node/test/math/math_server.js
 ```
 
 ### Run test client
@@ -212,7 +191,7 @@
 ```sh
 $ cd grpc
 $ npm install
-$ nodejs src/node/test/math/math_server.js
+$ node src/node/test/math/math_server.js
 ```
 
 Make sure you have run `composer install` to generate the `vendor/autoload.php` file
@@ -282,7 +261,7 @@
 ```sh
 $ cd grpc
 $ npm install
-$ nodejs src/node/test/math/math_server.js
+$ node src/node/test/math/math_server.js
 ```
 
 Make sure you have run `composer install` to generate the `vendor/autoload.php` file
diff --git a/src/php/bin/determine_extension_dir.sh b/src/php/bin/determine_extension_dir.sh
index b4342ac..a598825 100755
--- a/src/php/bin/determine_extension_dir.sh
+++ b/src/php/bin/determine_extension_dir.sh
@@ -29,11 +29,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 set -e
 default_extension_dir=$(php-config --extension-dir)
-if command -v brew > /dev/null && \
-   brew ls --versions | grep php5[56]-grpc > /dev/null; then
-  # the grpc php extension was installed by homebrew
-  :
-elif [ ! -e $default_extension_dir/grpc.so ]; then
+if [ ! -e $default_extension_dir/grpc.so ]; then
   # the grpc extension is not found in the default PHP extension dir
   # try the source modules directory
   module_dir=../ext/grpc/modules
diff --git a/src/php/composer.json b/src/php/composer.json
index 8841820..1eacc64 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -8,7 +8,9 @@
   "version": "1.0.0",
   "require": {
     "php": ">=5.5.0",
-    "stanley-cheung/protobuf-php": "v0.6",
+    "stanley-cheung/protobuf-php": "v0.6"
+  },
+  "require-dev": {
     "google/auth": "v0.9"
   },
   "autoload": {
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index bd1eccb..66ca151 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -58,66 +58,44 @@
 #include "byte_buffer.h"
 
 zend_class_entry *grpc_ce_call;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers call_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_call */
-void free_wrapped_grpc_call(void *object TSRMLS_DC) {
-  wrapped_grpc_call *call = (wrapped_grpc_call *)object;
-  if (call->owned && call->wrapped != NULL) {
-    grpc_call_destroy(call->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call)
+  if (p->owned && p->wrapped != NULL) {
+    grpc_call_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&call->std TSRMLS_CC);
-  efree(call);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call to be associated with an object
  * of a class specified by class_type */
-zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type
-                                               TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_call *intern;
-
-  intern = (wrapped_grpc_call *)emalloc(sizeof(wrapped_grpc_call));
-  memset(intern, 0, sizeof(wrapped_grpc_call));
-
+php_grpc_zend_object create_wrapped_grpc_call(zend_class_entry *class_type
+                                              TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_call, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
-}
-
-/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
-   should be destroyed at the end of the object's lifecycle */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC) {
-  zval *call_object;
-  MAKE_STD_ZVAL(call_object);
-  object_init_ex(call_object, grpc_ce_call);
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
-  call->wrapped = wrapped;
-  call->owned = owned;
-  return call_object;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call, call_ce_handlers);
 }
 
 /* Creates and returns a PHP array object with the data in a
  * grpc_metadata_array. Returns NULL on failure */
-zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC) {
+zval *grpc_parse_metadata_array(grpc_metadata_array
+                                *metadata_array TSRMLS_DC) {
   int count = metadata_array->count;
   grpc_metadata *elements = metadata_array->metadata;
-  int i;
   zval *array;
-  zval **data = NULL;
+  PHP_GRPC_MAKE_STD_ZVAL(array);
+  array_init(array);
+  int i;
   HashTable *array_hash;
   zval *inner_array;
   char *str_key;
   char *str_val;
   size_t key_len;
-  MAKE_STD_ZVAL(array);
-  array_init(array);
+  zval *data = NULL;
+
   array_hash = Z_ARRVAL_P(array);
   grpc_metadata *elem;
   for (i = 0; i < count; i++) {
@@ -127,9 +105,9 @@
     memcpy(str_key, elem->key, key_len);
     str_val = ecalloc(elem->value_length + 1, sizeof(char));
     memcpy(str_val, elem->value, elem->value_length);
-    if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
-        SUCCESS) {
-      if (Z_TYPE_P(*data) != IS_ARRAY) {
+    if (php_grpc_zend_hash_find(array_hash, str_key, key_len, (void **)&data)
+        == SUCCESS) {
+      if (Z_TYPE_P(data) != IS_ARRAY) {
         zend_throw_exception(zend_exception_get_default(TSRMLS_C),
                              "Metadata hash somehow contains wrong types.",
                              1 TSRMLS_CC);
@@ -137,11 +115,13 @@
         efree(str_val);
         return NULL;
       }
-      add_next_index_stringl(*data, str_val, elem->value_length, false);
+      php_grpc_add_next_index_stringl(data, str_val, elem->value_length,
+                                      false);
     } else {
-      MAKE_STD_ZVAL(inner_array);
+      PHP_GRPC_MAKE_STD_ZVAL(inner_array);
       array_init(inner_array);
-      add_next_index_stringl(inner_array, str_val, elem->value_length, false);
+      php_grpc_add_next_index_stringl(inner_array, str_val,
+                                      elem->value_length, false);
       add_assoc_zval(array, str_key, inner_array);
     }
   }
@@ -151,185 +131,64 @@
 /* Populates a grpc_metadata_array with the data in a PHP array object.
    Returns true on success and false on failure */
 bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
-  zval **inner_array;
-  zval **value;
   HashTable *array_hash;
-  HashPosition array_pointer;
   HashTable *inner_array_hash;
-  HashPosition inner_array_pointer;
-  char *key;
-  uint key_len;
-  ulong index;
+  zval *value;
+  zval *inner_array;
   if (Z_TYPE_P(array) != IS_ARRAY) {
     return false;
   }
   grpc_metadata_array_init(metadata);
   array_hash = Z_ARRVAL_P(array);
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
-      return false;
-    }
-    if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
-      return false;
-    }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  }
-  metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
-      return false;
-    }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
-                                             &inner_array_pointer);
-         zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
-                                       &inner_array_pointer) == SUCCESS;
-         zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
-      if (Z_TYPE_P(*value) != IS_STRING) {
-        return false;
-      }
-      metadata->metadata[metadata->count].key = key;
-      metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
-      metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
-      metadata->count += 1;
-    }
-  }
-  return true;
-}
 
-#else
-
-static zend_object_handlers call_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_call */
-static void free_wrapped_grpc_call(zend_object *object) {
-  wrapped_grpc_call *call = wrapped_grpc_call_from_obj(object);
-  if (call->owned && call->wrapped != NULL) {
-    grpc_call_destroy(call->wrapped);
-  }
-  zend_object_std_dtor(&call->std);
-}
-
-/* Initializes an instance of wrapped_grpc_call to be associated with an
- * object of a class specified by class_type */
-zend_object *create_wrapped_grpc_call(zend_class_entry *class_type) {
-  wrapped_grpc_call *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_call) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &call_ce_handlers;
-  return &intern->std;
-}
-
-/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the
-   struct should be destroyed at the end of the object's lifecycle */
-void grpc_php_wrap_call(grpc_call *wrapped, bool owned, zval *call_object) {
-  object_init_ex(call_object, grpc_ce_call);
-  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(call_object);
-  call->wrapped = wrapped;
-  call->owned = owned;
-}
-
-/* Creates and returns a PHP array object with the data in a
- * grpc_metadata_array. Returns NULL on failure */
-void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
-                               zval *array) {
-  int count = metadata_array->count;
-  grpc_metadata *elements = metadata_array->metadata;
-  int i;
-  zval *data;
-  HashTable *array_hash;
-  zval inner_array;
-  char *str_key;
-  char *str_val;
-  size_t key_len;
-
-  array_init(array);
-  array_hash = HASH_OF(array);
-  grpc_metadata *elem;
-  for (i = 0; i < count; i++) {
-    elem = &elements[i];
-    key_len = strlen(elem->key);
-    str_key = ecalloc(key_len + 1, sizeof(char));
-    memcpy(str_key, elem->key, key_len);
-    str_val = ecalloc(elem->value_length + 1, sizeof(char));
-    memcpy(str_val, elem->value, elem->value_length);
-    if ((data = zend_hash_str_find(array_hash, str_key, key_len)) != NULL) {
-      if (Z_TYPE_P(data) != IS_ARRAY) {
-        zend_throw_exception(zend_exception_get_default(),
-                             "Metadata hash somehow contains wrong types.",
-                             1);
-        efree(str_key);
-        efree(str_val);
-        return;
-      }
-      add_next_index_stringl(data, str_val, elem->value_length);
-    } else {
-      array_init(&inner_array);
-      add_next_index_stringl(&inner_array, str_val, elem->value_length);
-      add_assoc_zval(array, str_key, &inner_array);
-    }
-  }
-}
-
-/* Populates a grpc_metadata_array with the data in a PHP array object.
-   Returns true on success and false on failure */
-bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
-  zval *inner_array;
-  zval *value;
-  HashTable *array_hash;
-  HashTable *inner_array_hash;
-  zend_string *key;
-  if (Z_TYPE_P(array) != IS_ARRAY) {
-    return false;
-  }
-  grpc_metadata_array_init(metadata);
-  array_hash = HASH_OF(array);
-
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
+  char *key;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type,
+                                          inner_array)
+    if (key_type != HASH_KEY_IS_STRING || key == NULL) {
       return false;
     }
     if (Z_TYPE_P(inner_array) != IS_ARRAY) {
       return false;
     }
-    inner_array_hash = HASH_OF(inner_array);
+    inner_array_hash = Z_ARRVAL_P(inner_array);
     metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  }
-  ZEND_HASH_FOREACH_END();
+  PHP_GRPC_HASH_FOREACH_END()
 
   metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
 
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
+  char *key1 = NULL;
+  int key_type1;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key1, key_type1,
+                                          inner_array)
+    if (key_type1 != HASH_KEY_IS_STRING) {
       return false;
     }
-    inner_array_hash = HASH_OF(inner_array);
-
-    ZEND_HASH_FOREACH_VAL(inner_array_hash, value) {
+    inner_array_hash = Z_ARRVAL_P(inner_array);
+    PHP_GRPC_HASH_FOREACH_VAL_START(inner_array_hash, value)
       if (Z_TYPE_P(value) != IS_STRING) {
         return false;
       }
-      metadata->metadata[metadata->count].key = ZSTR_VAL(key);
+      metadata->metadata[metadata->count].key = key1;
       metadata->metadata[metadata->count].value = Z_STRVAL_P(value);
       metadata->metadata[metadata->count].value_length = Z_STRLEN_P(value);
       metadata->count += 1;
-    } ZEND_HASH_FOREACH_END();
-  } ZEND_HASH_FOREACH_END();
+    PHP_GRPC_HASH_FOREACH_END()
+  PHP_GRPC_HASH_FOREACH_END()
   return true;
 }
 
-#endif
+/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the
+   struct should be destroyed at the end of the object's lifecycle */
+zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC) {
+  zval *call_object;
+  PHP_GRPC_MAKE_STD_ZVAL(call_object);
+  object_init_ex(call_object, grpc_ce_call);
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(call_object);
+  call->wrapped = wrapped;
+  call->owned = owned;
+  return call_object;
+}
 
 /**
  * Constructs a new instance of the Call class.
@@ -341,18 +200,11 @@
 PHP_METHOD(Call, __construct) {
   zval *channel_obj;
   char *method;
+  php_grpc_int method_len;
   zval *deadline_obj;
   char *host_override = NULL;
-#if PHP_MAJOR_VERSION < 7
-  int method_len;
-  int host_override_len = 0;
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
-  size_t method_len;
-  size_t host_override_len = 0;
+  php_grpc_int host_override_len = 0;
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
-#endif
 
   /* "OsO|s" == 1 Object, 1 string, 1 Object, 1 optional string */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s", &channel_obj,
@@ -364,13 +216,7 @@
                          "an optional String", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(
-          channel_obj TSRMLS_CC);
-#else
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(channel_obj);
-#endif
   if (channel->wrapped == NULL) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "Call cannot be constructed from a closed Channel",
@@ -378,13 +224,7 @@
     return;
   }
   add_property_zval(getThis(), "channel", channel_obj);
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *deadline =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(
-          deadline_obj TSRMLS_CC);
-#else
   wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
-#endif
   call->wrapped =
     grpc_channel_create_call(channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS,
                              completion_queue, method, host_override,
@@ -398,32 +238,18 @@
  * @return object Object with results of all actions
  */
 PHP_METHOD(Call, startBatch) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  zval **value;
-  zval **inner_value;
-  HashPosition array_pointer;
-  zval **message_value;
-  zval **message_flags;
-  char *key;
-  uint key_len;
-  ulong index;
   zval *result;
-  zval *recv_status;
-  MAKE_STD_ZVAL(result);
+  PHP_GRPC_MAKE_STD_ZVAL(result);
   object_init(result);
-#else
-  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+  php_grpc_ulong index;
+  zval *recv_status;
+  PHP_GRPC_MAKE_STD_ZVAL(recv_status);
+  object_init(recv_status);
   zval *value;
   zval *inner_value;
   zval *message_value;
   zval *message_flags;
-  zend_string *key;
-  zend_ulong index;
-  zval recv_status;
-  object_init(return_value);
-#endif
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
   
   grpc_op ops[8];
   size_t op_num = 0;
@@ -445,7 +271,6 @@
   char *message_str;
   size_t message_len;
 
-
   grpc_metadata_array_init(&metadata);
   grpc_metadata_array_init(&trailing_metadata);
   grpc_metadata_array_init(&recv_metadata);
@@ -460,67 +285,63 @@
     goto cleanup;
   }
 
-#if PHP_MAJOR_VERSION < 7
-
   array_hash = Z_ARRVAL_P(array);
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&value,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_LONG) {
+
+  char *key = NULL;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(array_hash, key, key_type, index,
+                                           value)
+    if (key_type != HASH_KEY_IS_LONG || key != NULL) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "batch keys must be integers", 1 TSRMLS_CC);
       goto cleanup;
     }
     switch(index) {
     case GRPC_OP_SEND_INITIAL_METADATA:
-      if (!create_metadata_array(*value, &metadata)) {
+      if (!create_metadata_array(value, &metadata)) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Bad metadata value given", 1 TSRMLS_CC);
         goto cleanup;
       }
-      ops[op_num].data.send_initial_metadata.count =
-          metadata.count;
-      ops[op_num].data.send_initial_metadata.metadata =
-          metadata.metadata;
+      ops[op_num].data.send_initial_metadata.count = metadata.count;
+      ops[op_num].data.send_initial_metadata.metadata = metadata.metadata;
       break;
     case GRPC_OP_SEND_MESSAGE:
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
+      if (Z_TYPE_P(value) != IS_ARRAY) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected an array for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      message_hash = Z_ARRVAL_PP(value);
-      if (zend_hash_find(message_hash, "flags", sizeof("flags"),
+      message_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(message_hash, "flags", sizeof("flags"),
                          (void **)&message_flags) == SUCCESS) {
-        if (Z_TYPE_PP(message_flags) != IS_LONG) {
+        if (Z_TYPE_P(message_flags) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Expected an int for message flags",
                                1 TSRMLS_CC);
         }
-        ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
+        ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
       }
-      if (zend_hash_find(message_hash, "message", sizeof("message"),
+      if (php_grpc_zend_hash_find(message_hash, "message", sizeof("message"),
                          (void **)&message_value) != SUCCESS ||
-          Z_TYPE_PP(message_value) != IS_STRING) {
+          Z_TYPE_P(message_value) != IS_STRING) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected a string for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
       ops[op_num].data.send_message =
-          string_to_byte_buffer(Z_STRVAL_PP(message_value),
-                                Z_STRLEN_PP(message_value));
+          string_to_byte_buffer(Z_STRVAL_P(message_value),
+                                Z_STRLEN_P(message_value));
       break;
     case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
       break;
     case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      status_hash = Z_ARRVAL_PP(value);
-      if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
+      status_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(status_hash, "metadata", sizeof("metadata"),
                          (void **)&inner_value) == SUCCESS) {
-        if (!create_metadata_array(*inner_value, &trailing_metadata)) {
+        if (!create_metadata_array(inner_value, &trailing_metadata)) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Bad trailing metadata value given",
                                1 TSRMLS_CC);
@@ -531,32 +352,32 @@
         ops[op_num].data.send_status_from_server.trailing_metadata_count =
             trailing_metadata.count;
       }
-      if (zend_hash_find(status_hash, "code", sizeof("code"),
+      if (php_grpc_zend_hash_find(status_hash, "code", sizeof("code"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_LONG) {
+        if (Z_TYPE_P(inner_value) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status code must be an integer",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status =
-            Z_LVAL_PP(inner_value);
+            Z_LVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Integer status code is required",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      if (zend_hash_find(status_hash, "details", sizeof("details"),
+      if (php_grpc_zend_hash_find(status_hash, "details", sizeof("details"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_STRING) {
+        if (Z_TYPE_P(inner_value) != IS_STRING) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status details must be a string",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status_details =
-            Z_STRVAL_PP(inner_value);
+            Z_STRVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "String status details is required",
@@ -591,132 +412,7 @@
     ops[op_num].flags = 0;
     ops[op_num].reserved = NULL;
     op_num++;
-  }
-
-#else
-
-array_hash = HASH_OF(array);
-  ZEND_HASH_FOREACH_KEY_VAL(array_hash, index, key, value) {
-    if (key) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "batch keys must be integers", 1);
-      goto cleanup;
-    }
-
-    switch(index) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      if (!create_metadata_array(value, &metadata)) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Bad metadata value given", 1);
-        goto cleanup;
-      }
-      ops[op_num].data.send_initial_metadata.count = metadata.count;
-      ops[op_num].data.send_initial_metadata.metadata = metadata.metadata;
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      if (Z_TYPE_P(value) != IS_ARRAY) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Expected an array for send message", 1);
-        goto cleanup;
-      }
-      message_hash = HASH_OF(value);
-      if ((message_flags =
-           zend_hash_str_find(message_hash, "flags",
-                              sizeof("flags") - 1)) != NULL) {
-        if (Z_TYPE_P(message_flags) != IS_LONG) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Expected an int for message flags", 1);
-        }
-        ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
-      }
-      if ((message_value = zend_hash_str_find(message_hash, "message",
-                                              sizeof("message") - 1))
-          == NULL || Z_TYPE_P(message_value) != IS_STRING) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Expected a string for send message", 1);
-        goto cleanup;
-      }
-      ops[op_num].data.send_message =
-        string_to_byte_buffer(Z_STRVAL_P(message_value),
-                              Z_STRLEN_P(message_value));
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      status_hash = HASH_OF(value);
-      if ((inner_value = zend_hash_str_find(status_hash, "metadata",
-                                            sizeof("metadata") - 1))
-          != NULL) {
-        if (!create_metadata_array(inner_value, &trailing_metadata)) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Bad trailing metadata value given", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.trailing_metadata =
-          trailing_metadata.metadata;
-        ops[op_num].data.send_status_from_server.trailing_metadata_count =
-          trailing_metadata.count;
-      }
-      if ((inner_value = zend_hash_str_find(status_hash, "code",
-                                            sizeof("code") - 1)) != NULL) {
-        if (Z_TYPE_P(inner_value) != IS_LONG) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Status code must be an integer", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.status =
-          Z_LVAL_P(inner_value);
-      } else {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Integer status code is required", 1);
-        goto cleanup;
-      }
-      if ((inner_value = zend_hash_str_find(status_hash, "details",
-                                            sizeof("details") - 1)) != NULL) {
-        if (Z_TYPE_P(inner_value) != IS_STRING) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Status details must be a string", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.status_details =
-          Z_STRVAL_P(inner_value);
-      } else {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "String status details is required", 1);
-        goto cleanup;
-      }
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
-      ops[op_num].data.recv_initial_metadata = &recv_metadata;
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      ops[op_num].data.recv_message = &message;
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      ops[op_num].data.recv_status_on_client.trailing_metadata =
-        &recv_trailing_metadata;
-      ops[op_num].data.recv_status_on_client.status = &status;
-      ops[op_num].data.recv_status_on_client.status_details =
-        &status_details;
-      ops[op_num].data.recv_status_on_client.status_details_capacity =
-        &status_details_capacity;
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
-      break;
-    default:
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "Unrecognized key in batch", 1);
-      goto cleanup;
-    }
-    ops[op_num].op = (grpc_op_type)index;
-    ops[op_num].flags = 0;
-    ops[op_num].reserved = NULL;
-    op_num++;
-  }
-  ZEND_HASH_FOREACH_END();
-
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 
   error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
                                 NULL);
@@ -728,7 +424,9 @@
   }
   grpc_completion_queue_pluck(completion_queue, call->wrapped,
                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+  zval recv_md;
+#endif
   for (int i = 0; i < op_num; i++) {
     switch(ops[i].op) {
     case GRPC_OP_SEND_INITIAL_METADATA:
@@ -744,29 +442,38 @@
       add_property_bool(result, "send_status", true);
       break;
     case GRPC_OP_RECV_INITIAL_METADATA:
+#if PHP_MAJOR_VERSION < 7
       array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
       add_property_zval(result, "metadata", array);
-      Z_DELREF_P(array);
+#else
+      recv_md = *grpc_parse_metadata_array(&recv_metadata);
+      add_property_zval(result, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
       break;
     case GRPC_OP_RECV_MESSAGE:
       byte_buffer_to_string(message, &message_str, &message_len);
       if (message_str == NULL) {
         add_property_null(result, "message");
       } else {
-        add_property_stringl(result, "message", message_str, message_len,
-                             false);
+        php_grpc_add_property_stringl(result, "message", message_str,
+                                      message_len, false);
       }
       break;
     case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      MAKE_STD_ZVAL(recv_status);
-      object_init(recv_status);
+#if PHP_MAJOR_VERSION < 7
       array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
       add_property_zval(recv_status, "metadata", array);
-      Z_DELREF_P(array);
+#else
+      recv_md = *grpc_parse_metadata_array(&recv_trailing_metadata);
+      add_property_zval(recv_status, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
       add_property_long(recv_status, "code", status);
-      add_property_string(recv_status, "details", status_details, true);
+      php_grpc_add_property_string(recv_status, "details", status_details,
+                                   true);
       add_property_zval(result, "status", recv_status);
-      Z_DELREF_P(recv_status);
+      PHP_GRPC_DELREF(recv_status);
       break;
     case GRPC_OP_RECV_CLOSE_ON_SERVER:
       add_property_bool(result, "cancelled", cancelled);
@@ -775,50 +482,6 @@
       break;
     }
   }
-#else
-  for (int i = 0; i < op_num; i++) {
-    switch(ops[i].op) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      add_property_bool(return_value, "send_metadata", true);
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      add_property_bool(return_value, "send_message", true);
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      add_property_bool(return_value, "send_close", true);
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      add_property_bool(return_value, "send_status", true);
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
-      grpc_parse_metadata_array(&recv_metadata, array);
-      add_property_zval(return_value, "metadata", array);
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      byte_buffer_to_string(message, &message_str, &message_len);
-      if (message_str == NULL) {
-        add_property_null(return_value, "message");
-      } else {
-        add_property_stringl(return_value, "message", message_str,
-                             message_len);
-      }
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      object_init(&recv_status);
-      grpc_parse_metadata_array(&recv_trailing_metadata, array);
-      add_property_zval(&recv_status, "metadata", array);
-      add_property_long(&recv_status, "code", status);
-      add_property_string(&recv_status, "details", status_details);
-      add_property_zval(return_value, "status", &recv_status);
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      add_property_bool(return_value, "cancelled", cancelled);
-      break;
-    default:
-      break;
-    }
-  }
-#endif
 
 cleanup:
   grpc_metadata_array_destroy(&metadata);
@@ -836,11 +499,7 @@
       grpc_byte_buffer_destroy(message);
     }
   }
-#if PHP_MAJOR_VERSION < 7
   RETURN_DESTROY_ZVAL(result);
-#else
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -848,14 +507,8 @@
  * @return string The URI of the endpoint
  */
 PHP_METHOD(Call, getPeer) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
-#else
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
-  RETURN_STRING(grpc_call_get_peer(call->wrapped));
-#endif
+  PHP_GRPC_RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
 }
 
 /**
@@ -863,12 +516,7 @@
  * has not already ended with another status.
  */
 PHP_METHOD(Call, cancel) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
-#endif
   grpc_call_cancel(call->wrapped, NULL);
 }
 
@@ -889,17 +537,9 @@
     return;
   }
 
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_call_credentials *creds =
-      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
-          creds_obj TSRMLS_CC);
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_call_credentials *creds =
     Z_WRAPPED_GRPC_CALL_CREDS_P(creds_obj);
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
-#endif
 
   grpc_call_error error = GRPC_CALL_ERROR;
   error = grpc_call_set_credentials(call->wrapped, creds->wrapped);
@@ -920,10 +560,5 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods);
   ce.create_object = create_wrapped_grpc_call;
   grpc_ce_call = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&call_ce_handlers, zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  call_ce_handlers.offset = XtOffsetOf(wrapped_grpc_call, std);
-  call_ce_handlers.free_obj = free_wrapped_grpc_call;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_call, call_ce_handlers);
 }
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 9fc52d7..e49f9b3 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -48,31 +48,19 @@
 /* Class entry for the Call PHP class */
 extern zend_class_entry *grpc_ce_call;
 
+/* Wrapper struct for grpc_call that can be associated with a PHP object */
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_call)
+  bool owned;
+  grpc_call *wrapped;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_call)
+
 #if PHP_MAJOR_VERSION < 7
 
-/* Wrapper struct for grpc_call that can be associated with a PHP object */
-typedef struct wrapped_grpc_call {
-  zend_object std;
-  bool owned;
-  grpc_call *wrapped;
-} wrapped_grpc_call;
-
-/* Creates a Call object that wraps the given grpc_call struct */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
-
-/* Creates and returns a PHP associative array of metadata from a C array of
- * call metadata */
-zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC);
+#define Z_WRAPPED_GRPC_CALL_P(zv) \
+  (wrapped_grpc_call *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-/* Wrapper struct for grpc_call that can be associated with a PHP object */
-typedef struct wrapped_grpc_call {
-  bool owned;
-  grpc_call *wrapped;
-  zend_object std;
-} wrapped_grpc_call;
-
 static inline wrapped_grpc_call
 *wrapped_grpc_call_from_obj(zend_object *obj) {
   return (wrapped_grpc_call*)((char*)(obj) -
@@ -81,15 +69,14 @@
 
 #define Z_WRAPPED_GRPC_CALL_P(zv) wrapped_grpc_call_from_obj(Z_OBJ_P((zv)))
 
-/* Creates a Call object that wraps the given grpc_call struct */
-void grpc_php_wrap_call(grpc_call *wrapped, bool owned, zval *call_object);
+#endif /* PHP_MAJOR_VERSION */
 
 /* Creates and returns a PHP associative array of metadata from a C array of
  * call metadata */
-void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
-                               zval *array);
+zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC);
 
-#endif /* PHP_MAJOR_VERSION */
+/* Creates a Call object that wraps the given grpc_call struct */
+zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
 
 /* Initializes the Call PHP class */
 void grpc_init_call(TSRMLS_D);
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 70aaffb..6921a5d 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -52,88 +52,39 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_call_credentials;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers call_credentials_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_call_credentials */
-void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
-  wrapped_grpc_call_credentials *creds =
-      (wrapped_grpc_call_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_call_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call_credentials)
+  if (p->wrapped != NULL) {
+    grpc_call_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call_credentials to be
  * associated with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_call_credentials(
+php_grpc_zend_object create_wrapped_grpc_call_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_call_credentials *intern;
-
-  intern = (wrapped_grpc_call_credentials *)emalloc(
-      sizeof(wrapped_grpc_call_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_call_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_call_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call_credentials,
+                             call_credentials_ce_handlers);
 }
 
-zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped TSRMLS_DC) {
+zval *grpc_php_wrap_call_credentials(grpc_call_credentials
+                                     *wrapped TSRMLS_DC) {
   zval *credentials_object;
-  MAKE_STD_ZVAL(credentials_object);
-  object_init_ex(credentials_object, grpc_ce_call_credentials);
-  wrapped_grpc_call_credentials *credentials =
-      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
-          credentials_object TSRMLS_CC);
-  credentials->wrapped = wrapped;
-  return credentials_object;
-}
-
-#else
-
-static zend_object_handlers call_credentials_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_call_credentials */
-static void free_wrapped_grpc_call_credentials(zend_object *object) {
-  wrapped_grpc_call_credentials *creds =
-    wrapped_grpc_call_creds_from_obj(object);
-  if (creds->wrapped != NULL) {
-    grpc_call_credentials_release(creds->wrapped);
-  }
-  zend_object_std_dtor(&creds->std);
-}
-
-/* Initializes an instance of wrapped_grpc_call_credentials to be
- * associated with an object of a class specified by class_type */
-zend_object *create_wrapped_grpc_call_credentials(zend_class_entry
-                                                  *class_type) {
-  wrapped_grpc_call_credentials *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_call_credentials) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &call_credentials_ce_handlers;
-  return &intern->std;
-}
-
-void grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped,
-                                    zval *credentials_object) {
+  PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
   object_init_ex(credentials_object, grpc_ce_call_credentials);
   wrapped_grpc_call_credentials *credentials =
     Z_WRAPPED_GRPC_CALL_CREDS_P(credentials_object);
   credentials->wrapped = wrapped;
+  return credentials_object;
 }
 
-#endif
-
 /**
  * Create composite credentials from two existing credentials.
  * @param CallCredentials cred1 The first credential
@@ -153,29 +104,17 @@
                          1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_call_credentials *cred1 =
-      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
-          cred1_obj TSRMLS_CC);
-  wrapped_grpc_call_credentials *cred2 =
-      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
-          cred2_obj TSRMLS_CC);
-  grpc_call_credentials *creds =
-      grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
-                                             NULL);
-  zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
-  RETURN_DESTROY_ZVAL(creds_object);
-#else
   wrapped_grpc_call_credentials *cred1 =
     Z_WRAPPED_GRPC_CALL_CREDS_P(cred1_obj);
   wrapped_grpc_call_credentials *cred2 =
     Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
   grpc_call_credentials *creds =
-    grpc_composite_call_credentials_create(cred1->wrapped,
-                                           cred2->wrapped, NULL);
-  grpc_php_wrap_call_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
+      grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
+                                             NULL);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
+  RETURN_DESTROY_ZVAL(creds_object);
 }
 
 /**
@@ -216,13 +155,10 @@
 
   grpc_call_credentials *creds =
     grpc_metadata_credentials_create_from_plugin(plugin, NULL);
-#if PHP_MAJOR_VERSION < 7
-  zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
-#else
-  grpc_php_wrap_call_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /* Callback function for plugin creds API */
@@ -235,37 +171,28 @@
 
   /* prepare to call the user callback function with info from the
    * grpc_auth_metadata_context */
+  zval *arg;
+  PHP_GRPC_MAKE_STD_ZVAL(arg);
+  object_init(arg);
+  php_grpc_add_property_string(arg, "service_url", context.service_url, true);
+  php_grpc_add_property_string(arg, "method_name", context.method_name, true);
+  zval *retval;
+  PHP_GRPC_MAKE_STD_ZVAL(retval);
 #if PHP_MAJOR_VERSION < 7
   zval **params[1];
-  zval *arg;
-  zval *retval;
-  MAKE_STD_ZVAL(arg);
-  object_init(arg);
-  add_property_string(arg, "service_url", context.service_url, true);
-  add_property_string(arg, "method_name", context.method_name, true);
   params[0] = &arg;
-  state->fci->param_count = 1;
   state->fci->params = params;
   state->fci->retval_ptr_ptr = &retval;
 #else
-  zval arg;
-  zval retval;
-  object_init(&arg);
-  add_property_string(&arg, "service_url", context.service_url);
-  add_property_string(&arg, "method_name", context.method_name);
-  state->fci->param_count = 1;
-  state->fci->params = &arg;
-  state->fci->retval = &retval;
+  state->fci->params = arg;
+  state->fci->retval = retval;
 #endif
+  state->fci->param_count = 1;
 
   /* call the user callback function */
   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
 
-#if PHP_MAJOR_VERSION < 7
   if (Z_TYPE_P(retval) != IS_ARRAY) {
-#else
-  if (Z_TYPE_P(&retval) != IS_ARRAY) {
-#endif
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "plugin callback must return metadata array",
                          1 TSRMLS_CC);
@@ -273,11 +200,7 @@
   }
 
   grpc_metadata_array metadata;
-#if PHP_MAJOR_VERSION < 7
   if (!create_metadata_array(retval, &metadata)) {
-#else
-  if (!create_metadata_array(&retval, &metadata)) {
-#endif
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "invalid metadata", 1 TSRMLS_CC);
     grpc_metadata_array_destroy(&metadata);
@@ -312,13 +235,6 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
   ce.create_object = create_wrapped_grpc_call_credentials;
   grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&call_credentials_ce_handlers,
-         zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  call_credentials_ce_handlers.offset =
-    XtOffsetOf(wrapped_grpc_call_credentials, std);
-  call_credentials_ce_handlers.free_obj =
-    free_wrapped_grpc_call_credentials;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
+                        call_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
index e05e146..c1d85c0 100755
--- a/src/php/ext/grpc/call_credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -49,34 +49,27 @@
 /* Class entry for the CallCredentials PHP class */
 extern zend_class_entry *grpc_ce_call_credentials;
 
-#if PHP_MAJOR_VERSION < 7
-
 /* Wrapper struct for grpc_call_credentials that can be associated
  * with a PHP object */
-typedef struct wrapped_grpc_call_credentials {
-  zend_object std;
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_call_credentials)
   grpc_call_credentials *wrapped;
-} wrapped_grpc_call_credentials;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_call_credentials)
+
+#if PHP_MAJOR_VERSION < 7
+
+#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv) \
+  (wrapped_grpc_call_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-/* Wrapper struct for grpc_call_credentials that can be associated
- * with a PHP object */
-typedef struct wrapped_grpc_call_credentials {
-  grpc_call_credentials *wrapped;
-  zend_object std;
-} wrapped_grpc_call_credentials;
-
 static inline wrapped_grpc_call_credentials
-*wrapped_grpc_call_creds_from_obj(zend_object *obj) {
-  return
-    (wrapped_grpc_call_credentials*)((char*)(obj) -
-                                     XtOffsetOf(wrapped_grpc_call_credentials,
-                                                std));
+*wrapped_grpc_call_credentials_from_obj(zend_object *obj) {
+  return (wrapped_grpc_call_credentials*)(
+      (char*)(obj) - XtOffsetOf(wrapped_grpc_call_credentials, std));
 }
 
-#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv)           \
-  wrapped_grpc_call_creds_from_obj(Z_OBJ_P((zv)))
+#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv) \
+  wrapped_grpc_call_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 6737e34..b5a2c9f 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -56,123 +56,52 @@
 #include "timeval.h"
 
 zend_class_entry *grpc_ce_channel;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers channel_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_channel */
-void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
-  wrapped_grpc_channel *channel = (wrapped_grpc_channel *)object;
-  if (channel->wrapped != NULL) {
-    grpc_channel_destroy(channel->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
+  if (p->wrapped != NULL) {
+    grpc_channel_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&channel->std TSRMLS_CC);
-  efree(channel);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_channel to be associated with an
  * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_channel(zend_class_entry *class_type
-                                                  TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_channel *intern;
-  intern = (wrapped_grpc_channel *)emalloc(sizeof(wrapped_grpc_channel));
-  memset(intern, 0, sizeof(wrapped_grpc_channel));
+php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
+                                                 TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_channel, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
 }
 
 void php_grpc_read_args_array(zval *args_array,
                               grpc_channel_args *args TSRMLS_DC) {
   HashTable *array_hash;
-  HashPosition array_pointer;
   int args_index;
-  zval **data;
-  char *key;
-  uint key_len;
-  ulong index;
   array_hash = Z_ARRVAL_P(args_array);
-  args->num_args = zend_hash_num_elements(array_hash);
-  args->args = ecalloc(args->num_args, sizeof(grpc_arg));
-  args_index = 0;
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void **)&data,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args keys must be strings", 1 TSRMLS_CC);
-      return;
-    }
-    args->args[args_index].key = key;
-    switch (Z_TYPE_P(*data)) {
-    case IS_LONG:
-      args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_INTEGER;
-      break;
-    case IS_STRING:
-      args->args[args_index].value.string = Z_STRVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_STRING;
-      break;
-    default:
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1 TSRMLS_CC);
-      return;
-    }
-    args_index++;
-  }
-}
-
-#else
-
-static zend_object_handlers channel_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_channel */
-static void free_wrapped_grpc_channel(zend_object *object) {
-  wrapped_grpc_channel *channel = wrapped_grpc_channel_from_obj(object);
-  if (channel->wrapped != NULL) {
-    grpc_channel_destroy(channel->wrapped);
-  }
-  zend_object_std_dtor(&channel->std);
-}
-
-/* Initializes an instance of wrapped_grpc_channel to be associated with an
- * object of a class specified by class_type */
-zend_object *create_wrapped_grpc_channel(zend_class_entry *class_type) {
-  wrapped_grpc_channel *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_channel) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &channel_ce_handlers;
-  return &intern->std;
-}
-
-void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) {
-  HashTable *array_hash;
-  int args_index;
-  zval *data;
-  zend_string *key;
-  array_hash = HASH_OF(args_array);
   if (!array_hash) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "array_hash is NULL", 1);
+                         "array_hash is NULL", 1 TSRMLS_CC);
     return;
   }
   args->num_args = zend_hash_num_elements(array_hash);
   args->args = ecalloc(args->num_args, sizeof(grpc_arg));
   args_index = 0;
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, data) {
-    if (key == NULL) {
+
+  char *key = NULL;
+  zval *data;
+  int key_type;
+
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
+    if (key_type != HASH_KEY_IS_STRING) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args keys must be strings", 1);
+                           "args keys must be strings", 1 TSRMLS_CC);
+      return;
     }
-    args->args[args_index].key = ZSTR_VAL(key);
+    args->args[args_index].key = key;
     switch (Z_TYPE_P(data)) {
     case IS_LONG:
       args->args[args_index].value.integer = (int)Z_LVAL_P(data);
@@ -184,15 +113,13 @@
       break;
     default:
       zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1);
+                           "args values must be int or string", 1 TSRMLS_CC);
       return;
     }
     args_index++;
-  } ZEND_HASH_FOREACH_END();
+  PHP_GRPC_HASH_FOREACH_END()
 }
 
-#endif
-
 /**
  * Construct an instance of the Channel class. If the $args array contains a
  * "credentials" key mapping to a ChannelCredentials object, a secure channel
@@ -201,18 +128,10 @@
  * @param array $args The arguments to pass to the Channel (optional)
  */
 PHP_METHOD(Channel, __construct) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(
-          getThis() TSRMLS_CC);
-  zval **creds_obj = NULL;
-  int target_length;
-#else
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
   zval *creds_obj = NULL;
-  size_t target_length;
-#endif
   char *target;
+  php_grpc_int target_length;
   zval *args_array = NULL;
   grpc_channel_args args;
   HashTable *array_hash;
@@ -225,43 +144,23 @@
                          "Channel expects a string and an array", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
   array_hash = Z_ARRVAL_P(args_array);
-  if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
+  if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
                      (void **)&creds_obj) == SUCCESS) {
-    if (Z_TYPE_P(*creds_obj) == IS_NULL) {
+    if (Z_TYPE_P(creds_obj) == IS_NULL) {
       creds = NULL;
-      zend_hash_del(array_hash, "credentials", 12);
-    } else if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
-        grpc_ce_channel_credentials) {
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
+    } else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
+               grpc_ce_channel_credentials) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "credentials must be a ChannelCredentials object",
                            1 TSRMLS_CC);
       return;
     } else {
-      creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
-          *creds_obj TSRMLS_CC);
-      zend_hash_del(array_hash, "credentials", 12);
-    }
-  }
-#else
-  array_hash = HASH_OF(args_array);
-  if ((creds_obj = zend_hash_str_find(array_hash, "credentials",
-                                      sizeof("credentials") - 1)) != NULL) {
-    if (Z_TYPE_P(creds_obj) == IS_NULL) {
-      creds = NULL;
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
-    } else if (Z_OBJ_P(creds_obj)->ce != grpc_ce_channel_credentials) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "credentials must be a ChannelCredentials object",
-                           1);
-      return;
-    } else {
       creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
     }
   }
-#endif
   php_grpc_read_args_array(args_array, &args TSRMLS_CC);
   if (creds == NULL) {
     channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
@@ -277,14 +176,8 @@
  * @return string The URI of the endpoint
  */
 PHP_METHOD(Channel, getTarget) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel *channel =
-    (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
-#else
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-  RETURN_STRING(grpc_channel_get_target(channel->wrapped));
-#endif
+  PHP_GRPC_RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
 }
 
 /**
@@ -293,12 +186,7 @@
  * @return long The grpc connectivity state
  */
 PHP_METHOD(Channel, getConnectivityState) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-#endif
   bool try_to_connect = false;
 
   /* "|b" == 1 optional bool */
@@ -320,32 +208,19 @@
  *              before deadline
  */
 PHP_METHOD(Channel, watchConnectivityState) {
-#if PHP_MAJOR_VERSION < 7
-  long last_state;
-  wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
-  zend_long last_state;
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-#endif
+  php_grpc_long last_state;
   zval *deadline_obj;
 
   /* "lO" == 1 long 1 object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
           &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-        "watchConnectivityState expects 1 long 1 timeval",
-        1 TSRMLS_CC);
+        "watchConnectivityState expects 1 long 1 timeval", 1 TSRMLS_CC);
     return;
   }
 
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *deadline =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(
-          deadline_obj TSRMLS_CC);
-#else
   wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
-#endif
   grpc_channel_watch_connectivity_state(channel->wrapped,
                                         (grpc_connectivity_state)last_state,
                                         deadline->wrapped, completion_queue,
@@ -360,12 +235,7 @@
  * Close the channel
  */
 PHP_METHOD(Channel, close) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel *channel =
-    (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-#endif
   if (channel->wrapped != NULL) {
     grpc_channel_destroy(channel->wrapped);
     channel->wrapped = NULL;
@@ -386,11 +256,5 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
   ce.create_object = create_wrapped_grpc_channel;
   grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&channel_ce_handlers, zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  channel_ce_handlers.offset =
-    XtOffsetOf(wrapped_grpc_channel, std);
-  channel_ce_handlers.free_obj = free_wrapped_grpc_channel;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
 }
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index ea5efea..0b81565 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -48,29 +48,25 @@
 /* Class entry for the PHP Channel class */
 extern zend_class_entry *grpc_ce_channel;
 
+/* Wrapper struct for grpc_channel that can be associated with a PHP object */
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_channel)
+  grpc_channel *wrapped;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_channel)
+
 #if PHP_MAJOR_VERSION < 7
 
-/* Wrapper struct for grpc_channel that can be associated with a PHP object */
-typedef struct wrapped_grpc_channel {
-  zend_object std;
-  grpc_channel *wrapped;
-} wrapped_grpc_channel;
+#define Z_WRAPPED_GRPC_CHANNEL_P(zv) \
+  (wrapped_grpc_channel *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-/* Wrapper struct for grpc_channel that can be associated with a PHP object */
-typedef struct wrapped_grpc_channel {
-  grpc_channel *wrapped;
-  zend_object std;
-} wrapped_grpc_channel;
-
 static inline wrapped_grpc_channel
 *wrapped_grpc_channel_from_obj(zend_object *obj) {
   return (wrapped_grpc_channel*)((char*)(obj) -
                                  XtOffsetOf(wrapped_grpc_channel, std));
 }
 
-#define Z_WRAPPED_GRPC_CHANNEL_P(zv)            \
+#define Z_WRAPPED_GRPC_CHANNEL_P(zv) \
   wrapped_grpc_channel_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index 16ba036..0b356aa 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -52,6 +52,9 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_channel_credentials;
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers channel_credentials_ce_handlers;
+#endif
 static char *default_pem_root_certs = NULL;
 
 static grpc_ssl_roots_override_result get_ssl_roots_override(
@@ -63,88 +66,35 @@
   return GRPC_SSL_ROOTS_OVERRIDE_OK;
 }
 
-#if PHP_MAJOR_VERSION < 7
-
 /* Frees and destroys an instance of wrapped_grpc_channel_credentials */
-void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
-  wrapped_grpc_channel_credentials *creds =
-      (wrapped_grpc_channel_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_channel_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel_credentials)
+  if (p->wrapped != NULL) {
+    grpc_channel_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_channel_credentials to be
  * associated with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_channel_credentials(
+php_grpc_zend_object create_wrapped_grpc_channel_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_channel_credentials *intern;
-
-  intern = (wrapped_grpc_channel_credentials *)emalloc(
-      sizeof(wrapped_grpc_channel_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_channel_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_channel_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel_credentials,
+                             channel_credentials_ce_handlers);
 }
 
 zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials
                                         *wrapped TSRMLS_DC) {
   zval *credentials_object;
-  MAKE_STD_ZVAL(credentials_object);
-  object_init_ex(credentials_object, grpc_ce_channel_credentials);
-  wrapped_grpc_channel_credentials *credentials =
-      (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
-          credentials_object TSRMLS_CC);
-  credentials->wrapped = wrapped;
-  return credentials_object;
-}
-
-#else
-
-static zend_object_handlers channel_credentials_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
-static void free_wrapped_grpc_channel_credentials(zend_object *object) {
-  wrapped_grpc_channel_credentials *creds =
-    wrapped_grpc_channel_creds_from_obj(object);
-  if (creds->wrapped != NULL) {
-    grpc_channel_credentials_release(creds->wrapped);
-  }
-  zend_object_std_dtor(&creds->std);
-}
-
-/* Initializes an instance of wrapped_grpc_channel_credentials to be
- * associated with an object of a class specified by class_type */
-zend_object *create_wrapped_grpc_channel_credentials(zend_class_entry
-                                                     *class_type) {
-  wrapped_grpc_channel_credentials *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_channel_credentials) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &channel_credentials_ce_handlers;
-  return &intern->std;
-}
-
-void grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped,
-                                       zval *credentials_object) {
+  PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
   object_init_ex(credentials_object, grpc_ce_channel_credentials);
   wrapped_grpc_channel_credentials *credentials =
     Z_WRAPPED_GRPC_CHANNEL_CREDS_P(credentials_object);
   credentials->wrapped = wrapped;
+  return credentials_object;
 }
 
-#endif
-
 /**
  * Set default roots pem.
  * @param string pem_roots PEM encoding of the server root certificates
@@ -152,11 +102,7 @@
  */
 PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
   char *pem_roots;
-#if PHP_MAJOR_VERSION < 7
-  int pem_roots_length;
-#else
-  size_t pem_roots_length;
-#endif
+  php_grpc_int pem_roots_length;
 
   /* "s" == 1 string */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pem_roots,
@@ -175,13 +121,10 @@
  */
 PHP_METHOD(ChannelCredentials, createDefault) {
   grpc_channel_credentials *creds = grpc_google_default_credentials_create();
-#if PHP_MAJOR_VERSION < 7
-  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
-#else
-  grpc_php_wrap_channel_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -197,11 +140,9 @@
   char *pem_root_certs = NULL;
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
 
-#if PHP_MAJOR_VERSION < 7
-  int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
-#else
-  size_t root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
-#endif
+  php_grpc_int root_certs_length = 0;
+  php_grpc_int private_key_length = 0;
+  php_grpc_int cert_chain_length = 0;
 
   pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
 
@@ -219,13 +160,10 @@
   grpc_channel_credentials *creds = grpc_ssl_credentials_create(
       pem_root_certs,
       pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
-#if PHP_MAJOR_VERSION < 7
-  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
-#else
-  grpc_php_wrap_channel_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -246,29 +184,17 @@
                          "createComposite expects 2 Credentials", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_channel_credentials *cred1 =
-      (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
-          cred1_obj TSRMLS_CC);
-  wrapped_grpc_call_credentials *cred2 =
-      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
-          cred2_obj TSRMLS_CC);
-  grpc_channel_credentials *creds =
-      grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
-                                                NULL);
-  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
-  RETURN_DESTROY_ZVAL(creds_object);
-#else
   wrapped_grpc_channel_credentials *cred1 =
     Z_WRAPPED_GRPC_CHANNEL_CREDS_P(cred1_obj);
   wrapped_grpc_call_credentials *cred2 =
     Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
   grpc_channel_credentials *creds =
-    grpc_composite_channel_credentials_create(cred1->wrapped,
-                                              cred2->wrapped, NULL);
-  grpc_php_wrap_channel_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
+      grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
+                                                NULL);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  RETURN_DESTROY_ZVAL(creds_object);
 }
 
 /**
@@ -300,13 +226,6 @@
   grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
   ce.create_object = create_wrapped_grpc_channel_credentials;
   grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&channel_credentials_ce_handlers,
-         zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  channel_credentials_ce_handlers.offset =
-    XtOffsetOf(wrapped_grpc_channel_credentials, std);
-  channel_credentials_ce_handlers.free_obj =
-    free_wrapped_grpc_channel_credentials;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel_credentials,
+                        channel_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
index 44071b10..b043d91 100755
--- a/src/php/ext/grpc/channel_credentials.h
+++ b/src/php/ext/grpc/channel_credentials.h
@@ -49,34 +49,27 @@
 /* Class entry for the ChannelCredentials PHP class */
 extern zend_class_entry *grpc_ce_channel_credentials;
 
-#if PHP_MAJOR_VERSION < 7
-
 /* Wrapper struct for grpc_channel_credentials that can be associated
  * with a PHP object */
-typedef struct wrapped_grpc_channel_credentials {
-  zend_object std;
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_channel_credentials) 
   grpc_channel_credentials *wrapped;
-} wrapped_grpc_channel_credentials;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_channel_credentials)
+
+#if PHP_MAJOR_VERSION < 7
+
+#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv) \
+  (wrapped_grpc_channel_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-/* Wrapper struct for grpc_channel_credentials that can be associated
- * with a PHP object */
-typedef struct wrapped_grpc_channel_credentials {
-  grpc_channel_credentials *wrapped;
-  zend_object std;
-} wrapped_grpc_channel_credentials;
-
 static inline wrapped_grpc_channel_credentials
-*wrapped_grpc_channel_creds_from_obj(zend_object *obj) {
-  return
-    (wrapped_grpc_channel_credentials *)
-    ((char*)(obj) -
-     XtOffsetOf(wrapped_grpc_channel_credentials, std));
+*wrapped_grpc_channel_credentials_from_obj(zend_object *obj) {
+  return (wrapped_grpc_channel_credentials *)(
+      (char*)(obj) - XtOffsetOf(wrapped_grpc_channel_credentials, std));
 }
 
-#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv)            \
-  wrapped_grpc_channel_creds_from_obj(Z_OBJ_P((zv)))
+#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv) \
+  wrapped_grpc_channel_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
deleted file mode 100644
index daf2ee5..0000000
--- a/src/php/ext/grpc/package.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
- <name>grpc</name>
- <channel>pecl.php.net</channel>
- <summary>A high performance, open source, general RPC framework that puts mobile and HTTP/2 first.</summary>
- <description>Remote Procedure Calls (RPCs) provide a useful abstraction for building distributed applications and services. The libraries in this repository provide a concrete implementation of the gRPC protocol, layered over HTTP/2. These libraries enable communication between clients and servers using any combination of the supported languages.</description>
- <lead>
-  <name>Stanley Cheung</name>
-  <user>stanleycheung</user>
-  <email>grpc-packages@google.com</email>
-  <active>yes</active>
- </lead>
- <date>2016-01-13</date>
- <time>16:06:07</time>
- <version>
-  <release>0.7.0</release>
-  <api>0.7.0</api>
- </version>
- <stability>
-  <release>beta</release>
-  <api>beta</api>
- </stability>
- <license>BSD</license>
- <notes>
-- Breaking change to Credentials class (removed) #3765
-- Replaced by ChannelCredentials and CallCredentials class #3765
-- New plugin based metadata auth API #4394
-- Explicit ChannelCredentials::createInsecure() call
- </notes>
- <contents>
-  <dir baseinstalldir="/" name="/">
-   <file baseinstalldir="/" md5sum="f201d644fdbd8228ffd1d4a69cc44f1f" name="tests/grpc-basic.phpt" role="test" />
-   <file baseinstalldir="/" md5sum="6f19828fb869b7b8a590cbb76b4f996d" name="byte_buffer.c" role="src" />
-   <file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" />
-   <file baseinstalldir="/" md5sum="ee7eb7757f9e6f0e36f8f616b6bd0af5" name="call.c" role="src" />
-   <file baseinstalldir="/" md5sum="44c56bd9912d2538cbd6059e3e0452b6" name="call.h" role="src" />
-   <file baseinstalldir="/" md5sum="ff90f6c03ed44b5f4170bf3259a6704e" name="call_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="3c3860e1d84f43cb6b2fbaa8d2ae1ab7" name="call_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="aee9b63f790522aec2c682055240cc61" name="channel.c" role="src" />
-   <file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
-   <file baseinstalldir="/" md5sum="1a51c76d0b7b7d3ab570ed7d60c2ea46" name="channel_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
-   <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
-   <file baseinstalldir="/" md5sum="cafed254127007ff2271dad7d56a06c8" name="config.m4" role="src" />
-   <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
-   <file baseinstalldir="/" md5sum="8847cf67b1b54c981d47ecbb0d139a0c" name="LICENSE" role="doc" />
-   <file baseinstalldir="/" md5sum="3131a8af38fe5918e5409016b89d6cdb" name="php_grpc.c" role="src" />
-   <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
-   <file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
-   <file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
-   <file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
-   <file baseinstalldir="/" md5sum="34ea881f1fe960d190d0713422cf8916" name="server_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="7646ec78cb133f66ba59e03c6f451e39" name="timeval.c" role="src" />
-   <file baseinstalldir="/" md5sum="496e27a100b4d93ca3fb35c924c5e163" name="timeval.h" role="src" />
-  </dir>
- </contents>
- <dependencies>
-  <required>
-   <php>
-    <min>5.5.0</min>
-   </php>
-   <pearinstaller>
-    <min>1.4.0</min>
-   </pearinstaller>
-  </required>
- </dependencies>
- <providesextension>grpc</providesextension>
- <extsrcrelease />
- <changelog>
-  <release>
-   <version>
-    <release>0.5.0</release>
-    <api>0.5.0</api>
-   </version>
-   <stability>
-    <release>alpha</release>
-    <api>alpha</api>
-   </stability>
-   <date>2015-06-16</date>
-   <license>BSD</license>
-   <notes>
-First alpha release
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.5.1</release>
-    <api>0.5.1</api>
-   </version>
-   <stability>
-    <release>alpha</release>
-    <api>alpha</api>
-   </stability>
-   <date>2015-07-09</date>
-   <license>BSD</license>
-   <notes>
-Update to wrap gRPC C Core version 0.10.0
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.6.0</release>
-    <api>0.6.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2015-09-24</date>
-   <license>BSD</license>
-   <notes>
-- support per message compression disable
-- expose per-call host override option
-- expose connectivity API
-- expose channel target and call peer
-- add user-agent
-- update to wrap gRPC C core library beta version 0.11.0
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.6.1</release>
-    <api>0.6.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2015-10-21</date>
-   <license>BSD</license>
-   <notes>
-- fixed undefined constant fatal error when run with apache/nginx #2275
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.7.0</release>
-    <api>0.7.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2016-01-13</date>
-   <license>BSD</license>
-   <notes>
-- Breaking change to Credentials class (removed) #3765
-- Replaced by ChannelCredentials and CallCredentials class #3765
-- New plugin based metadata auth API #4394
-- Explicit ChannelCredentials::createInsecure() call
-   </notes>
-  </release>
- </changelog>
-</package>
diff --git a/src/php/ext/grpc/php7_wrapper.h b/src/php/ext/grpc/php7_wrapper.h
new file mode 100644
index 0000000..fd8d356
--- /dev/null
+++ b/src/php/ext/grpc/php7_wrapper.h
@@ -0,0 +1,218 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef PHP7_WRAPPER_GRPC_H
+#define PHP7_WRAPPER_GRPC_H
+
+#if PHP_MAJOR_VERSION < 7
+
+#define php_grpc_int int
+#define php_grpc_long long
+#define php_grpc_ulong ulong
+#define php_grpc_zend_object zend_object_value
+#define php_grpc_add_property_string(arg, name, context, b) \
+  add_property_string(arg, name, context, b)
+#define php_grpc_add_property_stringl(res, name, str, len, b) \
+  add_property_stringl(res, name, str, len, b)
+#define php_grpc_add_next_index_stringl(data, str, len, b) \
+  add_next_index_stringl(data, str, len, b)
+
+#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
+#define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
+#define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
+
+#define PHP_GRPC_WRAP_OBJECT_START(name) \
+  typedef struct name { \
+    zend_object std;
+#define PHP_GRPC_WRAP_OBJECT_END(name) \
+  } name;
+
+#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
+  void free_##class_object(void *object TSRMLS_DC) { \
+    class_object *p = (class_object *)object;
+#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
+    zend_object_std_dtor(&p->std TSRMLS_CC); \
+    efree(p); \
+  }
+
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  zend_object_value retval; \
+  intern = (class_object *)emalloc(sizeof(class_object)); \
+  memset(intern, 0, sizeof(class_object));
+
+#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
+  retval.handle = zend_objects_store_put( \
+    intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \
+    free_##class_object, NULL TSRMLS_CC); \
+  retval.handlers = zend_get_std_object_handlers(); \
+  return retval;
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  zval **tmp_data = NULL; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp_data) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    data = *tmp_data;
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zval **tmp##key = NULL; \
+  ulong index##key; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index##key,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index,\
+                                                 data) \
+  zval **tmp##key = NULL; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_END() }
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
+                                          void **value) {
+  zval **data = NULL;
+  if (zend_hash_find(ht, key, len, (void **)&data) == SUCCESS) {
+    *value = *data;
+    return SUCCESS;
+  } else {
+    *value = NULL;
+    return FAILURE;
+  }
+}
+
+#define php_grpc_zend_hash_del zend_hash_del
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) zend_get_class_entry(object TSRMLS_CC)
+
+#define PHP_GRPC_INIT_HANDLER(class_object, handler_name)
+
+#else
+
+#define php_grpc_int size_t
+#define php_grpc_long zend_long
+#define php_grpc_ulong zend_ulong
+#define php_grpc_zend_object zend_object*
+#define php_grpc_add_property_string(arg, name, context, b) \
+  add_property_string(arg, name, context)
+#define php_grpc_add_property_stringl(res, name, str, len, b) \
+  add_property_stringl(res, name, str, len)
+#define php_grpc_add_next_index_stringl(data, str, len, b) \
+  add_next_index_stringl(data, str, len)
+
+#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val)
+#define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
+  zval _stack_zval_##pzv; \
+  pzv = &(_stack_zval_##pzv)
+#define PHP_GRPC_DELREF(zv)
+
+#define PHP_GRPC_WRAP_OBJECT_START(name) \
+  typedef struct name {
+#define PHP_GRPC_WRAP_OBJECT_END(name) \
+    zend_object std; \
+  } name;
+
+#define WRAPPED_OBJECT_FROM_OBJ(class_object, obj) \
+  class_object##_from_obj(obj);
+
+#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
+  static void free_##class_object(zend_object *object) { \
+    class_object *p = WRAPPED_OBJECT_FROM_OBJ(class_object, object)
+#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
+    zend_object_std_dtor(&p->std); \
+  }
+
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  intern = ecalloc(1, sizeof(class_object) + \
+                   zend_object_properties_size(class_type));
+
+#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
+  intern->std.handlers = &handler; \
+  return &intern->std;
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  ZEND_HASH_FOREACH_VAL(ht, data) {
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_STR_KEY_VAL(ht, (zs_##key), data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index, \
+                                                 data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_KEY_VAL(ht, index, zs_##key, data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_END() } ZEND_HASH_FOREACH_END();
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
+                                          void **value) {
+  zval *value_tmp = zend_hash_str_find(ht, key, len -1);
+  if (value_tmp == NULL) {
+    return FAILURE;
+  } else {
+    *value = (void *)value_tmp;
+    return SUCCESS;
+  }
+}
+
+static inline int php_grpc_zend_hash_del(HashTable *ht, char *key, int len) {
+  return zend_hash_str_del(ht, key, len - 1);
+}
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) Z_OBJ_P(object)->ce
+
+#define PHP_GRPC_INIT_HANDLER(class_object, handler_name) \
+  memcpy(&handler_name, zend_get_std_object_handlers(), \
+         sizeof(zend_object_handlers)); \
+  handler_name.offset = XtOffsetOf(class_object, std); \
+  handler_name.free_obj = free_##class_object
+
+#endif /* PHP_MAJOR_VERSION */
+
+#endif /* PHP7_WRAPPER_GRPC_H */
diff --git a/src/php/ext/grpc/php_grpc.h b/src/php/ext/grpc/php_grpc.h
index bd7ee75..e57a065 100644
--- a/src/php/ext/grpc/php_grpc.h
+++ b/src/php/ext/grpc/php_grpc.h
@@ -57,6 +57,8 @@
 
 #include "php.h"
 
+#include "php7_wrapper.h"
+
 #include "grpc/grpc.h"
 
 #define RETURN_DESTROY_ZVAL(val)                               \
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 50fb2d0..fc20c42 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -57,84 +57,37 @@
 #include "timeval.h"
 
 zend_class_entry *grpc_ce_server;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers server_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_server */
-void free_wrapped_grpc_server(void *object TSRMLS_DC) {
-  wrapped_grpc_server *server = (wrapped_grpc_server *)object;
-  if (server->wrapped != NULL) {
-    grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
-    grpc_server_cancel_all_calls(server->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server)
+  if (p->wrapped != NULL) {
+    grpc_server_shutdown_and_notify(p->wrapped, completion_queue, NULL);
+    grpc_server_cancel_all_calls(p->wrapped);
     grpc_completion_queue_pluck(completion_queue, NULL,
                                 gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-    grpc_server_destroy(server->wrapped);
+    grpc_server_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&server->std TSRMLS_CC);
-  efree(server);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call to be associated with an object
  * of a class specified by class_type */
-zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
-                                                 TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_server *intern;
-
-  intern = (wrapped_grpc_server *)emalloc(sizeof(wrapped_grpc_server));
-  memset(intern, 0, sizeof(wrapped_grpc_server));
-
+php_grpc_zend_object create_wrapped_grpc_server(zend_class_entry *class_type
+                                                TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_server, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server, server_ce_handlers);
 }
 
-#else
-
-static zend_object_handlers server_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_server */
-static void free_wrapped_grpc_server(zend_object *object) {
-  wrapped_grpc_server *server = wrapped_grpc_server_from_obj(object);
-  if (server->wrapped != NULL) {
-    grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
-    grpc_server_cancel_all_calls(server->wrapped);
-    grpc_completion_queue_pluck(completion_queue, NULL,
-                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-    grpc_server_destroy(server->wrapped);
-  }
-  zend_object_std_dtor(&server->std);
-}
-
-/* Initializes an instance of wrapped_grpc_call to be associated with an object
- * of a class specified by class_type */
-zend_object *create_wrapped_grpc_server(zend_class_entry *class_type) {
-  wrapped_grpc_server *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_server) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &server_ce_handlers;
-  return &intern->std;
-}
-
-#endif
-
 /**
  * Constructs a new instance of the Server class
  * @param array $args The arguments to pass to the server (optional)
  */
 PHP_METHOD(Server, __construct) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
-#endif
   zval *args_array = NULL;
   grpc_channel_args args;
 
@@ -172,16 +125,10 @@
   grpc_metadata_array metadata;
   grpc_event event;
 
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  zval *result;
-  MAKE_STD_ZVAL(result);
-  object_init(result);
-#else
   wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
-  object_init(return_value);
-#endif
+  zval *result;
+  PHP_GRPC_MAKE_STD_ZVAL(result);
+  object_init(result);
 
   grpc_call_details_init(&details);
   grpc_metadata_array_init(&metadata);
@@ -202,40 +149,32 @@
                          1 TSRMLS_CC);
     goto cleanup;
   }
+  php_grpc_add_property_string(result, "method", details.method, true);
+  php_grpc_add_property_string(result, "host", details.host, true);
 #if PHP_MAJOR_VERSION < 7
   add_property_zval(result, "call", grpc_php_wrap_call(call, true TSRMLS_CC));
-  add_property_string(result, "method", details.method, true);
-  add_property_string(result, "host", details.host, true);
   add_property_zval(result, "absolute_deadline",
                     grpc_php_wrap_timeval(details.deadline TSRMLS_CC));
   add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata
                                                                   TSRMLS_CC));
- 
-cleanup:
-  grpc_call_details_destroy(&details);
-  grpc_metadata_array_destroy(&metadata);
-  RETURN_DESTROY_ZVAL(result);
-
 #else
-
   zval zv_call;
   zval zv_timeval;
   zval zv_md;
-  grpc_php_wrap_call(call, true, &zv_call);
-  grpc_php_wrap_timeval(details.deadline, &zv_timeval);
-  grpc_parse_metadata_array(&metadata, &zv_md);
+  //TODO(thinkerou): why use zval* to unit test error?
+  zv_call = *grpc_php_wrap_call(call, true);
+  zv_timeval = *grpc_php_wrap_timeval(details.deadline);
+  zv_md = *grpc_parse_metadata_array(&metadata);
 
-  add_property_zval(return_value, "call", &zv_call);
-  add_property_string(return_value, "method", details.method);
-  add_property_string(return_value, "host", details.host);
-  add_property_zval(return_value, "absolute_deadline", &zv_timeval);
-  add_property_zval(return_value, "metadata", &zv_md);
+  add_property_zval(result, "call", &zv_call);
+  add_property_zval(result, "absolute_deadline", &zv_timeval);
+  add_property_zval(result, "metadata", &zv_md);
+#endif
 
  cleanup:
   grpc_call_details_destroy(&details);
   grpc_metadata_array_destroy(&metadata);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
+  RETURN_DESTROY_ZVAL(result);
 }
 
 /**
@@ -245,14 +184,8 @@
  */
 PHP_METHOD(Server, addHttp2Port) {
   const char *addr;
-#if PHP_MAJOR_VERSION < 7
-  int addr_len;
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
-  size_t addr_len;
+  php_grpc_int addr_len;
   wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
-#endif
 
   /* "s" == 1 string */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len)
@@ -266,15 +199,9 @@
 
 PHP_METHOD(Server, addSecureHttp2Port) {
   const char *addr;
+  php_grpc_int addr_len;
   zval *creds_obj;
-#if PHP_MAJOR_VERSION < 7
-  int addr_len;
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
-  size_t addr_len;
   wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
-#endif
 
   /* "sO" == 1 string, 1 object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
@@ -285,14 +212,8 @@
         "add_http2_port expects a string and a ServerCredentials", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_server_credentials *creds =
-      (wrapped_grpc_server_credentials *)zend_object_store_get_object(
-          creds_obj TSRMLS_CC);
-#else
   wrapped_grpc_server_credentials *creds =
     Z_WRAPPED_GRPC_SERVER_CREDS_P(creds_obj);
-#endif
   RETURN_LONG(grpc_server_add_secure_http2_port(server->wrapped, addr,
                                                 creds->wrapped));
 }
@@ -302,12 +223,7 @@
  * @return Void
  */
 PHP_METHOD(Server, start) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
-#endif
   grpc_server_start(server->wrapped);
 }
 
@@ -317,7 +233,7 @@
   PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
   PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
   PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
+  PHP_FE_END
 };
 
 void grpc_init_server(TSRMLS_D) {
@@ -325,10 +241,5 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods);
   ce.create_object = create_wrapped_grpc_server;
   grpc_ce_server = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&server_ce_handlers, zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  server_ce_handlers.offset = XtOffsetOf(wrapped_grpc_server, std);
-  server_ce_handlers.free_obj = free_wrapped_grpc_server;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_server, server_ce_handlers);
 }
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index a7df456..a635bc1 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -48,30 +48,25 @@
 /* Class entry for the Server PHP class */
 extern zend_class_entry *grpc_ce_server;
 
+/* Wrapper struct for grpc_server that can be associated with a PHP object */
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_server)
+  grpc_server *wrapped;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_server)
+
 #if PHP_MAJOR_VERSION < 7
 
-/* Wrapper struct for grpc_server that can be associated with a PHP object */
-typedef struct wrapped_grpc_server {
-  zend_object std;
-  grpc_server *wrapped;
-} wrapped_grpc_server;
+#define Z_WRAPPED_GRPC_SERVER_P(zv) \
+  (wrapped_grpc_server *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-/* Wrapper struct for grpc_server that can be associated with a PHP object */
-typedef struct wrapped_grpc_server {
-  grpc_server *wrapped;
-  zend_object std;
-} wrapped_grpc_server;
-
 static inline wrapped_grpc_server
 *wrapped_grpc_server_from_obj(zend_object *obj) {
   return (wrapped_grpc_server*)((char*)(obj) -
                                 XtOffsetOf(wrapped_grpc_server, std));
 }
 
-#define Z_WRAPPED_GRPC_SERVER_P(zv)             \
-  wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
+#define Z_WRAPPED_GRPC_SERVER_P(zv) wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 296632d..b05896a 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -50,89 +50,39 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_server_credentials;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers server_credentials_ce_handlers;
+#endif
 
 /* Frees and destroys an instace of wrapped_grpc_server_credentials */
-void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
-  wrapped_grpc_server_credentials *creds =
-      (wrapped_grpc_server_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_server_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server_credentials)
+  if (p->wrapped != NULL) {
+    grpc_server_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instace of wrapped_grpc_server_credentials to be associated
  * with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_server_credentials(
+php_grpc_zend_object create_wrapped_grpc_server_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_server_credentials *intern;
-
-  intern = (wrapped_grpc_server_credentials *)emalloc(
-      sizeof(wrapped_grpc_server_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_server_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_server_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server_credentials,
+                             server_credentials_ce_handlers);
 }
 
 zval *grpc_php_wrap_server_credentials(grpc_server_credentials
                                        *wrapped TSRMLS_DC) {
   zval *server_credentials_object;
-  MAKE_STD_ZVAL(server_credentials_object);
-  object_init_ex(server_credentials_object, grpc_ce_server_credentials);
-  wrapped_grpc_server_credentials *server_credentials =
-      (wrapped_grpc_server_credentials *)zend_object_store_get_object(
-          server_credentials_object TSRMLS_CC);
-  server_credentials->wrapped = wrapped;
-  return server_credentials_object;
-}
-
-#else
-
-static zend_object_handlers server_credentials_ce_handlers;
-
-/* Frees and destroys an instace of wrapped_grpc_server_credentials */
-static void free_wrapped_grpc_server_credentials(zend_object *object) {
-  wrapped_grpc_server_credentials *creds =
-    wrapped_grpc_server_creds_from_obj(object);
-  if (creds->wrapped != NULL) {
-    grpc_server_credentials_release(creds->wrapped);
-  }
-  zend_object_std_dtor(&creds->std);
-}
-
-/* Initializes an instace of wrapped_grpc_server_credentials to be associated
- * with an object of a class specified by class_type */
-zend_object *create_wrapped_grpc_server_credentials(zend_class_entry
-                                                    *class_type) {
-  wrapped_grpc_server_credentials *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_server_credentials) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &server_credentials_ce_handlers;
-  return &intern->std;
-}
-
-void grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped,
-                                      zval *server_credentials_object) {
+  PHP_GRPC_MAKE_STD_ZVAL(server_credentials_object);
   object_init_ex(server_credentials_object, grpc_ce_server_credentials);
   wrapped_grpc_server_credentials *server_credentials =
     Z_WRAPPED_GRPC_SERVER_CREDS_P(server_credentials_object);
   server_credentials->wrapped = wrapped;
+  return server_credentials_object;
 }
 
-#endif
-
 /**
  * Create SSL credentials.
  * @param string pem_root_certs PEM encoding of the server root certificates
@@ -144,11 +94,9 @@
   char *pem_root_certs = 0;
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
 
-#if PHP_MAJOR_VERSION < 7
-  int root_certs_length = 0, private_key_length, cert_chain_length;
-#else
-  size_t root_certs_length = 0, private_key_length, cert_chain_length;
-#endif
+  php_grpc_int root_certs_length = 0;
+  php_grpc_int private_key_length;
+  php_grpc_int cert_chain_length;
 
   /* "s!ss" == 1 nullable string, 2 strings */
   /* TODO: support multiple key cert pairs. */
@@ -165,19 +113,16 @@
   grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex(
       pem_root_certs, &pem_key_cert_pair, 1,
       GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, NULL);
-#if PHP_MAJOR_VERSION < 7
-  zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
+  zval *creds_object;
+  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
+  creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
-#else
-  grpc_php_wrap_server_credentials(creds, return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 static zend_function_entry server_credentials_methods[] = {
   PHP_ME(ServerCredentials, createSsl, NULL,
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-   PHP_FE_END
+  PHP_FE_END
  };
 
 void grpc_init_server_credentials(TSRMLS_D) {
@@ -185,13 +130,6 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\ServerCredentials", server_credentials_methods);
   ce.create_object = create_wrapped_grpc_server_credentials;
   grpc_ce_server_credentials = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&server_credentials_ce_handlers,
-         zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  server_credentials_ce_handlers.offset =
-    XtOffsetOf(wrapped_grpc_server_credentials, std);
-  server_credentials_ce_handlers.free_obj =
-    free_wrapped_grpc_server_credentials;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_server_credentials,
+                        server_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index d37fafc..6781a61 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -49,31 +49,27 @@
 /* Class entry for the Server_Credentials PHP class */
 extern zend_class_entry *grpc_ce_server_credentials;
 
-#if PHP_MAJOR_VERSION < 7
-
 /* Wrapper struct for grpc_server_credentials that can be associated with a PHP
  * object */
-typedef struct wrapped_grpc_server_credentials {
-  zend_object std;
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_server_credentials)
   grpc_server_credentials *wrapped;
-} wrapped_grpc_server_credentials;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_server_credentials)
+
+#if PHP_MAJOR_VERSION < 7
+
+#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv) \
+  (wrapped_grpc_server_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-typedef struct wrapped_grpc_server_credentials {
-  grpc_server_credentials *wrapped;
-  zend_object std;
-} wrapped_grpc_server_credentials;
-
 static inline wrapped_grpc_server_credentials
-*wrapped_grpc_server_creds_from_obj(zend_object *obj) {
-  return (wrapped_grpc_server_credentials*)
-    ((char*)(obj) -
-     XtOffsetOf(wrapped_grpc_server_credentials, std));
+*wrapped_grpc_server_credentials_from_obj(zend_object *obj) {
+  return (wrapped_grpc_server_credentials*)(
+      (char*)(obj) - XtOffsetOf(wrapped_grpc_server_credentials, std));
 }
 
-#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv)           \
-  wrapped_grpc_server_creds_from_obj(Z_OBJ_P((zv)))
+#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv) \
+  wrapped_grpc_server_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 8dc997c..e145d96 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -51,87 +51,40 @@
 #include <grpc/support/time.h>
 
 zend_class_entry *grpc_ce_timeval;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers timeval_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_call */
-void free_wrapped_grpc_timeval(void *object TSRMLS_DC) {
-    wrapped_grpc_timeval *timeval = (wrapped_grpc_timeval *)object;
-    zend_object_std_dtor(&timeval->std TSRMLS_CC);
-    efree(timeval);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_timeval)
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_timeval to be associated with an
  * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_timeval(zend_class_entry *class_type
-                                                  TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_timeval *intern;
-  intern = (wrapped_grpc_timeval *)emalloc(sizeof(wrapped_grpc_timeval));
-  memset(intern, 0, sizeof(wrapped_grpc_timeval));
+php_grpc_zend_object create_wrapped_grpc_timeval(zend_class_entry *class_type
+                                                 TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_timeval);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_timeval, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_timeval, timeval_ce_handlers);
 }
 
 zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC) {
   zval *timeval_object;
-  MAKE_STD_ZVAL(timeval_object);
-  object_init_ex(timeval_object, grpc_ce_timeval);
-  wrapped_grpc_timeval *timeval =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(
-          timeval_object TSRMLS_CC);
-  memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
-  return timeval_object;
-}
-
-#else
-
-static zend_object_handlers timeval_ce_handlers;
-
-/* Frees and destroys an instance of wrapped_grpc_call */
-static void free_wrapped_grpc_timeval(zend_object *object) {
-  wrapped_grpc_timeval *timeval = wrapped_grpc_timeval_from_obj(object);
-  zend_object_std_dtor(&timeval->std);
-}
-
-/* Initializes an instance of wrapped_grpc_timeval to be associated with an
- * object of a class specified by class_type */
-zend_object *create_wrapped_grpc_timeval(zend_class_entry *class_type) {
-  wrapped_grpc_timeval *intern;
-  intern = ecalloc(1, sizeof(wrapped_grpc_timeval) +
-                   zend_object_properties_size(class_type));
-  zend_object_std_init(&intern->std, class_type);
-  object_properties_init(&intern->std, class_type);
-  intern->std.handlers = &timeval_ce_handlers;
-  return &intern->std;
-}
-
-void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object) {
+  PHP_GRPC_MAKE_STD_ZVAL(timeval_object);
   object_init_ex(timeval_object, grpc_ce_timeval);
   wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(timeval_object);
   memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
+  return timeval_object;
 }
 
-#endif
-
 /**
  * Constructs a new instance of the Timeval class
  * @param long $usec The number of microseconds in the interval
  */
 PHP_METHOD(Timeval, __construct) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *timeval =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long microseconds;
-#else
   wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
-  zend_long microseconds;
-#endif
+  php_grpc_long microseconds;
 
   /* "l" == 1 long */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &microseconds) ==
@@ -160,23 +113,14 @@
                          "add expects a Timeval", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *self =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  wrapped_grpc_timeval *other =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
-  zval *sum =
+  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
+  zval *sum;
+  PHP_GRPC_MAKE_STD_ZVAL(sum);
+  sum =
       grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
                             TSRMLS_CC);
   RETURN_DESTROY_ZVAL(sum);
-#else
-  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
-  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
-
-  grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped),
-                        return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -195,22 +139,14 @@
                          "subtract expects a Timeval", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *self =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  wrapped_grpc_timeval *other =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
-  zval *diff =
+  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
+  zval *diff;
+  PHP_GRPC_MAKE_STD_ZVAL(diff);
+  diff =
       grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
                             TSRMLS_CC);
   RETURN_DESTROY_ZVAL(diff);
-#else
-  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
-  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
-  grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped),
-                        return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -232,15 +168,8 @@
                          "compare expects two Timevals", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *a =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
-  wrapped_grpc_timeval *b =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
-#else
   wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
   wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
-#endif
   long result = gpr_time_cmp(a->wrapped, b->wrapped);
   RETURN_LONG(result);
 }
@@ -265,19 +194,9 @@
                          "compare expects three Timevals", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *a =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
-  wrapped_grpc_timeval *b =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
-  wrapped_grpc_timeval *thresh =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(
-          thresh_obj TSRMLS_CC);
-#else
   wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
   wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
   wrapped_grpc_timeval *thresh = Z_WRAPPED_GRPC_TIMEVAL_P(thresh_obj);
-#endif
   int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped);
   RETURN_BOOL(result);
 }
@@ -287,13 +206,10 @@
  * @return Timeval The current time
  */
 PHP_METHOD(Timeval, now) {
-#if PHP_MAJOR_VERSION < 7
-  zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
+  zval *now;
+  PHP_GRPC_MAKE_STD_ZVAL(now);
+  now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(now);
-#else
-  grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME), return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -301,18 +217,13 @@
  * @return Timeval Zero length time interval
  */
 PHP_METHOD(Timeval, zero) {
-#if PHP_MAJOR_VERSION < 7
-  zval *grpc_php_timeval_zero =
+  zval *grpc_php_timeval_zero;
+  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_zero);
+  grpc_php_timeval_zero =
       grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_ZVAL(grpc_php_timeval_zero,
               false, /* Copy original before returning? */
               true /* Destroy original before returning */);
-#else
-  grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME), return_value);
-  RETURN_ZVAL(return_value,
-              false, /* Copy original before returning? */
-              true /* Destroy original before returning */);
-#endif
 }
 
 /**
@@ -320,14 +231,11 @@
  * @return Timeval Infinite future time value
  */
 PHP_METHOD(Timeval, infFuture) {
-#if PHP_MAJOR_VERSION < 7
-  zval *grpc_php_timeval_inf_future =
+  zval *grpc_php_timeval_inf_future;
+  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_future);
+  grpc_php_timeval_inf_future =
       grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
-#else
-  grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME), return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -335,14 +243,11 @@
  * @return Timeval Infinite past time value
  */
 PHP_METHOD(Timeval, infPast) {
-#if PHP_MAJOR_VERSION < 7
-  zval *grpc_php_timeval_inf_past =
+  zval *grpc_php_timeval_inf_past;
+  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_past);
+  grpc_php_timeval_inf_past =
       grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
-#else
-  grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME), return_value);
-  RETURN_DESTROY_ZVAL(return_value);
-#endif
 }
 
 /**
@@ -350,12 +255,7 @@
  * @return void
  */
 PHP_METHOD(Timeval, sleepUntil) {
-#if PHP_MAJOR_VERSION < 7
-  wrapped_grpc_timeval *this =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
-#else
   wrapped_grpc_timeval *this = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
-#endif
   gpr_sleep_until(this->wrapped);
 }
 
@@ -378,13 +278,7 @@
   INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods);
   ce.create_object = create_wrapped_grpc_timeval;
   grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC);
-#if PHP_MAJOR_VERSION >= 7
-  memcpy(&timeval_ce_handlers, zend_get_std_object_handlers(),
-         sizeof(zend_object_handlers));
-  timeval_ce_handlers.offset =
-    XtOffsetOf(wrapped_grpc_timeval, std);
-  timeval_ce_handlers.free_obj = free_wrapped_grpc_timeval;
-#endif
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_timeval, timeval_ce_handlers);
 }
 
 void grpc_shutdown_timeval(TSRMLS_D) {}
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index d4eb2fa..63a1d70 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -50,27 +50,24 @@
 extern zend_class_entry *grpc_ce_timeval;
 
 /* Wrapper struct for timeval that can be associated with a PHP object */
+PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_timeval)
+  gpr_timespec wrapped;
+PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_timeval)
+
 #if PHP_MAJOR_VERSION < 7
 
-typedef struct wrapped_grpc_timeval {
-  zend_object std;
-  gpr_timespec wrapped;
-} wrapped_grpc_timeval;
+#define Z_WRAPPED_GRPC_TIMEVAL_P(zv) \
+  (wrapped_grpc_timeval *)zend_object_store_get_object(zv TSRMLS_CC)
 
 #else
 
-typedef struct wrapped_grpc_timeval {
-  gpr_timespec wrapped;
-  zend_object std;
-} wrapped_grpc_timeval;
-
 static inline wrapped_grpc_timeval
 *wrapped_grpc_timeval_from_obj(zend_object *obj) {
   return (wrapped_grpc_timeval*)((char*)(obj) -
                                  XtOffsetOf(wrapped_grpc_timeval, std));
 }
 
-#define Z_WRAPPED_GRPC_TIMEVAL_P(zv)            \
+#define Z_WRAPPED_GRPC_TIMEVAL_P(zv) \
   wrapped_grpc_timeval_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
@@ -82,10 +79,6 @@
 void grpc_shutdown_timeval(TSRMLS_D);
 
 /* Creates a Timeval object that wraps the given timeval struct */
-#if PHP_MAJOR_VERSION < 7
 zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC);
-#else
-void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object);
-#endif /* PHP_MAJOR_VERSION */
 
 #endif /* NET_GRPC_PHP_GRPC_TIMEVAL_H_ */
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index d1e2d41..c5c358c 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='1.0.0rc1'
+VERSION='1.0.0rc2'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 2e48fde..4bc1f3f 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION='1.0.0rc1'
+VERSION='1.0.0rc2'
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 727d628..6074175 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -50,6 +50,7 @@
 )
 
 INSTALL_REQUIRES = (
+    'protobuf>=3.0.0',
     'grpcio>=0.15.0',
 )
 
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index a238785..16e4eb8 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION='1.0.0rc1'
+VERSION='1.0.0rc2'
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 0afaf7d..5c60eac 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -63,7 +63,7 @@
     'grpcio>=0.14.0',
     'grpcio-health-checking>=0.14.0',
     'oauth2client>=1.4.7',
-    'protobuf>=3.0.0a3',
+    'protobuf>=3.0.0',
     'six>=1.10',
 )
 
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index 34bb477..0f61ccf 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -5,8 +5,8 @@
 AllCops:
   Exclude:
     - 'bin/apis/**/*'
-    - 'bin/math.rb'
-    - 'bin/math_services.rb'
+    - 'bin/math_pb.rb'
+    - 'bin/math_services_pb.rb'
     - 'pb/grpc/health/v1/*'
     - 'pb/test/**/*'
 
diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb
index d7e00e4..1f238a7 100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -40,7 +40,7 @@
 $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
 
 require 'grpc'
-require 'math_services'
+require 'math_services_pb'
 require 'optparse'
 
 include GRPC::Core::TimeConsts
diff --git a/src/ruby/bin/math.rb b/src/ruby/bin/math_pb.rb
old mode 100755
new mode 100644
similarity index 100%
rename from src/ruby/bin/math.rb
rename to src/ruby/bin/math_pb.rb
diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb
index 1ee4c56..751a6eb 100755
--- a/src/ruby/bin/math_server.rb
+++ b/src/ruby/bin/math_server.rb
@@ -42,7 +42,7 @@
 require 'forwardable'
 require 'grpc'
 require 'logger'
-require 'math_services'
+require 'math_services_pb'
 require 'optparse'
 
 # RubyLogger defines a logger for gRPC based on the standard ruby logger.
diff --git a/src/ruby/bin/math_services.rb b/src/ruby/bin/math_services_pb.rb
old mode 100755
new mode 100644
similarity index 92%
rename from src/ruby/bin/math_services.rb
rename to src/ruby/bin/math_services_pb.rb
index 34c36ab..2ba1825
--- a/src/ruby/bin/math_services.rb
+++ b/src/ruby/bin/math_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'math'
+require 'math_pb'
 
 module Math
   module Math
@@ -44,15 +44,15 @@
       self.unmarshal_class_method = :decode
       self.service_name = 'math.Math'
 
-      # Div divides args.dividend by args.divisor and returns the quotient and
-      # remainder.
+      # Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      # and remainder.
       rpc :Div, DivArgs, DivReply
       # DivMany accepts an arbitrary number of division args from the client stream
       # and sends back the results in the reply stream.  The stream continues until
       # the client closes its end; the server does the same after sending all the
       # replies.  The stream ends immediately if either end aborts.
       rpc :DivMany, stream(DivArgs), stream(DivReply)
-      # Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      # Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
       # generates up to limit numbers; otherwise it continues until the call is
       # canceled.  Unlike Fib above, Fib has no final FibReply.
       rpc :Fib, FibArgs, stream(Num)
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index e57fb3c..9e53780 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.0.0.pre1'
+  VERSION = '1.0.0.pre2'
 end
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index f7310d9..4bce174 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'grpc/health/v1/health_services'
+require 'grpc/health/v1/health_services_pb'
 require 'thread'
 
 module Grpc
diff --git a/src/ruby/pb/grpc/health/v1/health.rb b/src/ruby/pb/grpc/health/v1/health_pb.rb
similarity index 100%
rename from src/ruby/pb/grpc/health/v1/health.rb
rename to src/ruby/pb/grpc/health/v1/health_pb.rb
diff --git a/src/ruby/pb/grpc/health/v1/health_services.rb b/src/ruby/pb/grpc/health/v1/health_services_pb.rb
similarity index 97%
rename from src/ruby/pb/grpc/health/v1/health_services.rb
rename to src/ruby/pb/grpc/health/v1/health_services_pb.rb
index 68a3956..8cc01e9 100644
--- a/src/ruby/pb/grpc/health/v1/health_services.rb
+++ b/src/ruby/pb/grpc/health/v1/health_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'grpc/health/v1/health'
+require 'grpc/health/v1/health_pb'
 
 module Grpc
   module Health
diff --git a/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
similarity index 92%
rename from src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
rename to src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
index eb523ff..e51c2f0 100644
--- a/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
+++ b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: grpc/testing/duplicate/echo_duplicate.proto for package 'grpc.testing.duplicate'
+# Source: src/proto/grpc/testing/duplicate/echo_duplicate.proto for package 'grpc.testing.duplicate'
 # Original file comments:
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -34,7 +34,7 @@
 #
 
 require 'grpc'
-require 'grpc/testing/duplicate/echo_duplicate'
+require 'src/proto/grpc/testing/duplicate/echo_duplicate_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/grpc/testing/metrics.rb b/src/ruby/pb/grpc/testing/metrics_pb.rb
similarity index 94%
rename from src/ruby/pb/grpc/testing/metrics.rb
rename to src/ruby/pb/grpc/testing/metrics_pb.rb
index 3b3c8cd..77b6c90 100644
--- a/src/ruby/pb/grpc/testing/metrics.rb
+++ b/src/ruby/pb/grpc/testing/metrics_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: grpc/testing/metrics.proto
+# source: src/proto/grpc/testing/metrics.proto
 
 require 'google/protobuf'
 
diff --git a/src/ruby/pb/grpc/testing/metrics_services.rb b/src/ruby/pb/grpc/testing/metrics_services_pb.rb
similarity index 95%
rename from src/ruby/pb/grpc/testing/metrics_services.rb
rename to src/ruby/pb/grpc/testing/metrics_services_pb.rb
index 467b7b3..e46366b 100644
--- a/src/ruby/pb/grpc/testing/metrics_services.rb
+++ b/src/ruby/pb/grpc/testing/metrics_services_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: grpc/testing/metrics.proto for package 'grpc.testing'
+# Source: src/proto/grpc/testing/metrics.proto for package 'grpc.testing'
 # Original file comments:
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
@@ -38,7 +38,7 @@
 # service.
 
 require 'grpc'
-require 'grpc/testing/metrics'
+require 'src/proto/grpc/testing/metrics_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/src/proto/grpc/testing/empty.rb b/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb
similarity index 100%
rename from src/ruby/pb/src/proto/grpc/testing/empty.rb
rename to src/ruby/pb/src/proto/grpc/testing/empty_pb.rb
diff --git a/src/ruby/pb/src/proto/grpc/testing/messages.rb b/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
similarity index 88%
rename from src/ruby/pb/src/proto/grpc/testing/messages.rb
rename to src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
index 2bdfe0e..e27ccd0 100644
--- a/src/ruby/pb/src/proto/grpc/testing/messages.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
@@ -4,6 +4,9 @@
 require 'google/protobuf'
 
 Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "grpc.testing.BoolValue" do
+    optional :value, :bool, 1
+  end
   add_message "grpc.testing.Payload" do
     optional :type, :enum, 1, "grpc.testing.PayloadType"
     optional :body, :bytes, 2
@@ -18,8 +21,9 @@
     optional :payload, :message, 3, "grpc.testing.Payload"
     optional :fill_username, :bool, 4
     optional :fill_oauth_scope, :bool, 5
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+    optional :response_compressed, :message, 6, "grpc.testing.BoolValue"
     optional :response_status, :message, 7, "grpc.testing.EchoStatus"
+    optional :expect_compressed, :message, 8, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.SimpleResponse" do
     optional :payload, :message, 1, "grpc.testing.Payload"
@@ -28,6 +32,7 @@
   end
   add_message "grpc.testing.StreamingInputCallRequest" do
     optional :payload, :message, 1, "grpc.testing.Payload"
+    optional :expect_compressed, :message, 2, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.StreamingInputCallResponse" do
     optional :aggregated_payload_size, :int32, 1
@@ -35,12 +40,12 @@
   add_message "grpc.testing.ResponseParameters" do
     optional :size, :int32, 1
     optional :interval_us, :int32, 2
+    optional :compressed, :message, 3, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.StreamingOutputCallRequest" do
     optional :response_type, :enum, 1, "grpc.testing.PayloadType"
     repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
     optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
     optional :response_status, :message, 7, "grpc.testing.EchoStatus"
   end
   add_message "grpc.testing.StreamingOutputCallResponse" do
@@ -55,18 +60,12 @@
   end
   add_enum "grpc.testing.PayloadType" do
     value :COMPRESSABLE, 0
-    value :UNCOMPRESSABLE, 1
-    value :RANDOM, 2
-  end
-  add_enum "grpc.testing.CompressionType" do
-    value :NONE, 0
-    value :GZIP, 1
-    value :DEFLATE, 2
   end
 end
 
 module Grpc
   module Testing
+    BoolValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.BoolValue").msgclass
     Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
     EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
     SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
@@ -79,6 +78,5 @@
     ReconnectParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectParams").msgclass
     ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
     PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
-    CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
   end
 end
diff --git a/src/ruby/pb/src/proto/grpc/testing/test.rb b/src/ruby/pb/src/proto/grpc/testing/test_pb.rb
similarity index 72%
rename from src/ruby/pb/src/proto/grpc/testing/test.rb
rename to src/ruby/pb/src/proto/grpc/testing/test_pb.rb
index 245b5ce..2cc9863 100644
--- a/src/ruby/pb/src/proto/grpc/testing/test.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/test_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/empty'
-require 'src/proto/grpc/testing/messages'
+require 'src/proto/grpc/testing/empty_pb'
+require 'src/proto/grpc/testing/messages_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
 end
 
diff --git a/src/ruby/pb/src/proto/grpc/testing/test_services.rb b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
similarity index 98%
rename from src/ruby/pb/src/proto/grpc/testing/test_services.rb
rename to src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
index 2652de5..fde328e 100644
--- a/src/ruby/pb/src/proto/grpc/testing/test_services.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
@@ -35,7 +35,7 @@
 #
 
 require 'grpc'
-require 'src/proto/grpc/testing/test'
+require 'src/proto/grpc/testing/test_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 066a7bb..b9af160 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -52,9 +52,9 @@
 require 'googleauth'
 require 'google/protobuf'
 
-require_relative 'proto/empty'
-require_relative 'proto/messages'
-require_relative 'proto/test_services'
+require_relative '../src/proto/grpc/testing/empty_pb'
+require_relative '../src/proto/grpc/testing/messages_pb'
+require_relative '../src/proto/grpc/testing/test_services_pb'
 
 AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
 
diff --git a/src/ruby/pb/test/proto/empty.rb b/src/ruby/pb/test/proto/empty.rb
deleted file mode 100644
index 559adcc..0000000
--- a/src/ruby/pb/test/proto/empty.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/proto/empty.proto
-
-require 'google/protobuf'
-
-Google::Protobuf::DescriptorPool.generated_pool.build do
-  add_message "grpc.testing.Empty" do
-  end
-end
-
-module Grpc
-  module Testing
-    Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass
-  end
-end
diff --git a/src/ruby/pb/test/proto/messages.rb b/src/ruby/pb/test/proto/messages.rb
deleted file mode 100644
index 5222c98..0000000
--- a/src/ruby/pb/test/proto/messages.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/proto/messages.proto
-
-require 'google/protobuf'
-
-Google::Protobuf::DescriptorPool.generated_pool.build do
-  add_message "grpc.testing.Payload" do
-    optional :type, :enum, 1, "grpc.testing.PayloadType"
-    optional :body, :bytes, 2
-  end
-  add_message "grpc.testing.EchoStatus" do
-    optional :code, :int32, 1
-    optional :message, :string, 2
-  end
-  add_message "grpc.testing.SimpleRequest" do
-    optional :response_type, :enum, 1, "grpc.testing.PayloadType"
-    optional :response_size, :int32, 2
-    optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :fill_username, :bool, 4
-    optional :fill_oauth_scope, :bool, 5
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
-    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
-  end
-  add_message "grpc.testing.SimpleResponse" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-    optional :username, :string, 2
-    optional :oauth_scope, :string, 3
-  end
-  add_message "grpc.testing.StreamingInputCallRequest" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-  end
-  add_message "grpc.testing.StreamingInputCallResponse" do
-    optional :aggregated_payload_size, :int32, 1
-  end
-  add_message "grpc.testing.ResponseParameters" do
-    optional :size, :int32, 1
-    optional :interval_us, :int32, 2
-  end
-  add_message "grpc.testing.StreamingOutputCallRequest" do
-    optional :response_type, :enum, 1, "grpc.testing.PayloadType"
-    repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
-    optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
-    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
-  end
-  add_message "grpc.testing.StreamingOutputCallResponse" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-  end
-  add_message "grpc.testing.ReconnectInfo" do
-    optional :passed, :bool, 1
-    repeated :backoff_ms, :int32, 2
-  end
-  add_enum "grpc.testing.PayloadType" do
-    value :COMPRESSABLE, 0
-    value :UNCOMPRESSABLE, 1
-    value :RANDOM, 2
-  end
-  add_enum "grpc.testing.CompressionType" do
-    value :NONE, 0
-    value :GZIP, 1
-    value :DEFLATE, 2
-  end
-end
-
-module Grpc
-  module Testing
-    Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
-    EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
-    SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
-    SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass
-    StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass
-    StreamingInputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallResponse").msgclass
-    ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass
-    StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass
-    StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
-    ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
-    PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
-    CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
-  end
-end
diff --git a/src/ruby/pb/test/proto/test.rb b/src/ruby/pb/test/proto/test.rb
deleted file mode 100644
index 100eb65..0000000
--- a/src/ruby/pb/test/proto/test.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: test/proto/test.proto
-
-require 'google/protobuf'
-
-require 'test/proto/empty'
-require 'test/proto/messages'
-Google::Protobuf::DescriptorPool.generated_pool.build do
-end
-
-module Grpc
-  module Testing
-  end
-end
diff --git a/src/ruby/pb/test/proto/test_services.rb b/src/ruby/pb/test/proto/test_services.rb
deleted file mode 100644
index 9df9cc5..0000000
--- a/src/ruby/pb/test/proto/test_services.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: test/proto/test.proto for package 'grpc.testing'
-
-require 'grpc'
-require 'test/proto/test'
-
-module Grpc
-  module Testing
-    module TestService
-
-      # TODO: add proto service documentation here
-      class Service
-
-        include GRPC::GenericService
-
-        self.marshal_class_method = :encode
-        self.unmarshal_class_method = :decode
-        self.service_name = 'grpc.testing.TestService'
-
-        rpc :EmptyCall, Empty, Empty
-        rpc :UnaryCall, SimpleRequest, SimpleResponse
-        rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
-        rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse
-        rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
-        rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
-      end
-
-      Stub = Service.rpc_stub_class
-    end
-    module UnimplementedService
-
-      # TODO: add proto service documentation here
-      class Service
-
-        include GRPC::GenericService
-
-        self.marshal_class_method = :encode
-        self.unmarshal_class_method = :decode
-        self.service_name = 'grpc.testing.UnimplementedService'
-
-        rpc :UnimplementedCall, Empty, Empty
-      end
-
-      Stub = Service.rpc_stub_class
-    end
-    module ReconnectService
-
-      # TODO: add proto service documentation here
-      class Service
-
-        include GRPC::GenericService
-
-        self.marshal_class_method = :encode
-        self.unmarshal_class_method = :decode
-        self.service_name = 'grpc.testing.ReconnectService'
-
-        rpc :Start, Empty, Empty
-        rpc :Stop, Empty, ReconnectInfo
-      end
-
-      Stub = Service.rpc_stub_class
-    end
-  end
-end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 088f281..0808121 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -50,9 +50,9 @@
 
 require 'grpc'
 
-require 'test/proto/empty'
-require 'test/proto/messages'
-require 'test/proto/test_services'
+require_relative '../src/proto/grpc/testing/empty_pb'
+require_relative '../src/proto/grpc/testing/messages_pb'
+require_relative '../src/proto/grpc/testing/test_services_pb'
 
 # DebugIsTruncated extends the default Logger to truncate debug messages
 class DebugIsTruncated < Logger
diff --git a/src/ruby/qps/client.rb b/src/ruby/qps/client.rb
index 917b012..7ed648a 100644
--- a/src/ruby/qps/client.rb
+++ b/src/ruby/qps/client.rb
@@ -38,7 +38,7 @@
 
 require 'grpc'
 require 'histogram'
-require 'src/proto/grpc/testing/services_services'
+require 'src/proto/grpc/testing/services_services_pb'
 
 class Poisson
   def interarrival
diff --git a/src/ruby/qps/server.rb b/src/ruby/qps/server.rb
index 52a89ce..cd98ee1 100644
--- a/src/ruby/qps/server.rb
+++ b/src/ruby/qps/server.rb
@@ -38,9 +38,9 @@
 
 require 'grpc'
 require 'qps-common'
-require 'src/proto/grpc/testing/messages'
-require 'src/proto/grpc/testing/services_services'
-require 'src/proto/grpc/testing/stats'
+require 'src/proto/grpc/testing/messages_pb'
+require 'src/proto/grpc/testing/services_services_pb'
+require 'src/proto/grpc/testing/stats_pb'
 
 class BenchmarkServiceImpl < Grpc::Testing::BenchmarkService::Service
   def unary_call(req, _call)
diff --git a/src/ruby/qps/src/proto/grpc/testing/control.rb b/src/ruby/qps/src/proto/grpc/testing/control_pb.rb
similarity index 97%
rename from src/ruby/qps/src/proto/grpc/testing/control.rb
rename to src/ruby/qps/src/proto/grpc/testing/control_pb.rb
index 958fca3..02207a2 100644
--- a/src/ruby/qps/src/proto/grpc/testing/control.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/control_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/payloads'
-require 'src/proto/grpc/testing/stats'
+require 'src/proto/grpc/testing/payloads_pb'
+require 'src/proto/grpc/testing/stats_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_message "grpc.testing.PoissonParams" do
     optional :offered_load, :double, 1
@@ -109,6 +109,8 @@
     repeated :server_stats, :message, 4, "grpc.testing.ServerStats"
     repeated :server_cores, :int32, 5
     optional :summary, :message, 6, "grpc.testing.ScenarioResultSummary"
+    repeated :client_success, :bool, 7
+    repeated :server_success, :bool, 8
   end
   add_enum "grpc.testing.ClientType" do
     value :SYNC_CLIENT, 0
diff --git a/src/ruby/qps/src/proto/grpc/testing/messages.rb b/src/ruby/qps/src/proto/grpc/testing/messages.rb
deleted file mode 100644
index 2bdfe0e..0000000
--- a/src/ruby/qps/src/proto/grpc/testing/messages.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: src/proto/grpc/testing/messages.proto
-
-require 'google/protobuf'
-
-Google::Protobuf::DescriptorPool.generated_pool.build do
-  add_message "grpc.testing.Payload" do
-    optional :type, :enum, 1, "grpc.testing.PayloadType"
-    optional :body, :bytes, 2
-  end
-  add_message "grpc.testing.EchoStatus" do
-    optional :code, :int32, 1
-    optional :message, :string, 2
-  end
-  add_message "grpc.testing.SimpleRequest" do
-    optional :response_type, :enum, 1, "grpc.testing.PayloadType"
-    optional :response_size, :int32, 2
-    optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :fill_username, :bool, 4
-    optional :fill_oauth_scope, :bool, 5
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
-    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
-  end
-  add_message "grpc.testing.SimpleResponse" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-    optional :username, :string, 2
-    optional :oauth_scope, :string, 3
-  end
-  add_message "grpc.testing.StreamingInputCallRequest" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-  end
-  add_message "grpc.testing.StreamingInputCallResponse" do
-    optional :aggregated_payload_size, :int32, 1
-  end
-  add_message "grpc.testing.ResponseParameters" do
-    optional :size, :int32, 1
-    optional :interval_us, :int32, 2
-  end
-  add_message "grpc.testing.StreamingOutputCallRequest" do
-    optional :response_type, :enum, 1, "grpc.testing.PayloadType"
-    repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
-    optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
-    optional :response_status, :message, 7, "grpc.testing.EchoStatus"
-  end
-  add_message "grpc.testing.StreamingOutputCallResponse" do
-    optional :payload, :message, 1, "grpc.testing.Payload"
-  end
-  add_message "grpc.testing.ReconnectParams" do
-    optional :max_reconnect_backoff_ms, :int32, 1
-  end
-  add_message "grpc.testing.ReconnectInfo" do
-    optional :passed, :bool, 1
-    repeated :backoff_ms, :int32, 2
-  end
-  add_enum "grpc.testing.PayloadType" do
-    value :COMPRESSABLE, 0
-    value :UNCOMPRESSABLE, 1
-    value :RANDOM, 2
-  end
-  add_enum "grpc.testing.CompressionType" do
-    value :NONE, 0
-    value :GZIP, 1
-    value :DEFLATE, 2
-  end
-end
-
-module Grpc
-  module Testing
-    Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
-    EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
-    SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
-    SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass
-    StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass
-    StreamingInputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallResponse").msgclass
-    ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass
-    StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass
-    StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass
-    ReconnectParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectParams").msgclass
-    ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
-    PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
-    CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
-  end
-end
diff --git a/src/ruby/pb/src/proto/grpc/testing/messages.rb b/src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
similarity index 88%
copy from src/ruby/pb/src/proto/grpc/testing/messages.rb
copy to src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
index 2bdfe0e..e27ccd0 100644
--- a/src/ruby/pb/src/proto/grpc/testing/messages.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
@@ -4,6 +4,9 @@
 require 'google/protobuf'
 
 Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "grpc.testing.BoolValue" do
+    optional :value, :bool, 1
+  end
   add_message "grpc.testing.Payload" do
     optional :type, :enum, 1, "grpc.testing.PayloadType"
     optional :body, :bytes, 2
@@ -18,8 +21,9 @@
     optional :payload, :message, 3, "grpc.testing.Payload"
     optional :fill_username, :bool, 4
     optional :fill_oauth_scope, :bool, 5
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
+    optional :response_compressed, :message, 6, "grpc.testing.BoolValue"
     optional :response_status, :message, 7, "grpc.testing.EchoStatus"
+    optional :expect_compressed, :message, 8, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.SimpleResponse" do
     optional :payload, :message, 1, "grpc.testing.Payload"
@@ -28,6 +32,7 @@
   end
   add_message "grpc.testing.StreamingInputCallRequest" do
     optional :payload, :message, 1, "grpc.testing.Payload"
+    optional :expect_compressed, :message, 2, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.StreamingInputCallResponse" do
     optional :aggregated_payload_size, :int32, 1
@@ -35,12 +40,12 @@
   add_message "grpc.testing.ResponseParameters" do
     optional :size, :int32, 1
     optional :interval_us, :int32, 2
+    optional :compressed, :message, 3, "grpc.testing.BoolValue"
   end
   add_message "grpc.testing.StreamingOutputCallRequest" do
     optional :response_type, :enum, 1, "grpc.testing.PayloadType"
     repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters"
     optional :payload, :message, 3, "grpc.testing.Payload"
-    optional :response_compression, :enum, 6, "grpc.testing.CompressionType"
     optional :response_status, :message, 7, "grpc.testing.EchoStatus"
   end
   add_message "grpc.testing.StreamingOutputCallResponse" do
@@ -55,18 +60,12 @@
   end
   add_enum "grpc.testing.PayloadType" do
     value :COMPRESSABLE, 0
-    value :UNCOMPRESSABLE, 1
-    value :RANDOM, 2
-  end
-  add_enum "grpc.testing.CompressionType" do
-    value :NONE, 0
-    value :GZIP, 1
-    value :DEFLATE, 2
   end
 end
 
 module Grpc
   module Testing
+    BoolValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.BoolValue").msgclass
     Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass
     EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass
     SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass
@@ -79,6 +78,5 @@
     ReconnectParams = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectParams").msgclass
     ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass
     PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule
-    CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule
   end
 end
diff --git a/src/ruby/qps/src/proto/grpc/testing/payloads.rb b/src/ruby/qps/src/proto/grpc/testing/payloads_pb.rb
similarity index 100%
rename from src/ruby/qps/src/proto/grpc/testing/payloads.rb
rename to src/ruby/qps/src/proto/grpc/testing/payloads_pb.rb
diff --git a/src/ruby/qps/src/proto/grpc/testing/services.rb b/src/ruby/qps/src/proto/grpc/testing/services_pb.rb
similarity index 72%
rename from src/ruby/qps/src/proto/grpc/testing/services.rb
rename to src/ruby/qps/src/proto/grpc/testing/services_pb.rb
index b2675c2..5ce13bf 100644
--- a/src/ruby/qps/src/proto/grpc/testing/services.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/services_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/messages'
-require 'src/proto/grpc/testing/control'
+require 'src/proto/grpc/testing/messages_pb'
+require 'src/proto/grpc/testing/control_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
 end
 
diff --git a/src/ruby/qps/src/proto/grpc/testing/services_services.rb b/src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
similarity index 98%
rename from src/ruby/qps/src/proto/grpc/testing/services_services.rb
rename to src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
index 94b9a1e..bdbb9c8 100644
--- a/src/ruby/qps/src/proto/grpc/testing/services_services.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
@@ -34,7 +34,7 @@
 # of unary/streaming requests/responses.
 
 require 'grpc'
-require 'src/proto/grpc/testing/services'
+require 'src/proto/grpc/testing/services_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/qps/src/proto/grpc/testing/stats.rb b/src/ruby/qps/src/proto/grpc/testing/stats_pb.rb
similarity index 100%
rename from src/ruby/qps/src/proto/grpc/testing/stats.rb
rename to src/ruby/qps/src/proto/grpc/testing/stats_pb.rb
diff --git a/src/ruby/qps/worker.rb b/src/ruby/qps/worker.rb
index 665fb86..12b8087 100755
--- a/src/ruby/qps/worker.rb
+++ b/src/ruby/qps/worker.rb
@@ -44,7 +44,7 @@
 require 'client'
 require 'qps-common'
 require 'server'
-require 'src/proto/grpc/testing/services_services'
+require 'src/proto/grpc/testing/services_services_pb'
 
 class WorkerServiceImpl < Grpc::Testing::WorkerService::Service
   def cpu_cores
diff --git a/src/ruby/spec/pb/duplicate/codegen_spec.rb b/src/ruby/spec/pb/duplicate/codegen_spec.rb
index 54c136c..ea02409 100644
--- a/src/ruby/spec/pb/duplicate/codegen_spec.rb
+++ b/src/ruby/spec/pb/duplicate/codegen_spec.rb
@@ -44,7 +44,7 @@
       # Get the current content
       service_path = File.join(root_dir, 'src', 'ruby', 'pb', 'grpc',
                                'testing', 'duplicate',
-                               'echo_duplicate_services.rb')
+                               'echo_duplicate_services_pb.rb')
       want = nil
       File.open(service_path) { |f| want = f.read }
 
@@ -54,7 +54,7 @@
       got = nil
       Dir.mktmpdir do |tmp_dir|
         gen_out = File.join(tmp_dir, 'src', 'proto', 'grpc', 'testing',
-                            'duplicate', 'echo_duplicate_services.rb')
+                            'duplicate', 'echo_duplicate_services_pb.rb')
         pid = spawn(
           'protoc',
           '-I.',
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index de11c9f..1b2fa96 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'grpc/health/v1/health'
+require 'grpc/health/v1/health_pb'
 require 'grpc/health/checker'
 require 'open3'
 require 'tmpdir'
@@ -43,7 +43,7 @@
       skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen'
     else
       it 'should already be loaded indirectly i.e, used by the other specs' do
-        expect(require('grpc/health/v1/health_services')).to be(false)
+        expect(require('grpc/health/v1/health_services_pb')).to be(false)
       end
 
       it 'should have the same content as created by code generation' do
@@ -52,7 +52,7 @@
 
         # Get the current content
         service_path = File.join(root_dir, 'ruby', 'pb', 'grpc',
-                                 'health', 'v1', 'health_services.rb')
+                                 'health', 'v1', 'health_services_pb.rb')
         want = nil
         File.open(service_path) { |f| want = f.read }
 
@@ -62,7 +62,7 @@
         got = nil
         Dir.mktmpdir do |tmp_dir|
           gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1',
-                              'health_services.rb')
+                              'health_services_pb.rb')
           pid = spawn(
             'protoc',
             '-I.',
diff --git a/src/ruby/stress/metrics_server.rb b/src/ruby/stress/metrics_server.rb
index 13638c4..2b7f785 100644
--- a/src/ruby/stress/metrics_server.rb
+++ b/src/ruby/stress/metrics_server.rb
@@ -27,8 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require_relative '../pb/grpc/testing/metrics.rb'
-require_relative '../pb/grpc/testing/metrics_services.rb'
+require_relative '../pb/grpc/testing/metrics_pb.rb'
+require_relative '../pb/grpc/testing/metrics_services_pb.rb'
 
 class Gauge
   def get_name
diff --git a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb b/src/ruby/tools/bin/grpc_tools_ruby_protoc
similarity index 79%
rename from src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
rename to src/ruby/tools/bin/grpc_tools_ruby_protoc
index 3a2a5b8..dab06e7 100755
--- a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
+++ b/src/ruby/tools/bin/grpc_tools_ruby_protoc
@@ -32,10 +32,17 @@
 
 require_relative '../os_check'
 
-protoc_name = 'protoc' + RbConfig::CONFIG['EXEEXT']
+ext = RbConfig::CONFIG['EXEEXT']
 
-protoc_path = File.join(File.dirname(__FILE__),
-                        RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name,
-                        protoc_name)
+protoc_name = 'protoc' + ext
 
-exec([ protoc_path, protoc_path ], *ARGV)
+plugin_name = 'grpc_ruby_plugin' + ext
+
+protoc_dir = File.join(File.dirname(__FILE__),
+                       RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name)
+
+protoc_path = File.join(protoc_dir, protoc_name)
+
+plugin_path = File.join(protoc_dir, plugin_name)
+
+exec([ protoc_path, protoc_path ], "--plugin=protoc-gen-grpc=#{plugin_path}", *ARGV)
diff --git a/src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin.rb b/src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin
similarity index 100%
rename from src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin.rb
rename to src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin
diff --git a/src/ruby/tools/grpc-tools.gemspec b/src/ruby/tools/grpc-tools.gemspec
index 9fa4b66..68e2a7a 100644
--- a/src/ruby/tools/grpc-tools.gemspec
+++ b/src/ruby/tools/grpc-tools.gemspec
@@ -18,5 +18,5 @@
 
   s.platform = Gem::Platform::RUBY
 
-  s.executables = %w( grpc_tools_ruby_protoc.rb grpc_tools_ruby_protoc_plugin.rb )
+  s.executables = %w( grpc_tools_ruby_protoc grpc_tools_ruby_protoc_plugin )
 end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 2e318b8..84c03b2 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.0.0.pre1'
+    VERSION = '1.0.0.pre2'
   end
 end
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 76c6fff..87b1038 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
     <email>grpc-packages@google.com</email>
     <active>yes</active>
    </lead>
-   <date>2016-07-21</date>
+   <date>2016-07-28</date>
    <time>16:06:07</time>
    <version>
     <release>${settings.php_version.php()}</release>
@@ -24,7 +24,7 @@
    </stability>
    <license>BSD</license>
    <notes>
-  - PHP7 Support #7464
+  - PHP7 Support continued, reduce code duplication #7543
    </notes>
    <contents>
     <dir baseinstalldir="/" name="/">
@@ -234,5 +234,20 @@
   - PHP7 Support #7464
      </notes>
     </release>
+    <release>
+     <version>
+      <release>1.0.0RC3</release>
+      <api>1.0.0RC3</api>
+     </version>
+     <stability>
+      <release>stable</release>
+      <api>stable</api>
+     </stability>
+     <date>2016-07-28</date>
+     <license>BSD</license>
+     <notes>
+  - PHP7 Support continued, reduce code duplication #7543
+     </notes>
+    </release>
    </changelog>
   </package>
diff --git a/templates/src/csharp/Grpc.Auth/project.json.template b/templates/src/csharp/Grpc.Auth/project.json.template
index d91bd8c..b3244e4 100644
--- a/templates/src/csharp/Grpc.Auth/project.json.template
+++ b/templates/src/csharp/Grpc.Auth/project.json.template
@@ -34,9 +34,9 @@
           "net45"
         ],
         "dependencies": {
-          "Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027",
-          "NETStandard.Library": "1.5.0-rc2-24027",
-          "System.Threading.Tasks": "4.0.11-rc2-24027"
+          "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
+          "NETStandard.Library": "1.6.0",
+          "System.Threading.Tasks": "4.0.11"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.Core.Tests/project.json.template b/templates/src/csharp/Grpc.Core.Tests/project.json.template
index bc9fa3e..3452d6b 100644
--- a/templates/src/csharp/Grpc.Core.Tests/project.json.template
+++ b/templates/src/csharp/Grpc.Core.Tests/project.json.template
@@ -8,16 +8,20 @@
       },
       "Newtonsoft.Json": "8.0.3",
       "NUnit": "3.2.0",
-      "NUnitLite": "3.2.0-*"
+      "NUnitLite": "3.2.0-*",
+      "NUnit.ConsoleRunner": "3.2.0",
+      "OpenCover": "4.6.519",
+      "ReportGenerator": "2.4.4.0"
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     },
diff --git a/templates/src/csharp/Grpc.Core/project.json.template b/templates/src/csharp/Grpc.Core/project.json.template
index 6355db5..bd0e8b2 100644
--- a/templates/src/csharp/Grpc.Core/project.json.template
+++ b/templates/src/csharp/Grpc.Core/project.json.template
@@ -42,8 +42,8 @@
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027",
-          "System.Threading.Thread": "4.0.0-rc2-24027"
+          "NETStandard.Library": "1.6.0",
+          "System.Threading.Thread": "4.0.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
index fba401c..67151db 100644
--- a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
+++ b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
@@ -9,12 +9,13 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
index fba401c..67151db 100644
--- a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
+++ b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
@@ -9,12 +9,13 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.Examples.Tests/project.json.template b/templates/src/csharp/Grpc.Examples.Tests/project.json.template
index 21765f0..af13cb5 100644
--- a/templates/src/csharp/Grpc.Examples.Tests/project.json.template
+++ b/templates/src/csharp/Grpc.Examples.Tests/project.json.template
@@ -11,12 +11,13 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.Examples/project.json.template b/templates/src/csharp/Grpc.Examples/project.json.template
index 715fc08..d5d63f6 100644
--- a/templates/src/csharp/Grpc.Examples/project.json.template
+++ b/templates/src/csharp/Grpc.Examples/project.json.template
@@ -20,7 +20,7 @@
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template b/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
index 79e6722..417b773 100644
--- a/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
+++ b/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
@@ -11,12 +11,13 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.HealthCheck/project.json.template b/templates/src/csharp/Grpc.HealthCheck/project.json.template
index 264ed29..cd2da00 100644
--- a/templates/src/csharp/Grpc.HealthCheck/project.json.template
+++ b/templates/src/csharp/Grpc.HealthCheck/project.json.template
@@ -39,7 +39,7 @@
           "portable-net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
index 10ed549..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
@@ -9,13 +9,14 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45",
           "net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
index 10ed549..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
@@ -9,13 +9,14 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45",
           "net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
index 10ed549..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
@@ -9,13 +9,14 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45",
           "net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
index 10ed549..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
@@ -9,13 +9,14 @@
     },
     "frameworks": {
       "net45": { },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45",
           "net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0"
         }
       }
     }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
index 3181511..0a7d5e9 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
@@ -24,14 +24,15 @@
           "System.IO": ""
         }
       },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45",
           "net45"
         ],
         "dependencies": {
-          "NETStandard.Library": "1.5.0-rc2-24027",
-          "System.Linq.Expressions": "4.0.11-rc2-24027"
+          "Microsoft.NETCore.App": "1.0.0",
+          "NETStandard.Library": "1.6.0",
+          "System.Linq.Expressions": "4.1.0"
         }
       }
     }
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
index 476f9d3..f37eada 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
@@ -1,6 +1,6 @@
 %YAML 1.2
 --- |
-  # Copyright 2015, Google Inc.
+  # Copyright 2016, Google Inc.
   # All rights reserved.
   #
   # Redistribution and use in source and binary forms, with or without
@@ -35,30 +35,5 @@
   <%include file="../../ruby_deps.include"/>
   <%include file="../../php_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
-  # ronn: a ruby tool used to convert markdown to man pages, used during the
-  # install of Protobuf extensions
-  #
-  # rake: a ruby version of make used to build the PHP Protobuf extension
-  RUN /bin/bash -l -c "rvm all do gem install ronn rake"
-  
-  # Install composer
-  RUN curl -sS https://getcomposer.org/installer | php
-  RUN mv composer.phar /usr/local/bin/composer
-  
-  # As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
-  # into composer cache to prevent "composer install" from cloning on each build.
-  RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git ${'\\'}
-    /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
-  
-  # Download the patched PHP protobuf so that PHP gRPC clients can be generated
-  # from proto3 schemas.
-  RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
-  
-  RUN /bin/bash -l -c "rvm use ruby-2.1 ${'\\'}
-    && cd /var/local/git/protobuf-php ${'\\'}
-    && rvm all do rake pear:package version=1.0 ${'\\'}
-    && pear install Protobuf-1.0.tgz"
-  
-  # Define the default command.
-  CMD ["bash"]
+  <%include file="../../php_common_deps.include"/>
   
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile.template
new file mode 100644
index 0000000..42157ee
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+  # Copyright 2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../php7_deps.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  <%include file="../../php_common_deps.include"/>
diff --git a/templates/tools/dockerfile/php7_deps.include b/templates/tools/dockerfile/php7_deps.include
new file mode 100644
index 0000000..a24e506
--- /dev/null
+++ b/templates/tools/dockerfile/php7_deps.include
@@ -0,0 +1,45 @@
+#=================
+# PHP7 dependencies
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y ${'\\'}
+  autoconf ${'\\'}
+  automake ${'\\'}
+  build-essential ${'\\'}
+  ccache ${'\\'}
+  curl ${'\\'}
+  git ${'\\'}
+  libcurl4-openssl-dev ${'\\'}
+  libgmp-dev ${'\\'}
+  libgmp3-dev ${'\\'}
+  libssl-dev ${'\\'}
+  libtool ${'\\'}
+  libxml2-dev ${'\\'}
+  pkg-config ${'\\'}
+  re2c ${'\\'}
+  time ${'\\'}
+  unzip ${'\\'}
+  wget ${'\\'}
+  zip && apt-get clean
+
+# Install other dependencies
+RUN ln -sf /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h
+RUN wget http://ftp.gnu.org/gnu/bison/bison-2.6.4.tar.gz -O /var/local/bison-2.6.4.tar.gz
+RUN cd /var/local ${'\\'}
+  && tar -zxvf bison-2.6.4.tar.gz ${'\\'}
+  && cd /var/local/bison-2.6.4 ${'\\'}
+  && ./configure ${'\\'}
+  && make ${'\\'}
+  && make install
+
+# Compile PHP7 from source
+RUN git clone https://github.com/php/php-src /var/local/git/php-src
+RUN cd /var/local/git/php-src ${'\\'}
+  && git checkout PHP-7.0.9 ${'\\'}
+  && ./buildconf --force ${'\\'}
+  && ./configure ${'\\'}
+  --with-gmp ${'\\'}
+  --with-openssl ${'\\'}
+  --with-zlib ${'\\'}
+  && make ${'\\'}
+  && make install
diff --git a/templates/tools/dockerfile/php_common_deps.include b/templates/tools/dockerfile/php_common_deps.include
new file mode 100644
index 0000000..8839bb5
--- /dev/null
+++ b/templates/tools/dockerfile/php_common_deps.include
@@ -0,0 +1,21 @@
+# ronn: a ruby tool used to convert markdown to man pages, used during the
+# install of Protobuf extensions
+#
+# rake: a ruby version of make used to build the PHP Protobuf extension
+RUN /bin/bash -l -c "rvm all do gem install ronn rake"
+
+# Install composer
+RUN curl -sS https://getcomposer.org/installer | php
+RUN mv composer.phar /usr/local/bin/composer
+
+# Download the patched PHP protobuf so that PHP gRPC clients can be generated
+# from proto3 schemas.
+RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
+
+RUN /bin/bash -l -c "rvm use ruby-2.1 ${'\\'}
+  && cd /var/local/git/protobuf-php ${'\\'}
+  && rvm all do rake pear:package version=1.0 ${'\\'}
+  && pear install Protobuf-1.0.tgz"
+
+# Define the default command.
+CMD ["bash"]
diff --git a/templates/tools/dockerfile/php_deps.include b/templates/tools/dockerfile/php_deps.include
index 739049b..da071e2 100644
--- a/templates/tools/dockerfile/php_deps.include
+++ b/templates/tools/dockerfile/php_deps.include
@@ -3,11 +3,5 @@
 
 # Install dependencies
 
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
 RUN apt-get update && apt-get install -y ${'\\'}
     git php5 php5-dev phpunit unzip
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
index 4cd069d..df61808 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
@@ -46,11 +46,6 @@
   RUN curl -sS https://getcomposer.org/installer | php
   RUN mv composer.phar /usr/local/bin/composer
   
-  # As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
-  # into composer cache to prevent "composer install" from cloning on each build.
-  RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git ${'\\'}
-    /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
-  
   # Download the patched PHP protobuf so that PHP gRPC clients can be generated
   # from proto3 schemas.
   RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
diff --git a/templates/tools/dockerfile/test/php7_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/php7_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..e6a213d
--- /dev/null
+++ b/templates/tools/dockerfile/test/php7_jessie_x64/Dockerfile.template
@@ -0,0 +1,38 @@
+%YAML 1.2
+--- |
+  # Copyright 2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../php7_deps.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc
index 778a2be..b967a5d 100644
--- a/test/cpp/end2end/server_builder_plugin_test.cc
+++ b/test/cpp/end2end/server_builder_plugin_test.cc
@@ -191,7 +191,7 @@
     // we run some tests without a service, and for those we need to supply a
     // frequently polled completion queue
     cq_ = builder_->AddCompletionQueue();
-    cq_thread_ = grpc::thread(std::bind(&ServerBuilderPluginTest::RunCQ, this));
+    cq_thread_ = new grpc::thread(&ServerBuilderPluginTest::RunCQ, this);
     server_ = builder_->BuildAndStart();
     EXPECT_TRUE(CheckPresent());
   }
@@ -209,7 +209,8 @@
     EXPECT_TRUE(plugin->finish_is_called());
     server_->Shutdown();
     cq_->Shutdown();
-    cq_thread_.join();
+    cq_thread_->join();
+    delete cq_thread_;
   }
 
   string to_string(const int number) {
@@ -224,7 +225,7 @@
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::unique_ptr<ServerCompletionQueue> cq_;
   std::unique_ptr<Server> server_;
-  grpc::thread cq_thread_;
+  grpc::thread* cq_thread_;
   TestServiceImpl service_;
   int port_;
 
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 7938b3d..91f6849 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION='1.0.0rc1'
+VERSION='1.0.0rc2'
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index 8082c7a..43d0f55 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -148,7 +148,7 @@
   packages=setuptools.find_packages('.'),
   namespace_packages=['grpc'],
   install_requires=[
-    'protobuf>=3.0.0a3',
+    'protobuf>=3.0.0',
     'grpcio>=0.15.0',
   ],
   package_data=package_data(),
diff --git a/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
index af83ee6..0d6171c 100644
--- a/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -83,12 +83,6 @@
 
 # Install dependencies
 
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
@@ -113,11 +107,6 @@
 RUN curl -sS https://getcomposer.org/installer | php
 RUN mv composer.phar /usr/local/bin/composer
 
-# As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
-# into composer cache to prevent "composer install" from cloning on each build.
-RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git \
-  /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
-
 # Download the patched PHP protobuf so that PHP gRPC clients can be generated
 # from proto3 schemas.
 RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
@@ -129,3 +118,4 @@
 
 # Define the default command.
 CMD ["bash"]
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile
new file mode 100644
index 0000000..be8f25f
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile
@@ -0,0 +1,125 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM debian:jessie
+
+#=================
+# PHP7 dependencies
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  automake \
+  build-essential \
+  ccache \
+  curl \
+  git \
+  libcurl4-openssl-dev \
+  libgmp-dev \
+  libgmp3-dev \
+  libssl-dev \
+  libtool \
+  libxml2-dev \
+  pkg-config \
+  re2c \
+  time \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+# Install other dependencies
+RUN ln -sf /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h
+RUN wget http://ftp.gnu.org/gnu/bison/bison-2.6.4.tar.gz -O /var/local/bison-2.6.4.tar.gz
+RUN cd /var/local \
+  && tar -zxvf bison-2.6.4.tar.gz \
+  && cd /var/local/bison-2.6.4 \
+  && ./configure \
+  && make \
+  && make install
+
+# Compile PHP7 from source
+RUN git clone https://github.com/php/php-src /var/local/git/php-src
+RUN cd /var/local/git/php-src \
+  && git checkout PHP-7.0.9 \
+  && ./buildconf --force \
+  && ./configure \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  && make \
+  && make install
+
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+
+RUN mkdir /var/local/jenkins
+
+# ronn: a ruby tool used to convert markdown to man pages, used during the
+# install of Protobuf extensions
+#
+# rake: a ruby version of make used to build the PHP Protobuf extension
+RUN /bin/bash -l -c "rvm all do gem install ronn rake"
+
+# Install composer
+RUN curl -sS https://getcomposer.org/installer | php
+RUN mv composer.phar /usr/local/bin/composer
+
+# Download the patched PHP protobuf so that PHP gRPC clients can be generated
+# from proto3 schemas.
+RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
+
+RUN /bin/bash -l -c "rvm use ruby-2.1 \
+  && cd /var/local/git/protobuf-php \
+  && rvm all do rake pear:package version=1.0 \
+  && pear install Protobuf-1.0.tgz"
+
+# Define the default command.
+CMD ["bash"]
+
diff --git a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
similarity index 71%
copy from src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
copy to tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
index 3a2a5b8..261dded 100755
--- a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
+++ b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -27,15 +27,26 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Builds PHP interop server and client in a base image.
+set -ex
 
-require 'rbconfig'
+mkdir -p /var/local/git
+git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
 
-require_relative '../os_check'
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
 
-protoc_name = 'protoc' + RbConfig::CONFIG['EXEEXT']
+cd /var/local/git/grpc
+rvm --default use ruby-2.1
 
-protoc_path = File.join(File.dirname(__FILE__),
-                        RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name,
-                        protoc_name)
+# gRPC core and protobuf need to be installed
+make install
 
-exec([ protoc_path, protoc_path ], *ARGV)
+(cd src/php/ext/grpc && phpize && ./configure && make)
+
+(cd third_party/protobuf && make install)
+
+(cd src/php && composer install)
+
+(cd src/php && protoc-gen-php -i tests/interop/ -o tests/interop/ tests/interop/test.proto)
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
index 3092bd9..13afa15 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
@@ -88,12 +88,6 @@
 
 # Install dependencies
 
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
@@ -118,11 +112,6 @@
 RUN curl -sS https://getcomposer.org/installer | php
 RUN mv composer.phar /usr/local/bin/composer
 
-# As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
-# into composer cache to prevent "composer install" from cloning on each build.
-RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git \
-  /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
-
 # Download the patched PHP protobuf so that PHP gRPC clients can be generated
 # from proto3 schemas.
 RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index bd77285..8790b0d 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -100,12 +100,6 @@
 
 # Install dependencies
 
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
new file mode 100644
index 0000000..c0b394e
--- /dev/null
+++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -0,0 +1,105 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM debian:jessie
+
+#=================
+# PHP7 dependencies
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  automake \
+  build-essential \
+  ccache \
+  curl \
+  git \
+  libcurl4-openssl-dev \
+  libgmp-dev \
+  libgmp3-dev \
+  libssl-dev \
+  libtool \
+  libxml2-dev \
+  pkg-config \
+  re2c \
+  time \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+# Install other dependencies
+RUN ln -sf /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h
+RUN wget http://ftp.gnu.org/gnu/bison/bison-2.6.4.tar.gz -O /var/local/bison-2.6.4.tar.gz
+RUN cd /var/local \
+  && tar -zxvf bison-2.6.4.tar.gz \
+  && cd /var/local/bison-2.6.4 \
+  && ./configure \
+  && make \
+  && make install
+
+# Compile PHP7 from source
+RUN git clone https://github.com/php/php-src /var/local/git/php-src
+RUN cd /var/local/git/php-src \
+  && git checkout PHP-7.0.9 \
+  && ./buildconf --force \
+  && ./configure \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  && make \
+  && make install
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
index e477295..91e8a90 100644
--- a/tools/dockerfile/test/php_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -68,12 +68,6 @@
 
 # Install dependencies
 
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index fa4b50f..db3d27c 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.0-pre1
+PROJECT_NUMBER         = 1.0.0-pre2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 1473594..9ff396a 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.0-pre1
+PROJECT_NUMBER         = 1.0.0-pre2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 7619b95..696bf4c 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.0-pre1
+PROJECT_NUMBER         = 1.0.0-pre2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 66d6156..44c17f3 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.0-pre1
+PROJECT_NUMBER         = 1.0.0-pre2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/run_tests/build_csharp_coreclr.sh b/tools/run_tests/build_csharp_coreclr.sh
index 733b1a2..02cf0d3 100755
--- a/tools/run_tests/build_csharp_coreclr.sh
+++ b/tools/run_tests/build_csharp_coreclr.sh
@@ -35,4 +35,4 @@
 # TODO(jtattermusch): introduce caching
 dotnet restore .
 
-dotnet build -f netstandard1.5 --configuration $MSBUILD_CONFIG '**/project.json'
+dotnet build --configuration $MSBUILD_CONFIG '**/project.json'
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/build_package_node.sh
index ef4a10c..f20daea 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -49,7 +49,12 @@
 
 mkdir -p bin
 
-cd src/node/tools
+cd $base/src/node/health_check
+npm update
+npm pack
+cp grpc-health-check-*.tgz $artifacts/
+
+cd $base/src/node/tools
 npm update
 npm pack
 cp grpc-tools-*.tgz $artifacts/
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index 13d745d..83e456d 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -168,7 +168,9 @@
   cd $PWD
 }
 
-$VENV_PYTHON -m pip install --upgrade pip setuptools
+$VENV_PYTHON -m pip install --upgrade pip
+# TODO(https://github.com/pypa/setuptools/issues/709) get the latest setuptools
+$VENV_PYTHON -m pip install setuptools==25.1.1
 $VENV_PYTHON -m pip install cython
 pip_install_dir $ROOT
 $VENV_PYTHON $ROOT/tools/distrib/python/make_grpcio_tools.py
diff --git a/tools/run_tests/pre_build_csharp.bat b/tools/run_tests/pre_build_csharp.bat
index e7131d5..580d563 100644
--- a/tools/run_tests/pre_build_csharp.bat
+++ b/tools/run_tests/pre_build_csharp.bat
@@ -38,8 +38,61 @@
 set NUGET=C:\nuget\nuget.exe
 
 if exist %NUGET% (
+  @rem Restore Grpc packages by packages since Nuget client 3.4.4 doesnt support restore
+  @rem by solution
+  @rem Moving into each directory to let the restores work with both nuget 3.4 and 2.8
   %NUGET% restore vsprojects/grpc_csharp_ext.sln || goto :error
-  %NUGET% restore src/csharp/Grpc.sln || goto :error
+
+  cd src/csharp
+
+  cd Grpc.Auth || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Core || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Core.Tests || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples.MathClient || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples.MathServer || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.HealthCheck.Tests || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.HealthCheck || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.Client || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.QpsWorker || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.StressClient || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+
+  cd /d %~dp0\..\.. || goto :error
 )
 
 endlocal
diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/pre_build_csharp.sh
index 3ff1a4e..0fd3b92 100755
--- a/tools/run_tests/pre_build_csharp.sh
+++ b/tools/run_tests/pre_build_csharp.sh
@@ -37,5 +37,54 @@
 
 if [ -x "$(command -v nuget)" ]
 then
-  nuget restore Grpc.sln
+  # Restoring Nuget packages by packages rather than by solution because of
+  # inability to restore by solution with Nuget client 3.4.4
+  # Moving into each directory to let the restores work with nuget 3.4 and 2.8
+  cd Grpc.Auth
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Core.Tests
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Core
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples.MathClient
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples.MathServer
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.HealthCheck.Tests
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.HealthCheck
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.Client
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.QpsWorker
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.StressClient
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting
+  nuget restore -PackagesDirectory ../packages
+  cd ..
 fi
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 13a4a49..782e316 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -266,6 +266,31 @@
     return 'php'
 
 
+class PHP7Language:
+
+  def __init__(self):
+    self.client_cwd = None
+    self.safename = str(self)
+
+  def client_cmd(self, args):
+    return ['src/php/bin/interop_client.sh'] + args
+
+  def cloud_to_prod_env(self):
+    return {}
+
+  def global_env(self):
+    return {}
+
+  def unimplemented_test_cases(self):
+    return _SKIP_COMPRESSION
+
+  def unimplemented_test_cases_server(self):
+    return []
+
+  def __str__(self):
+    return 'php7'
+
+
 class RubyLanguage:
 
   def __init__(self):
@@ -344,6 +369,7 @@
     'java' : JavaLanguage(),
     'node' : NodeLanguage(),
     'php' :  PHPLanguage(),
+    'php7' :  PHP7Language(),
     'ruby' : RubyLanguage(),
     'python' : PythonLanguage(),
 }
@@ -407,7 +433,7 @@
   default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
 
   if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
-    if language in ['csharp', 'node', 'php', 'python', 'ruby']:
+    if language in ['csharp', 'node', 'php', 'php7', 'python', 'ruby']:
       env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
     else:
       cmdargs += [key_file_arg]
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index d5f28fc..5002bf4 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -379,6 +379,42 @@
     return 'php'
 
 
+class Php7Language(object):
+
+  def configure(self, config, args):
+    self.config = config
+    self.args = args
+    _check_compiler(self.args.compiler, ['default'])
+
+  def test_specs(self):
+    return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
+                                  environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
+
+  def pre_build_steps(self):
+    return []
+
+  def make_targets(self):
+    return ['static_c', 'shared_c']
+
+  def make_options(self):
+    return []
+
+  def build_steps(self):
+    return [['tools/run_tests/build_php.sh']]
+
+  def post_tests_steps(self):
+    return [['tools/run_tests/post_tests_php.sh']]
+
+  def makefile_name(self):
+    return 'Makefile'
+
+  def dockerfile_dir(self):
+    return 'tools/dockerfile/test/php7_jessie_%s' % _docker_arch_suffix(self.args.arch)
+
+  def __str__(self):
+    return 'php7'
+
+
 class PythonConfig(collections.namedtuple('PythonConfig', [
     'name', 'build', 'run'])):
   """Tuple of commands (named s.t. 'what it says on the tin' applies)"""
@@ -738,6 +774,7 @@
     'c': CLanguage('c', 'c'),
     'node': NodeLanguage(),
     'php': PhpLanguage(),
+    'php7': Php7Language(),
     'python': PythonLanguage(),
     'ruby': RubyLanguage(),
     'csharp': CSharpLanguage(),